--============================================================================= -- RL验证.lua 单文件优化版 -- 结构(逻辑分区,非物理拆分): -- 1. 加密工具:ZZMathBit / __VCRC4_ / __VCMD5_ -- 2. 通用工具:ultra / writeFile / readFile / file_mkdir / urlencode -- 3. 主流程:_ENV["luoyeyun"] -- 4. 配置入口 --============================================================================= --============================================================================= -- 1. 加密工具 --============================================================================= ZZRc4 = {} ZZMathBit = {} function ZZMathBit.__xorBit(left, right) return (left + right) == 1 and 1 or 0 end function ZZMathBit.__base(left, right, op) if left < right then left, right = right, left end local res = 0 local shift = 1 while left ~= 0 do local ra = left % 2 local rb = right % 2 res = shift * op(ra, rb) + res shift = shift * 2 left = (left - ra) / 2 -- 避免 math.modf 浮点精度问题 right = (right - rb) / 2 end return res end function ZZMathBit.xorOp(left, right) return ZZMathBit.__base(left, right, ZZMathBit.__xorBit) end function __VCRC4_(text, key, kasi) -- 十六进制字符串转字节 if kasi == false then local str = text:gsub("[%s%p]", ""):upper() local ret = {} for i = 1, #str, 2 do local byte = tonumber(str:sub(i, i + 1), 16) if byte then ret[#ret + 1] = string.char(byte) end end text = table.concat(ret) end local function KSA(key) local keyLen = #key local schedule = {} for i = 0, 255 do schedule[i] = i end local keyByte = {} for i = 1, keyLen do keyByte[i - 1] = string.byte(key, i) end local j = 0 for i = 0, 255 do j = (j + schedule[i] + keyByte[i % keyLen]) % 256 schedule[i], schedule[j] = schedule[j], schedule[i] end return schedule end local function PRGA(schedule, textLen) local i, j, k = 0, 0, {} for n = 1, textLen do i = (i + 1) % 256 j = (j + schedule[i]) % 256 schedule[i], schedule[j] = schedule[j], schedule[i] k[n] = schedule[(schedule[i] + schedule[j]) % 256] end return k end local function output(k, text) local res = {} for i = 1, #text do res[i] = string.char(ZZMathBit.xorOp(k[i], string.byte(text, i))) end return table.concat(res) end local schedule = KSA(key) local k = PRGA(schedule, #text) local out = output(k, text) if kasi == true then local ret = {} for i = 1, #out do ret[i] = string.format("%02X", string.byte(out, i)) end return string.lower(table.concat(ret)) end return out end function __VCMD5_(code) local code = tostring(code) local HexTable = { "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F" } local A, B, C, D = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 local S11, S12, S13, S14 = 7, 12, 17, 22 local S21, S22, S23, S24 = 5, 9, 14, 20 local S31, S32, S33, S34 = 4, 11, 16, 23 local S41, S42, S43, S44 = 6, 10, 15, 21 local function F(x, y, z) return (x & y) | (~x & z) end local function G(x, y, z) return (x & z) | (y & ~z) end local function H(x, y, z) return x ~ y ~ z end local function I(x, y, z) return y ~ (x | ~z) end local function step(fn, a, b, c, d, x, s, ac) a = a + fn(b, c, d) + x + ac a = (((a & 0xffffffff) << s) | ((a & 0xffffffff) >> (32 - s))) + b return a & 0xffffffff end local function fill(s) local len = #s local rTab = {} local byteIndex = 1 for i = 1, len do local index = (i - 1) // 4 + 1 rTab[index] = (rTab[index] or 0) | (s:byte(i) << ((byteIndex - 1) * 8)) byteIndex = byteIndex + 1 if byteIndex == 5 then byteIndex = 1 end end local mod512 = len * 8 % 512 local fillSize = ((mod512 > 448) and (960 - mod512) or (448 - mod512)) // 8 local b0x80 = false local tLen = #rTab if byteIndex ~= 1 then rTab[tLen] = rTab[tLen] | (0x80 << ((byteIndex - 1) * 8)) b0x80 = true end for i = 1, fillSize // 4 do if not b0x80 and i == 1 then rTab[tLen + i] = 0x80 else rTab[tLen + i] = 0x0 end end local bitLen = math.floor(len * 8) tLen = #rTab rTab[tLen + 1] = bitLen & 0xffffffff rTab[tLen + 2] = bitLen >> 32 return rTab end local fillTab = fill(code) local result = { A, B, C, D } for i = 1, #fillTab // 16 do local a, b, c, d = result[1], result[2], result[3], result[4] local o = (i - 1) * 16 local t = fillTab -- F 轮 a = step(F,a,b,c,d,t[o+1],S11,0xd76aa478); d = step(F,d,a,b,c,t[o+2],S12,0xe8c7b756) c = step(F,c,d,a,b,t[o+3],S13,0x242070db); b = step(F,b,c,d,a,t[o+4],S14,0xc1bdceee) a = step(F,a,b,c,d,t[o+5],S11,0xf57c0faf); d = step(F,d,a,b,c,t[o+6],S12,0x4787c62a) c = step(F,c,d,a,b,t[o+7],S13,0xa8304613); b = step(F,b,c,d,a,t[o+8],S14,0xfd469501) a = step(F,a,b,c,d,t[o+9],S11,0x698098d8); d = step(F,d,a,b,c,t[o+10],S12,0x8b44f7af) c = step(F,c,d,a,b,t[o+11],S13,0xffff5bb1); b = step(F,b,c,d,a,t[o+12],S14,0x895cd7be) a = step(F,a,b,c,d,t[o+13],S11,0x6b901122); d = step(F,d,a,b,c,t[o+14],S12,0xfd987193) c = step(F,c,d,a,b,t[o+15],S13,0xa679438e); b = step(F,b,c,d,a,t[o+16],S14,0x49b40821) -- G 轮 a = step(G,a,b,c,d,t[o+2],S21,0xf61e2562); d = step(G,d,a,b,c,t[o+7],S22,0xc040b340) c = step(G,c,d,a,b,t[o+12],S23,0x265e5a51); b = step(G,b,c,d,a,t[o+1],S24,0xe9b6c7aa) a = step(G,a,b,c,d,t[o+6],S21,0xd62f105d); d = step(G,d,a,b,c,t[o+11],S22,0x2441453) c = step(G,c,d,a,b,t[o+16],S23,0xd8a1e681); b = step(G,b,c,d,a,t[o+5],S24,0xe7d3fbc8) a = step(G,a,b,c,d,t[o+10],S21,0x21e1cde6); d = step(G,d,a,b,c,t[o+15],S22,0xc33707d6) c = step(G,c,d,a,b,t[o+4],S23,0xf4d50d87); b = step(G,b,c,d,a,t[o+9],S24,0x455a14ed) a = step(G,a,b,c,d,t[o+14],S21,0xa9e3e905); d = step(G,d,a,b,c,t[o+3],S22,0xfcefa3f8) c = step(G,c,d,a,b,t[o+8],S23,0x676f02d9); b = step(G,b,c,d,a,t[o+13],S24,0x8d2a4c8a) -- H 轮 a = step(H,a,b,c,d,t[o+6],S31,0xfffa3942); d = step(H,d,a,b,c,t[o+9],S32,0x8771f681) c = step(H,c,d,a,b,t[o+12],S33,0x6d9d6122); b = step(H,b,c,d,a,t[o+15],S34,0xfde5380c) a = step(H,a,b,c,d,t[o+2],S31,0xa4beea44); d = step(H,d,a,b,c,t[o+5],S32,0x4bdecfa9) c = step(H,c,d,a,b,t[o+8],S33,0xf6bb4b60); b = step(H,b,c,d,a,t[o+11],S34,0xbebfbc70) a = step(H,a,b,c,d,t[o+14],S31,0x289b7ec6); d = step(H,d,a,b,c,t[o+1],S32,0xeaa127fa) c = step(H,c,d,a,b,t[o+4],S33,0xd4ef3085); b = step(H,b,c,d,a,t[o+7],S34,0x4881d05) a = step(H,a,b,c,d,t[o+10],S31,0xd9d4d039); d = step(H,d,a,b,c,t[o+13],S32,0xe6db99e5) c = step(H,c,d,a,b,t[o+16],S33,0x1fa27cf8); b = step(H,b,c,d,a,t[o+3],S34,0xc4ac5665) -- I 轮 a = step(I,a,b,c,d,t[o+1],S41,0xf4292244); d = step(I,d,a,b,c,t[o+8],S42,0x432aff97) c = step(I,c,d,a,b,t[o+15],S43,0xab9423a7); b = step(I,b,c,d,a,t[o+6],S44,0xfc93a039) a = step(I,a,b,c,d,t[o+13],S41,0x655b59c3); d = step(I,d,a,b,c,t[o+4],S42,0x8f0ccc92) c = step(I,c,d,a,b,t[o+11],S43,0xffeff47d); b = step(I,b,c,d,a,t[o+2],S44,0x85845dd1) a = step(I,a,b,c,d,t[o+9],S41,0x6fa87e4f); d = step(I,d,a,b,c,t[o+16],S42,0xfe2ce6e0) c = step(I,c,d,a,b,t[o+7],S43,0xa3014314); b = step(I,b,c,d,a,t[o+14],S44,0x4e0811a1) a = step(I,a,b,c,d,t[o+5],S41,0xf7537e82); d = step(I,d,a,b,c,t[o+12],S42,0xbd3af235) c = step(I,c,d,a,b,t[o+3],S43,0x2ad7d2bb); b = step(I,b,c,d,a,t[o+10],S44,0xeb86d391) result[1] = (result[1] + a) & 0xffffffff result[2] = (result[2] + b) & 0xffffffff result[3] = (result[3] + c) & 0xffffffff result[4] = (result[4] + d) & 0xffffffff end local ret = {} for i = 1, 4 do for _ = 1, 4 do local v = result[i] & 0x0F local low = HexTable[v + 1] result[i] = result[i] >> 4 ret[#ret + 1] = HexTable[(result[i] & 0x0F) + 1] .. low result[i] = result[i] >> 4 end end return string.lower(table.concat(ret)) end --============================================================================= -- 2. 通用工具 --============================================================================= local function ultra(get, post) local resp = gg.makeRequest(get, nil, post) local c = resp and resp.content if c == nil then os.exit(print("请允许网络申请")) end return c end local function readFile(path) local f = io.open(path, "r") if not f then return nil end local c = f:read("*a") f:close() return c end local function writeFile(path, content) local f = io.open(path, "w") if not f then return false end f:write(content) f:close() return true end local function file_mkdir(path) local ok, File = pcall(import, "java.io.File") if not ok then os.execute('mkdir -p "' .. path .. '"') return true end local dir = File(path) if not dir:exists() then local ok2 = dir:mkdirs() if ok2 then print("目录创建成功: " .. path) else print("目录创建失败: " .. path) end return ok2 end return true end local function urlencode(s) return (tostring(s):gsub("([^%w%-%._~])", function(c) return string.format("%%%02X", string.byte(c)) end)) end local function decodeUnicode(str) return (str:gsub("\\u(%x%x%x%x)", function(hex) local n = tonumber(hex, 16) if n < 128 then return string.char(n) elseif n < 2048 then return string.char(192 + math.floor(n / 64), 128 + (n % 64)) else return string.char(224 + math.floor(n / 4096), 128 + (math.floor(n / 64) % 64), 128 + (n % 64)) end end)) end local function jsonSafe(content) local ok, data = pcall(table.json, content) if ok and type(data) == "table" then return data end return nil end --============================================================================= -- 3. 主流程 --============================================================================= _ENV["luoyeyun"] = function(user) file_mkdir("/sdcard/Android/落叶验证") local FILES_DIR = "/sdcard/Android/落叶验证/" local AMI_e = FILES_DIR .. "autologin" local AMI_r = FILES_DIR .. "kami" local nk = "https://www.luoyeyunyan.icu/" local EP_Kami = nk .. "api.php?api=kmlogon" local EP_Jieba = nk .. "api.php?api=kmunmachine" local EP_Config = nk .. "api.php?api=ini" local EP_Notice = nk .. "api.php?api=notice" -- 配置校验 for _, k in ipairs({"appid","appidkey","rc4key"}) do if not user[k] or user[k] == "" then gg.alert("关键配置未填写: " .. k) os.exit() end end -- autologin 初始化 if not readFile(AMI_e) then writeFile(AMI_e, "0") end -- 统一 API 拉取 + 解 RC4 + code 校验 local function apiGet(url, label) local body = ultra(url, "") local code = body:match('"code":%s*(%d+)') if code and tonumber(code) ~= 200 then local msg = body:match('"msg":"(.-)"') or "未知错误" gg.alert(label .. ":" .. msg) os.exit() end if user.rc4 then body = __VCRC4_(body, user.rc4key, false) end return body end -- 公告 local Notice = apiGet(EP_Notice .. "&app=" .. user.appid, "公告接口") local __yygg_ = (Notice:match('"app_gg":"(.-)"}') or ""):gsub("换行代码", "\n") if __yygg_ == "" then __yygg_ = "空" end -- 应用配置(只拉一次) local gongxing = apiGet(EP_Config .. "&app=" .. user.appid, "应用配置接口") local xxcisu = gongxing:match('"api_total":"(.-)"') or "无法获取" local name = gongxing:match('"app_name":"(.-)"') or "无法获取" local version = gongxing:match('"version":"(.-)"') or "无法获取" local app_template = gongxing:match('"app_template":"(.-)"') or "无法获取" -- 运行时长 local po = "未获取到运行时间" local y, mo, d, h, mi, s = app_template:match("(%d+)年(%d+)月(%d+)日(%d+)时(%d+)分(%d+)秒") if y then local target = os.time({year=tonumber(y),month=tonumber(mo),day=tonumber(d), hour=tonumber(h),min=tonumber(mi),sec=tonumber(s)}) local diff = math.max(os.time() - target, 0) po = string.format("%d天%d小时%d分%d秒", math.floor(diff/86400), math.floor((diff%86400)/3600), math.floor((diff%3600)/60), diff%60) end -- IP 信息 local function getIPInfo() local resp = gg.makeRequest("https://cn.apihz.cn/api/ip/chaapi.php?id=10002325&key=luoyekeji2025666&ip=") if not resp or resp.code ~= 200 then return nil end local data = jsonSafe(resp.content) if not data then return nil end return (data.guo or "")..(data.sheng or "")..(data.shi or "")..(data.qu or "") end local yp = getIPInfo() or "无法获取IP信息" -- 反馈 local feedbackConfig = user.feedbackConfig or { URL = "https://www.luoyekj.top", api_key = user.feedback_api_key or "", feedbackTypes = { { id = 1, title = "卡密错误问题", name = "卡密测试问题" }, { id = 2, title = "bug反馈问题", name = "bug反馈问题" }, }, } local function submitFeedback(cfg) if not cfg then gg.alert("反馈类型无效"); return end local rs = gg.prompt({"输入你的内容","输入你的联系方式"},{"",""},{"text","text"}) if not rs then return end local url = string.format( "%s/api/feedback.php?api_key=%s&action=submit&title=%s&content=%s&contact=%s", feedbackConfig.URL, feedbackConfig.api_key, urlencode(cfg.name), urlencode(rs[1]), urlencode(rs[2])) local resp = gg.makeRequest(url) if not resp or not resp.content then gg.alert("网络请求失败"); return end local message = decodeUnicode(resp.content:match('"message":"(.-)"') or "未知") local created_at = resp.content:match('"created_at":"(.-)"') or "未知" gg.alert(string.format("反馈状态:%s\n反馈时间:%s", message, created_at)) end local function FeedbackMain() if not feedbackConfig.api_key or feedbackConfig.api_key == "" then gg.alert("开发者未配置用户反馈功能,请联系作者处理。") return end local items = {} for _, v in ipairs(feedbackConfig.feedbackTypes) do items[#items+1] = v.title end local rso = gg.choice(items, nil, "请选择反馈板块") if not rso then return end submitFeedback(feedbackConfig.feedbackTypes[rso]) end -- 卡密验证 local function yanzzzzz(km, sbm) local time = os.time() local Random = __VCMD5_(__VCRC4_(time .. "落叶云验证", user.rc4key, true) .. user.appidkey .. sbm) local key = __VCMD5_("kami="..km.."&markcode="..sbm.."&t="..time.."&"..user.appidkey) local bops = "kami="..km.."&markcode="..sbm.."&t="..time.."&sign="..key if user.rc4 then bops = "data="..__VCRC4_(bops, user.rc4key, true) end local HUT = ultra(EP_Kami .. "&app=" .. user.appid, bops .. "&value=" .. Random) if HUT == nil then gg.setVisible(false); gg.toast("请检查网络!"); return false end if user.rc4 then HUT = __VCRC4_(HUT, user.rc4key, false) end local qued = tonumber(HUT:match('"code":%s*(%d+)')) local vip = HUT:match('"vip":%s*"([^"]*)"') local yanzen = HUT:match('"check":%s*"([^"]*)"') local tinme = tonumber(HUT:match('"time":%s*(%d+)')) local fanhui = HUT:match('"msg":%s*"([^"]*)"') if qued ~= 200 then gg.alert(fanhui or "请求失败") writeFile(AMI_e, "0") return false end if not tinme or math.abs(tinme - os.time()) > 150 then gg.setVisible(false); gg.toast("数据超时!"); return false end if yanzen ~= __VCMD5_(tinme .. user.appidkey .. Random) then gg.setVisible(false); gg.toast("修改数据???"); writeFile(AMI_e, "0"); return false end gg.setVisible(false) local vip1 = os.date("%Y年%m月%d日\r%H时%M分%S秒\n", vip) writeFile(AMI_r, km) local kll = gg.alert("登入成功:\n\n到期时间∶\n" .. vip1, "确定", "取消自动登录") if kll == 2 then writeFile(AMI_e, "0") end if user.script and type(user.script) == "function" then user.script() end return true end -- 解绑 local function jiebang(km, sbm) gg.setVisible(false) local t = os.time() local key = __VCMD5_("kami="..km.."&markcode="..sbm.."&t="..t.."&"..user.appidkey) local bops = "kami="..km.."&markcode="..sbm.."&t="..t.."&sign="..key if user.rc4 then bops = "data="..__VCRC4_(bops, user.rc4key, true) end local HUT = ultra(EP_Jieba .. "&app=" .. user.appid, bops) if user.rc4 then HUT = __VCRC4_(HUT, user.rc4key, false) end gg.alert(HUT:match('msg":"(.-)",') or "未知") end local rq = os.date("%Y年%m月%d日 %H时%M分%S秒") -- 设备码(增强随机性,首次生成后固定) local sbm = readFile(FILES_DIR .. "imei") if not sbm or sbm == "" then sbm = __VCMD5_(rq .. tostring(os.time()) .. tostring(math.random(1, 1e9))) writeFile(FILES_DIR .. "imei", sbm) end -- 主菜单 local function MainVC() -- 启动次数 local cntFile = "/storage/emulated/0/落叶次数.txt" local f = io.open(cntFile, "a+") if not f then gg.alert("文件无法写入或打开"); return false end f:write("1") local yu = f:seek("end") f:close() -- 在线人数 local online = "未知" local onlines = gg.makeRequest(nk .. "api/api/online/online.php").content local ajh = onlines and jsonSafe(onlines) if ajh and ajh.online then online = tostring(ajh.online) end local tmp = readFile(AMI_r) or "" local logo = "---------------------------------------------------" local hak = gg.prompt({ "・ 📢公告:" .. __yygg_ .. "\n" .. logo .. "\n・当前项目:" .. name .. "v" .. version .. "\n・该项目已运行:" .. po .. "\n・全网启动:" .. xxcisu .. "次" .. "\n・当前用户总启动:" .. yu .. "次" .. "\n・总在线人数:" .. online .. "\n・当前时间:" .. rq .. "\n・欢迎你,来自" .. yp .. "的朋友!", "自动登入", "解绑卡密", "问题反馈", "联系方式", "跳转卡网", "退出脚本", }, {tmp, false}, {"text","checkbox","checkbox","checkbox","checkbox","checkbox","checkbox"}) if hak == nil then gg.toast("取消……"); return false end if hak[3] == true then gg.toast("开始解绑卡密……") local hak2 = gg.prompt({"现在时间:"..rq.."\n请输入解绑卡密:"}, {tmp}, {"text"}) if hak2 == nil then gg.toast("取消……"); return false end jiebang(hak2[1], sbm) return false end writeFile(AMI_e, hak[2] and "1" or "0") if hak[4] == true then FeedbackMain(); return false end if hak[5] == true then gg.alert("正在为您查询当前项目预留联系方式.....") local ini = apiGet(EP_Config .. "&app=" .. user.appid, "应用配置接口") local qq = ini:match('"app_qq":"(.-)"') or "" local qu = ini:match('"app_groupchat":"(.-)"') or "" qq = (qq ~= "" and qq ~= "null") and qq or "未预留联系QQ" qu = (qu ~= "" and qu ~= "null") and qu or "未预留交流群号码" local yn = gg.alert("查询成功,以下是联系方式\n\n作者QQ:"..qq.." \n\n交流群:"..qu, "复制QQ", "复制群号") if yn == 1 then gg.copyText(qq) elseif yn == 2 then gg.copyText(qu) end return false end if hak[6] == true then local kw = apiGet(EP_Notice .. "&app=" .. user.appid, "公告接口") local url = kw:match('"version_info":"(.-)"') or "" if url == "" or url == "未输入卡网" or url == "null" then gg.alert("未设置卡网链接,请联系项目作者"); return false end local as = gg.alert2("获取成功", "卡网:"..url, "跳转链接", "复制链接") if as == 1 then gg.goURL(url) elseif as == 2 then gg.copyText(url) end return false end if hak[7] == true then os.exit() end writeFile(AMI_r, hak[1]) return yanzzzzz(hak[1], sbm) end -- 自动登录 if readFile(AMI_e) == "1" then local km = readFile(AMI_r) if km and km ~= "" then if yanzzzzz(km, sbm) then return end end end -- 主循环 while true do if gg.isVisible(true) then gg.setVisible(false) if MainVC() then break end end gg.sleep(100) end end --============================================================================= -- 4. 配置入口 --============================================================================= do if type(_ENV["luoyeyun"]) ~= "function" then gg.alert("运行异常,请重试") os.exit() end local info = { appid = "10018", appidkey = "ZwR732Jo7Y9TIzYL", rc4key = "G3hSPAnRmZn10018", rc4 = true, feedbackConfig = { URL = "https://www.luoyekj.top", api_key = "", feedbackTypes = { { id = 1, title = "卡密错误问题", name = "卡密测试问题" }, { id = 2, title = "bug反馈问题", name = "bug反馈问题" }, { id = 3, title = "功能建议", name = "功能建议" }, { id = 4, title = "其他问题", name = "其他问题" }, }, }, script = function() gg.alert("登录成功") -- 以下放你的脚本 end, } _ENV["luoyeyun"](info) end