--作者夜辞 --适配64位il2cpp游戏,32位不兼容 --核心修改:1.常驻sx UI按钮,点击弹出三选项框(修改/仅清空保存列表/退出脚本);2.各选项独立执行对应逻辑 -- 定义拼接用的变量(全局,避免重复定义) local zg = "zg" local xjcs = "xjcs" local jyl = "jyl" local cyl = "cyl" local csl = "csl" local zzl = "zzl" local zc = "zc" -- 【核心函数】封装整个脚本的执行逻辑(选择修改时调用) function P() gg.toast("正在重新解析地址!") gg.clearList() -- 执行解析前先清空旧的保存列表 -- 1. rxp函数:获取有效模块起始地址 local function rxp() local last_addr = nil local modules = gg.getRangesList(gg.getTargetInfo().packageName) for _, mod in ipairs(modules) do local result = gg.getValues({{address = mod.start, flags = gg.TYPE_DWORD}}) if result and result[1] and result[1].value == 1179403647 then if mod.state == "Xa" then return mod.start end end end gg.toast("rxp:未找到有效模块!") return nil end -- 2. clear2048函数:清空2048字节内存 local function clear2048(addr) if not addr then return nil end local list = {} for i = 0, 2047, 4 do list[#list + 1] = {address = addr + i, flags = gg.TYPE_DWORD, value = 0} end gg.setValues(list) return addr end -- 3. getmap函数:查找可用Stack区域 local function getmap() local RangesList = gg.getRangesList() for i, range in ipairs(RangesList) do if range.type == "rw-p" and range.start and range["end"] then local name = range.name or "" if name:find("stack") and (range["end"] - range.start) >= 2048 then local start = range.start local endAddr = start + 2048 local allZero = true for addr = start, endAddr - 4, 16 do local val = gg.getValues({{address = addr, flags = gg.TYPE_DWORD}}) if val and val[1] and val[1].value ~= 0 then allZero = false break end end if allZero then gg.toast("getmap:找到有效Stack -> " .. string.format("0x%X", start)) return start end end end end gg.toast("getmap:未找到可用Stack区域!") return nil end -- 4. _lib函数:获取libil2cpp.so有效地址 local function _lib(lib, state) local ranges = gg.getRangesList(lib) if not ranges or #ranges == 0 then gg.toast("_lib:未找到" .. lib .. "!") return nil end if not state then for _, __ in pairs(ranges) do local val = gg.getValues({{address = __["start"], flags = 4}}) if val and val[1] and val[1].value == 1179403647 and ranges[_ + 1] then if __["end"] == ranges[_ + 1]["start"] then return __["start"] end end end elseif state then for _, __ in ipairs(ranges) do if __["state"] == state then return __["start"] end end end gg.toast("_lib:未找到" .. lib .. "有效起始地址!") return nil end -- 5. utf16函数:字符串转UTF16格式 local function utf16(s) if not s or s == "" then return nil end local rxp_addr = rxp() if not rxp_addr then return nil end local a = clear2048(rxp_addr + 0x1000) if not a then return nil end local b = a + 0x10 local c = {} local d = 0 local e = 1 local f = 0 while e <= #s do local g = string.byte(s, e) if g >= 0xE0 then e = e + 3 elseif g >= 0xC0 then e = e + 2 else e = e + 1 end f = f + 1 end e = 1 gg.setValues({{address = b + 0x0, flags = gg.TYPE_DWORD, value = f}}) while e <= #s do local g = string.byte(s, e) local h if g >= 0xE0 then local i = string.byte(s, e + 1) local j = string.byte(s, e + 2) if i and j then h = ((g & 0x0F) << 12) | ((i & 0x3F) << 6) | (j & 0x3F) e = e + 3 else break end elseif g >= 0xC0 then local k = string.byte(s, e + 1) if k then h = ((g & 0x1F) << 6) | (k & 0x3F) e = e + 2 else break end else h = g e = e + 1 end table.insert(c, {address = b + 0x4 + d * 2, flags = gg.TYPE_WORD, value = h}) d = d + 1 end table.insert(c, {address = b + 0x4 + d * 2, flags = gg.TYPE_WORD, value = 0}) gg.setValues(c) return a end -- 6. 核心封装:解析类对象并添加到列表 local function getClassObjAndAddList(className, offsets) if not className or className == "" then gg.toast("错误:类名为空!") return end local rxp_addr = rxp() local rxpaddr = clear2048(rxp_addr and rxp_addr + 0x100 or nil) local map = rxpaddr local map2 = getmap() local lib_il2cpp = _lib("libil2cpp.so") if not map or not map2 or not lib_il2cpp then gg.toast(className .. ":基础内存初始化失败!") return end local update = lib_il2cpp + 0x216e9d0 local GetType = lib_il2cpp + 0x1d1b744 local FindObjectsOfType = lib_il2cpp + 0x21438a4 local recover = gg.getValues({{address = update, flags = 32}, {address = update + 0x8, flags = 32}}) if not recover or #recover < 2 then gg.toast(className .. ":保存原内存失败!") return end gg.processPause() local setValuesList = { {address = update, flags = 4, value = "~A8 LDR X16, [PC,#0X8]"}, {address = update+0x4, flags = 4, value = "~A8 BR X16"}, {address = update+0x8, flags = 32, value = map}, {address = map, flags = 4, value = "~A8 LDR X11, [X16,#0X100]"}, {address = map+0x100, flags = 32, value = map2}, {address = map+0x4, flags = 4, value = "~A8 STP X29, X30, [X11]"}, {address = map+0x8, flags = 4, value = "~A8 LDR X12, [X11,#0X10]"}, {address = map+0xC, flags = 4, value = "~A8 CMP X12, #0"}, {address = map+0x10, flags = 4, value = "~A8 B.EQ [PC,#0X8]"}, {address = map+0x14, flags = 4, value = "~A8 RET"}, {address = map+0x18, flags = 4, value = "~A8 LDR X0, [X16,#0X110]"}, {address = map+0x110, flags = 32, value = utf16(className)}, {address = map+0x1C, flags = 4, value = "~A8 LDR X25, [X16,#0X120]"}, {address = map+0x20, flags = 4, value = "~A8 BLR X25"}, {address = map+0x120, flags = 32, value = GetType}, {address = map+0x24, flags = 4, value = "~A8 LDR X16, [PC,#0x888]"}, {address = map+0x24+0x888, flags = 32, value = map}, {address = map+0x28, flags = 4, value = "~A8 LDR X11, [X16,#0X100]"}, {address = map+0x2C, flags = 4, value = "~A8 LDP X29, X30, [X11]"}, {address = map+0X30, flags = 4, value = "~A8 LDR X25, [X16,#0X130]"}, {address = map+0x130, flags = 32, value = FindObjectsOfType}, {address = map+0x34, flags = 4, value = "~A8 BLR X25"}, {address = map+0x38, flags = 4, value = "~A8 LDR X16, [PC,#0X448]"}, {address = map+0x38+0x448, flags = 32, value = map}, {address = map+0x3C, flags = 4, value = "~A8 LDR X11, [X16,#0X100]"}, {address = map+0x40, flags = 4, value = "~A8 LDP X29, X30, [X11]"}, {address = map+0x44, flags = 4, value = "~A8 STR X30, [X11,#0X10]"}, {address = map+0x48, flags = 4, value = "~A8 STR X0, [X11,#0X20]"}, {address = map+0x4C, flags = 4, value = "~A8 RET"} } gg.setValues(setValuesList) gg.processResume() -- 超时等待结果 local retValue = 0 local waitCount = 0 local maxWait = 200 while retValue == 0 and waitCount < maxWait do local val = gg.getValues({{address = map2 + 0x10, flags = 4}}) retValue = (val and val[1] and val[1].value) or 0 waitCount = waitCount + 1 end if waitCount >= maxWait then gg.toast(className .. ":获取对象超时!") gg.processPause() gg.setValues(recover) gg.processResume() return end -- 恢复原内存 gg.processPause() gg.setValues(recover) gg.processResume() -- 解析对象列表并添加 local pi_val = gg.getValues({{address = map2 + 0x20, flags = 32}}) local pi = (pi_val and pi_val[1] and pi_val[1].value) or 0 if pi == 0 then gg.toast(className .. ":对象列表根地址为0!") return end local n_val = gg.getValues({{address = pi + 0x18, flags = 4}}) local n = (n_val and n_val[1] and n_val[1].value) or 0 if n == 0 then gg.toast(className .. ":未找到任何对象实例!") return end gg.toast(className .. ":解析到对象数 -> " .. n) local a = {} local validCount = 0 for i = 0, n - 1 do local q_val = gg.getValues({{address = pi + 0x20 + i * 8, flags = 32}}) local q = (q_val and q_val[1] and q_val[1].value) or 0 if q ~= 0 and string.sub(string.format("0x%X", q), 1, 3) ~= "0x0" then validCount = validCount + 1 table.insert(a, {address = q, flags = 32, name = className .. "_对象地址_" .. validCount}) for offsetName, offsetInfo in pairs(offsets) do table.insert(a, { address = q + offsetInfo.offset, flags = offsetInfo.type, name = className .. "_" .. offsetName }) end end end if validCount > 0 then gg.addListItems(a) gg.toast(className .. ":成功添加" .. validCount .. "个有效对象地址!") else gg.toast(className .. ":解析到n=" .. n .. ",但无有效地址!") end end -- 【配置区】 local CFG = { PlayerController = { className = "PlayerController", offsets = { ["最大速度"] = {offset = 0xB4, type = gg.TYPE_FLOAT}, ["速度"] = {offset = 0xAC, type = gg.TYPE_FLOAT}, ["蹲伏速度"] = {offset = 0xB0, type = gg.TYPE_FLOAT}, ["最大血量"] = {offset = 0xE8, type = gg.TYPE_DWORD}, ["血量"] = {offset = 0xE4, type = gg.TYPE_DWORD}, ["最大体力"] = {offset = 0x12C, type = gg.TYPE_FLOAT}, ["体力"] = {offset = 0x128, type = gg.TYPE_FLOAT}, ["枪地址\n手枪:256\n冲锋:65792"] = {offset = 0xD0, type = gg.TYPE_DWORD}, ["无敌"] = {offset = 0xD4, type = gg.TYPE_DWORD}, ["跌倒65536,0不跌倒"] = {offset = 0xc4, type = gg.TYPE_DWORD}, ["兴奋值"] = {offset = 0xEC, type = gg.TYPE_FLOAT}, [zg..xjcs] = {offset = 0x100, type = gg.TYPE_DWORD}, [zg..jyl] = {offset = 0x104, type = gg.TYPE_FLOAT}, [zg..cyl] = {offset = 0x108, type = gg.TYPE_DWORD}, [zg..csl] = {offset = 0x10C, type = gg.TYPE_DWORD}, [zg..zzl] = {offset = 0x110, type = gg.TYPE_DWORD}, [zc..xjcs] = {offset = 0x114, type = gg.TYPE_DWORD}, [zc..jyl] = {offset = 0x118, type = gg.TYPE_FLOAT}, [zc..cyl] = {offset = 0x11C, type = gg.TYPE_DWORD}, [zc..csl] = {offset = 0x120, type = gg.TYPE_DWORD}, [zc..zzl] = {offset = 0x124, type = gg.TYPE_DWORD} } }, Weapon = { className = "Weapon", offsets = { ["手枪子弹"] = {offset = 0x8C, type = gg.TYPE_DWORD}, ["手枪弹匣"] = {offset = 0x90, type = gg.TYPE_DWORD}, ["冲锋枪子弹"] = {offset = 0x98, type = gg.TYPE_DWORD}, ["冲锋枪弹匣"] = {offset = 0x9C, type = gg.TYPE_DWORD}, ["手枪射速"] = {offset = 0x80, type = gg.TYPE_FLOAT}, ["冲锋枪射速"] = {offset = 0x84, type = gg.TYPE_FLOAT} } } } -- 执行核心逻辑:先PlayerController,后Weapon if CFG.PlayerController and CFG.PlayerController.className then getClassObjAndAddList(CFG.PlayerController.className, CFG.PlayerController.offsets) end if CFG.Weapon and CFG.Weapon.className then gg.sleep(500) -- 延迟避免内存冲突 getClassObjAndAddList(CFG.Weapon.className, CFG.Weapon.offsets) end gg.toast("全脚本逻辑执行完毕!") end -- 【新增函数】仅清空保存列表(独立逻辑) function clearOnlyList() gg.clearList() gg.toast("已仅清空保存列表!") end -- 初始化:显示常驻UI按钮 + 监听点击事件(三选项核心逻辑) gg.showUiButton() while true do if gg.isClickedUiButton() then -- 弹出三选项对话框,返回1=修改,2=仅清空保存列表,3=退出脚本 local selectRes = gg.choice({"修改", "仅清空保存列表", "退出脚本"}, nil, "Sx脚本操作选择") if selectRes == 1 then P() -- 选择修改,执行原解析+清空列表逻辑 elseif selectRes == 2 then clearOnlyList() -- 选择仅清空,只执行列表清空 elseif selectRes == 3 then gg.toast("脚本已退出!") gg.hideUiButton() -- 隐藏UI按钮 return -- 终止脚本运行 end end gg.sleep(100) -- 降低CPU占用,必加! end