├── .gitignore ├── .gitmodules ├── README.md ├── build.ts ├── build └── Il2cppApi.lua ├── il2cpp.lua ├── il2cppstruct ├── api │ ├── classinfo.lua │ └── fieldinfo.lua ├── class.lua ├── field.lua ├── globalmetadata.lua ├── il2cppstring.lua ├── metadataRegistration.lua ├── method.lua ├── object.lua └── type.lua ├── index.lua ├── package.json ├── test ├── 1.apk ├── img │ ├── Screenshot_20220712-090652.png │ ├── TestModule.gif │ └── photo_2023-03-17_22-35-52.jpg └── test.lua └── utils ├── androidinfo.lua ├── il2cppconst.lua ├── il2cppmemory.lua ├── malloc.lua ├── patchapi.lua ├── protect.lua ├── stringutils.lua ├── universalsearcher.lua └── version.lua /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | # For modules 43 | node_modules 44 | package-lock.json 45 | gg.lua 46 | testbuild.ts 47 | Il2cppApihelp.txt -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "semver"] 2 | path = semver 3 | url = https://github.com/kikito/semver.lua 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Il2cpp Module for GameGuardian 2 | [![GameGuardian](https://img.shields.io/badge/GameGuardian-7c36b1)](https://gameguardian.net/forum/files/file/3056-ggil2cpp)[![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?&logo=telegram&logoColor=white)](https://t.me/CDdreem) 3 | ## About Module 4 | 5 | This script is only needed to make it easier to work with Il2cpp. This script works through the program [GameGuardian](https://gameguardian.net). With the help of the module, you can get information about the method or class that interests you. This script is not positioned as a dumper, and is only needed to simplify working with Il2cpp. 6 | 7 | The module has support for the [Lua](https://marketplace.visualstudio.com/items?itemName=yinfei.luahelper) plugin for [VS Code](https://code.visualstudio.com/), that is, some functions have a description that this plugin can display. 8 | 9 | The script is divided and available for assembly. You can also use an already built version from the [build](/build/) folder or from the [Releases](https://github.com/kruvcraft21/GGIl2cpp/releases/latest) tab. Script is built using the [luabundle](https://github.com/Benjamin-Dobell/luabundle) library. 10 | 11 | All documentation about the module is available on the [wiki](../../wiki/) -------------------------------------------------------------------------------- /build.ts: -------------------------------------------------------------------------------- 1 | import { bundle } from 'luabundle' 2 | import fs from 'fs' 3 | import path from "path" 4 | 5 | const bundledLua = bundle('./index.lua', { 6 | metadata: false, 7 | rootModuleName: "GGIl2cpp" 8 | }) 9 | 10 | const buildPath = path.normalize("build/Il2cppApi.lua") 11 | 12 | fs.writeFile(buildPath, bundledLua, (err : any) => { 13 | if (err) throw err 14 | console.log("Il2cppApi.lua -> ОК\n") 15 | }) -------------------------------------------------------------------------------- /il2cpp.lua: -------------------------------------------------------------------------------- 1 | local Il2cppMemory = require("utils.il2cppmemory") 2 | local VersionEngine = require("utils.version") 3 | local AndroidInfo = require("utils.androidinfo") 4 | local Searcher = require("utils.universalsearcher") 5 | local PatchApi = require("utils.patchapi") 6 | 7 | 8 | 9 | ---@class Il2cpp 10 | local Il2cppBase = { 11 | il2cppStart = 0, 12 | il2cppEnd = 0, 13 | globalMetadataStart = 0, 14 | globalMetadataEnd = 0, 15 | globalMetadataHeader = 0, 16 | MainType = AndroidInfo.platform and gg.TYPE_QWORD or gg.TYPE_DWORD, 17 | pointSize = AndroidInfo.platform and 8 or 4, 18 | ---@type Il2CppTypeDefinitionApi 19 | Il2CppTypeDefinitionApi = {}, 20 | MetadataRegistrationApi = require("il2cppstruct.metadataRegistration"), 21 | TypeApi = require("il2cppstruct.type"), 22 | MethodsApi = require("il2cppstruct.method"), 23 | GlobalMetadataApi = require("il2cppstruct.globalmetadata"), 24 | FieldApi = require("il2cppstruct.field"), 25 | ClassApi = require("il2cppstruct.class"), 26 | ObjectApi = require("il2cppstruct.object"), 27 | ClassInfoApi = require("il2cppstruct.api.classinfo"), 28 | FieldInfoApi = require("il2cppstruct.api.fieldinfo"), 29 | ---@type MyString 30 | String = require("il2cppstruct.il2cppstring"), 31 | MemoryManager = require("utils.malloc"), 32 | --- Patch `Bytescodes` to `add` 33 | --- 34 | --- Example: 35 | --- arm64: 36 | --- `mov w0,#0x1` 37 | --- `ret` 38 | --- 39 | --- `Il2cpp.PatchesAddress(0x100, "\x20\x00\x80\x52\xc0\x03\x5f\xd6")` 40 | ---@param add number 41 | ---@param Bytescodes string 42 | ---@return Patch 43 | PatchesAddress = function(add, Bytescodes) 44 | local patchCode = {} 45 | for code in string.gmatch(Bytescodes, '.') do 46 | patchCode[#patchCode + 1] = { 47 | address = add + #patchCode, 48 | value = string.byte(code), 49 | flags = gg.TYPE_BYTE 50 | } 51 | end 52 | ---@type Patch 53 | local patch = PatchApi:Create(patchCode) 54 | patch:Patch() 55 | return patch 56 | end, 57 | 58 | 59 | --- Searches for a method, or rather information on the method, by name or by offset, you can also send an address in memory to it. 60 | --- 61 | --- Return table with information about methods. 62 | ---@generic TypeForSearch : number | string 63 | ---@param searchParams TypeForSearch[] @TypeForSearch = number | string 64 | ---@return table 65 | FindMethods = function(searchParams) 66 | Il2cppMemory:SaveResults() 67 | for i = 1, #searchParams do 68 | ---@type number | string 69 | searchParams[i] = Il2cpp.MethodsApi:Find(searchParams[i]) 70 | end 71 | Il2cppMemory:ClearSavedResults() 72 | return searchParams 73 | end, 74 | 75 | 76 | --- Searches for a class, by name, or by address in memory. 77 | --- 78 | --- Return table with information about class. 79 | ---@param searchParams ClassConfig[] 80 | ---@return table 81 | FindClass = function(searchParams) 82 | Il2cppMemory:SaveResults() 83 | for i = 1, #searchParams do 84 | searchParams[i] = Il2cpp.ClassApi:Find(searchParams[i]) 85 | end 86 | Il2cppMemory:ClearSavedResults() 87 | return searchParams 88 | end, 89 | 90 | 91 | --- Searches for an object by name or by class address, in memory. 92 | --- 93 | --- In some cases, the function may return an incorrect result for certain classes. For example, sometimes the garbage collector may not have time to remove an object from memory and then a `fake object` will appear or for a turnover, the object may still be `not implemented` or `not created`. 94 | --- 95 | --- Returns a table of objects. 96 | ---@param searchParams table 97 | ---@return table 98 | FindObject = function(searchParams) 99 | Il2cppMemory:SaveResults() 100 | for i = 1, #searchParams do 101 | searchParams[i] = Il2cpp.ObjectApi:Find(Il2cpp.ClassApi:Find({Class = searchParams[i]})) 102 | end 103 | Il2cppMemory:ClearSavedResults() 104 | return searchParams 105 | end, 106 | 107 | 108 | --- Searches for a field, or rather information about the field, by name or by address in memory. 109 | --- 110 | --- Return table with information about fields. 111 | ---@generic TypeForSearch : number | string 112 | ---@param searchParams TypeForSearch[] @TypeForSearch = number | string 113 | ---@return table 114 | FindFields = function(searchParams) 115 | Il2cppMemory:SaveResults() 116 | for i = 1, #searchParams do 117 | ---@type number | string 118 | local searchParam = searchParams[i] 119 | local searchResult = Il2cppMemory:GetInformationOfField(searchParam) 120 | if not searchResult then 121 | searchResult = Il2cpp.FieldApi:Find(searchParam) 122 | Il2cppMemory:SetInformationOfField(searchParam, searchResult) 123 | end 124 | searchParams[i] = searchResult 125 | end 126 | Il2cppMemory:ClearSavedResults() 127 | return searchParams 128 | end, 129 | 130 | 131 | ---@param Address number 132 | ---@param length? number 133 | ---@return string 134 | Utf8ToString = function(Address, length) 135 | local chars, char = {}, { 136 | address = Address, 137 | flags = gg.TYPE_BYTE 138 | } 139 | if not length then 140 | repeat 141 | _char = string.char(gg.getValues({char})[1].value & 0xFF) 142 | chars[#chars + 1] = _char 143 | char.address = char.address + 0x1 144 | until string.find(_char, "[%z%s]") 145 | return table.concat(chars, "", 1, #chars - 1) 146 | else 147 | for i = 1, length do 148 | local _char = gg.getValues({char})[1].value 149 | chars[i] = string.char(_char & 0xFF) 150 | char.address = char.address + 0x1 151 | end 152 | return table.concat(chars) 153 | end 154 | end, 155 | 156 | 157 | ---@param bytes string 158 | ChangeBytesOrder = function(bytes) 159 | local newBytes, index, lenBytes = {}, 0, #bytes / 2 160 | for byte in string.gmatch(bytes, "..") do 161 | newBytes[lenBytes - index] = byte 162 | index = index + 1 163 | end 164 | return table.concat(newBytes) 165 | end, 166 | 167 | 168 | FixValue = function(val) 169 | return AndroidInfo.platform and val & 0x00FFFFFFFFFFFFFF or val & 0xFFFFFFFF 170 | end, 171 | 172 | 173 | GetValidAddress = function(Address) 174 | local lastByte = Address & 0x000000000000000F 175 | local delta = 0 176 | local checkTable = {[12] = true, [4] = true, [8] = true, [0] = true} 177 | while not checkTable[lastByte - delta] do 178 | delta = delta + 1 179 | end 180 | return Address - delta 181 | end, 182 | 183 | 184 | ---@param self Il2cpp 185 | ---@param address number | string 186 | SearchPointer = function(self, address) 187 | address = self.ChangeBytesOrder(type(address) == 'number' and string.format('%X', address) or address) 188 | gg.searchNumber('h ' .. address) 189 | gg.refineNumber('h ' .. address:sub(1, 6)) 190 | gg.refineNumber('h ' .. address:sub(1, 2)) 191 | local FindsResult = gg.getResults(gg.getResultsCount()) 192 | gg.clearResults() 193 | return FindsResult 194 | end, 195 | } 196 | 197 | ---@type Il2cpp 198 | Il2cpp = setmetatable({}, { 199 | ---@param self Il2cpp 200 | ---@param config? Il2cppConfig 201 | __call = function(self, config) 202 | config = config or {} 203 | getmetatable(self).__index = Il2cppBase 204 | 205 | if config.libilcpp then 206 | self.il2cppStart, self.il2cppEnd = config.libilcpp.start, config.libilcpp['end'] 207 | else 208 | self.il2cppStart, self.il2cppEnd = Searcher.FindIl2cpp() 209 | end 210 | 211 | if config.globalMetadata then 212 | self.globalMetadataStart, self.globalMetadataEnd = config.globalMetadata.start, config.globalMetadata['end'] 213 | else 214 | self.globalMetadataStart, self.globalMetadataEnd = Searcher:FindGlobalMetaData() 215 | end 216 | 217 | if config.globalMetadataHeader then 218 | self.globalMetadataHeader = config.globalMetadataHeader 219 | else 220 | self.globalMetadataHeader = self.globalMetadataStart 221 | end 222 | 223 | self.MetadataRegistrationApi.metadataRegistration = config.metadataRegistration 224 | 225 | VersionEngine:ChooseVersion(config.il2cppVersion, self.globalMetadataHeader) 226 | 227 | Il2cppMemory:ClearMemorize() 228 | end, 229 | __index = function(self, key) 230 | assert(key == "PatchesAddress", "You didn't call 'Il2cpp'") 231 | return Il2cppBase[key] 232 | end 233 | }) 234 | 235 | return Il2cpp -------------------------------------------------------------------------------- /il2cppstruct/api/classinfo.lua: -------------------------------------------------------------------------------- 1 | local ClassInfoApi = { 2 | 3 | 4 | ---Get FieldInfo by Field Name. If Field isn't found by name, then function will return `nil` 5 | ---@param self ClassInfo 6 | ---@param name string 7 | ---@return FieldInfo | nil 8 | GetFieldWithName = function(self, name) 9 | local FieldsInfo = self.Fields 10 | if FieldsInfo then 11 | for fieldIndex = 1, #FieldsInfo do 12 | if FieldsInfo[fieldIndex].FieldName == name then 13 | return FieldsInfo[fieldIndex] 14 | end 15 | end 16 | else 17 | local ClassAddress = tonumber(self.ClassAddress, 16) 18 | local _ClassInfo = gg.getValues({ 19 | { -- Link as Fields 20 | address = ClassAddress + Il2cpp.ClassApi.FieldsLink, 21 | flags = Il2cpp.MainType 22 | }, 23 | { -- Fields Count 24 | address = ClassAddress + Il2cpp.ClassApi.CountFields, 25 | flags = gg.TYPE_WORD 26 | } 27 | }) 28 | self.Fields = Il2cpp.ClassApi:GetClassFields(Il2cpp.FixValue(_ClassInfo[1].value), _ClassInfo[2].value, { 29 | ClassName = self.ClassName, 30 | IsEnum = self.IsEnum, 31 | TypeMetadataHandle = self.TypeMetadataHandle 32 | }) 33 | return self:GetFieldWithName(name) 34 | end 35 | return nil 36 | end, 37 | 38 | 39 | ---Get MethodInfo[] by MethodName. If Method isn't found by name, then function will return `table with zero size` 40 | ---@param self ClassInfo 41 | ---@param name string 42 | ---@return MethodInfo[] 43 | GetMethodsWithName = function(self, name) 44 | local MethodsInfo, MethodsInfoResult = self.Methods, {} 45 | if MethodsInfo then 46 | for methodIndex = 1, #MethodsInfo do 47 | if MethodsInfo[methodIndex].MethodName == name then 48 | MethodsInfoResult[#MethodsInfoResult + 1] = MethodsInfo[methodIndex] 49 | end 50 | end 51 | return MethodsInfoResult 52 | else 53 | local ClassAddress = tonumber(self.ClassAddress, 16) 54 | local _ClassInfo = gg.getValues({ 55 | { -- Link as Methods 56 | address = ClassAddress + Il2cpp.ClassApi.MethodsLink, 57 | flags = Il2cpp.MainType 58 | }, 59 | { -- Methods Count 60 | address = ClassAddress + Il2cpp.ClassApi.CountMethods, 61 | flags = gg.TYPE_WORD 62 | } 63 | }) 64 | self.Methods = Il2cpp.ClassApi:GetClassMethods(Il2cpp.FixValue(_ClassInfo[1].value), _ClassInfo[2].value, 65 | self.ClassName) 66 | return self:GetMethodsWithName(name) 67 | end 68 | end, 69 | 70 | 71 | ---@param self ClassInfo 72 | ---@param fieldOffset number 73 | ---@return nil | FieldInfo 74 | GetFieldWithOffset = function(self, fieldOffset) 75 | if not self.Fields then 76 | local ClassAddress = tonumber(self.ClassAddress, 16) 77 | local _ClassInfo = gg.getValues({ 78 | { -- Link as Fields 79 | address = ClassAddress + Il2cpp.ClassApi.FieldsLink, 80 | flags = Il2cpp.MainType 81 | }, 82 | { -- Fields Count 83 | address = ClassAddress + Il2cpp.ClassApi.CountFields, 84 | flags = gg.TYPE_WORD 85 | } 86 | }) 87 | self.Fields = Il2cpp.ClassApi:GetClassFields(Il2cpp.FixValue(_ClassInfo[1].value), _ClassInfo[2].value, { 88 | ClassName = self.ClassName, 89 | IsEnum = self.IsEnum, 90 | TypeMetadataHandle = self.TypeMetadataHandle 91 | }) 92 | end 93 | if #self.Fields > 0 then 94 | local klass = self 95 | while klass ~= nil do 96 | if klass.Fields and klass.InstanceSize >= fieldOffset then 97 | local lastField 98 | for indexField, field in ipairs(klass.Fields) do 99 | if not (field.IsStatic or field.IsConst) then 100 | local offset = tonumber(field.Offset, 16) 101 | if offset > 0 then 102 | local maybeStruct = fieldOffset < offset 103 | 104 | if indexField == 1 and maybeStruct then 105 | break 106 | elseif offset == fieldOffset or indexField == #klass.Fields then 107 | return field 108 | elseif maybeStruct then 109 | return lastField 110 | else 111 | lastField = field 112 | end 113 | end 114 | end 115 | end 116 | end 117 | klass = klass.Parent ~= nil 118 | and Il2cpp.FindClass({ 119 | { 120 | Class = tonumber(klass.Parent.ClassAddress, 16), 121 | FieldsDump = true 122 | } 123 | })[1][1] 124 | or nil 125 | end 126 | end 127 | return nil 128 | end 129 | } 130 | 131 | return ClassInfoApi -------------------------------------------------------------------------------- /il2cppstruct/api/fieldinfo.lua: -------------------------------------------------------------------------------- 1 | local Il2cppMemory = require("utils.il2cppmemory") 2 | 3 | ---@type FieldInfo 4 | local FieldInfoApi = { 5 | 6 | 7 | ---@param self FieldInfo 8 | ---@return nil | string | number 9 | GetConstValue = function(self) 10 | if self.IsConst then 11 | local fieldIndex = getmetatable(self).fieldIndex 12 | local defaultValue = Il2cppMemory:GetDefaultValue(fieldIndex) 13 | if not defaultValue then 14 | defaultValue = Il2cpp.GlobalMetadataApi:GetDefaultFieldValue(fieldIndex) 15 | Il2cppMemory:SetDefaultValue(fieldIndex, defaultValue) 16 | elseif defaultValue == "nil" then 17 | return nil 18 | end 19 | return defaultValue 20 | end 21 | return nil 22 | end 23 | } 24 | 25 | return FieldInfoApi -------------------------------------------------------------------------------- /il2cppstruct/class.lua: -------------------------------------------------------------------------------- 1 | local Protect = require("utils.protect") 2 | local StringUtils = require("utils.stringutils") 3 | local Il2cppMemory = require("utils.il2cppmemory") 4 | 5 | ---@class ClassApi 6 | ---@field NameOffset number 7 | ---@field MethodsStep number 8 | ---@field CountMethods number 9 | ---@field MethodsLink number 10 | ---@field FieldsLink number 11 | ---@field FieldsStep number 12 | ---@field CountFields number 13 | ---@field ParentOffset number 14 | ---@field NameSpaceOffset number 15 | ---@field StaticFieldDataOffset number 16 | ---@field EnumType number 17 | ---@field EnumRsh number 18 | ---@field TypeMetadataHandle number 19 | ---@field InstanceSize number 20 | ---@field Token number 21 | ---@field GetClassName fun(self : ClassApi, ClassAddress : number) : string 22 | ---@field GetClassMethods fun(self : ClassApi, MethodsLink : number, Count : number, ClassName : string | nil) : MethodInfo[] 23 | local ClassApi = { 24 | 25 | 26 | ---@param self ClassApi 27 | ---@param ClassAddress number 28 | GetClassName = function(self, ClassAddress) 29 | return Il2cpp.Utf8ToString(Il2cpp.FixValue(gg.getValues({{ 30 | address = Il2cpp.FixValue(ClassAddress) + self.NameOffset, 31 | flags = Il2cpp.MainType 32 | }})[1].value)) 33 | end, 34 | 35 | 36 | ---@param self ClassApi 37 | ---@param MethodsLink number 38 | ---@param Count number 39 | ---@param ClassName string | nil 40 | GetClassMethods = function(self, MethodsLink, Count, ClassName) 41 | local MethodsInfo, _MethodsInfo = {}, {} 42 | for i = 0, Count - 1 do 43 | _MethodsInfo[#_MethodsInfo + 1] = { 44 | address = MethodsLink + (i << self.MethodsStep), 45 | flags = Il2cpp.MainType 46 | } 47 | end 48 | _MethodsInfo = gg.getValues(_MethodsInfo) 49 | for i = 1, #_MethodsInfo do 50 | local MethodInfo 51 | MethodInfo, _MethodsInfo[i] = Il2cpp.MethodsApi:UnpackMethodInfo({ 52 | MethodInfoAddress = Il2cpp.FixValue(_MethodsInfo[i].value), 53 | ClassName = ClassName 54 | }) 55 | table.move(MethodInfo, 1, #MethodInfo, #MethodsInfo + 1, MethodsInfo) 56 | end 57 | MethodsInfo = gg.getValues(MethodsInfo) 58 | Il2cpp.MethodsApi:DecodeMethodsInfo(_MethodsInfo, MethodsInfo) 59 | return _MethodsInfo 60 | end, 61 | 62 | 63 | GetClassFields = function(self, FieldsLink, Count, ClassCharacteristic) 64 | local FieldsInfo, _FieldsInfo = {}, {} 65 | for i = 0, Count - 1 do 66 | _FieldsInfo[#_FieldsInfo + 1] = { 67 | address = FieldsLink + (i * self.FieldsStep), 68 | flags = Il2cpp.MainType 69 | } 70 | end 71 | _FieldsInfo = gg.getValues(_FieldsInfo) 72 | for i = 1, #_FieldsInfo do 73 | local FieldInfo 74 | FieldInfo = Il2cpp.FieldApi:UnpackFieldInfo(Il2cpp.FixValue(_FieldsInfo[i].address)) 75 | table.move(FieldInfo, 1, #FieldInfo, #FieldsInfo + 1, FieldsInfo) 76 | end 77 | FieldsInfo = gg.getValues(FieldsInfo) 78 | _FieldsInfo = Il2cpp.FieldApi:DecodeFieldsInfo(FieldsInfo, ClassCharacteristic) 79 | return _FieldsInfo 80 | end, 81 | 82 | 83 | ---@param self ClassApi 84 | ---@param ClassInfo ClassInfoRaw 85 | ---@param Config table 86 | ---@return ClassInfo 87 | UnpackClassInfo = function(self, ClassInfo, Config) 88 | local _ClassInfo = gg.getValues({ 89 | { -- Class Name [1] 90 | address = ClassInfo.ClassInfoAddress + self.NameOffset, 91 | flags = Il2cpp.MainType 92 | }, 93 | { -- Methods Count [2] 94 | address = ClassInfo.ClassInfoAddress + self.CountMethods, 95 | flags = gg.TYPE_WORD 96 | }, 97 | { -- Fields Count [3] 98 | address = ClassInfo.ClassInfoAddress + self.CountFields, 99 | flags = gg.TYPE_WORD 100 | }, 101 | { -- Link as Methods [4] 102 | address = ClassInfo.ClassInfoAddress + self.MethodsLink, 103 | flags = Il2cpp.MainType 104 | }, 105 | { -- Link as Fields [5] 106 | address = ClassInfo.ClassInfoAddress + self.FieldsLink, 107 | flags = Il2cpp.MainType 108 | }, 109 | { -- Link as Parent Class [6] 110 | address = ClassInfo.ClassInfoAddress + self.ParentOffset, 111 | flags = Il2cpp.MainType 112 | }, 113 | { -- Class NameSpace [7] 114 | address = ClassInfo.ClassInfoAddress + self.NameSpaceOffset, 115 | flags = Il2cpp.MainType 116 | }, 117 | { -- Class Static Field Data [8] 118 | address = ClassInfo.ClassInfoAddress + self.StaticFieldDataOffset, 119 | flags = Il2cpp.MainType 120 | }, 121 | { -- EnumType [9] 122 | address = ClassInfo.ClassInfoAddress + self.EnumType, 123 | flags = gg.TYPE_BYTE 124 | }, 125 | { -- TypeMetadataHandle [10] 126 | address = ClassInfo.ClassInfoAddress + self.TypeMetadataHandle, 127 | flags = Il2cpp.MainType 128 | }, 129 | { -- InstanceSize [11] 130 | address = ClassInfo.ClassInfoAddress + self.InstanceSize, 131 | flags = gg.TYPE_DWORD 132 | }, 133 | { -- Token [12] 134 | address = ClassInfo.ClassInfoAddress + self.Token, 135 | flags = gg.TYPE_DWORD 136 | } 137 | }) 138 | local ClassName = ClassInfo.ClassName or Il2cpp.Utf8ToString(Il2cpp.FixValue(_ClassInfo[1].value)) 139 | local ClassCharacteristic = { 140 | ClassName = ClassName, 141 | IsEnum = ((_ClassInfo[9].value >> self.EnumRsh) & 1) == 1, 142 | TypeMetadataHandle = Il2cpp.FixValue(_ClassInfo[10].value) 143 | } 144 | return setmetatable({ 145 | ClassName = ClassName, 146 | ClassAddress = string.format('%X', Il2cpp.FixValue(ClassInfo.ClassInfoAddress)), 147 | Methods = (_ClassInfo[2].value > 0 and Config.MethodsDump) and 148 | self:GetClassMethods(Il2cpp.FixValue(_ClassInfo[4].value), _ClassInfo[2].value, ClassName) or nil, 149 | Fields = (_ClassInfo[3].value > 0 and Config.FieldsDump) and 150 | self:GetClassFields(Il2cpp.FixValue(_ClassInfo[5].value), _ClassInfo[3].value, ClassCharacteristic) or 151 | nil, 152 | Parent = _ClassInfo[6].value ~= 0 and { 153 | ClassAddress = string.format('%X', Il2cpp.FixValue(_ClassInfo[6].value)), 154 | ClassName = self:GetClassName(_ClassInfo[6].value) 155 | } or nil, 156 | ClassNameSpace = Il2cpp.Utf8ToString(Il2cpp.FixValue(_ClassInfo[7].value)), 157 | StaticFieldData = _ClassInfo[8].value ~= 0 and Il2cpp.FixValue(_ClassInfo[8].value) or nil, 158 | IsEnum = ClassCharacteristic.IsEnum, 159 | TypeMetadataHandle = ClassCharacteristic.TypeMetadataHandle, 160 | InstanceSize = _ClassInfo[11].value, 161 | Token = string.format("0x%X", _ClassInfo[12].value), 162 | ImageName = ClassInfo.ImageName 163 | }, { 164 | __index = Il2cpp.ClassInfoApi, 165 | __tostring = StringUtils.ClassInfoToDumpCS 166 | }) 167 | end, 168 | 169 | --- Defines not quite accurately, especially in the 29th version of the backend 170 | ---@param Address number 171 | IsClassInfo = function(Address) 172 | local imageAddress = Il2cpp.FixValue(gg.getValues( 173 | { 174 | { 175 | address = Il2cpp.FixValue(Address), 176 | flags = Il2cpp.MainType 177 | } 178 | } 179 | )[1].value) 180 | local imageStr = Il2cpp.Utf8ToString(Il2cpp.FixValue(gg.getValues( 181 | { 182 | { 183 | address = imageAddress, 184 | flags = Il2cpp.MainType 185 | } 186 | } 187 | )[1].value)) 188 | local check = string.find(imageStr, ".-%.dll") or string.find(imageStr, "__Generated") 189 | return check and imageStr or nil 190 | end, 191 | 192 | 193 | ---@param self ClassApi 194 | ---@param ClassName string 195 | ---@param searchResult ClassMemory 196 | FindClassWithName = function(self, ClassName, searchResult) 197 | local ClassNamePoint = Il2cpp.GlobalMetadataApi.GetPointersToString(ClassName) 198 | local ResultTable = {} 199 | if #ClassNamePoint > searchResult.len then 200 | for classPointIndex, classPoint in ipairs(ClassNamePoint) do 201 | local classAddress = classPoint.address - self.NameOffset 202 | local imageName = self.IsClassInfo(classAddress) 203 | if (imageName) then 204 | ResultTable[#ResultTable + 1] = { 205 | ClassInfoAddress = Il2cpp.FixValue(classAddress), 206 | ClassName = ClassName, 207 | ImageName = imageName 208 | } 209 | end 210 | end 211 | searchResult.len = #ClassNamePoint 212 | else 213 | searchResult.isNew = false 214 | end 215 | assert(#ResultTable > 0, string.format("The '%s' class is not initialized", ClassName)) 216 | return ResultTable 217 | end, 218 | 219 | 220 | ---@param self ClassApi 221 | ---@param ClassAddress number 222 | ---@param searchResult ClassMemory 223 | ---@return ClassInfoRaw[] 224 | FindClassWithAddressInMemory = function(self, ClassAddress, searchResult) 225 | local ResultTable = {} 226 | if searchResult.len < 1 then 227 | local imageName = self.IsClassInfo(ClassAddress) 228 | if imageName then 229 | ResultTable[#ResultTable + 1] = { 230 | ClassInfoAddress = ClassAddress, 231 | ImageName = imageName 232 | } 233 | end 234 | searchResult.len = 1 235 | else 236 | searchResult.isNew = false 237 | end 238 | assert(#ResultTable > 0, string.format("nothing was found for this address 0x%X", ClassAddress)) 239 | return ResultTable 240 | end, 241 | 242 | 243 | FindParamsCheck = { 244 | ---@param self ClassApi 245 | ---@param _class number @Class Address In Memory 246 | ---@param searchResult ClassMemory 247 | ['number'] = function(self, _class, searchResult) 248 | return Protect:Call(self.FindClassWithAddressInMemory, self, _class, searchResult) 249 | end, 250 | ---@param self ClassApi 251 | ---@param _class string @Class Name 252 | ---@param searchResult ClassMemory 253 | ['string'] = function(self, _class, searchResult) 254 | return Protect:Call(self.FindClassWithName, self, _class, searchResult) 255 | end, 256 | ['default'] = function() 257 | return { 258 | Error = 'Invalid search criteria' 259 | } 260 | end 261 | }, 262 | 263 | 264 | ---@param self ClassApi 265 | ---@param class ClassConfig 266 | ---@return ClassInfo[] | ErrorSearch 267 | Find = function(self, class) 268 | local searchResult = Il2cppMemory:GetInformationOfClass(class.Class) 269 | if not searchResult 270 | or (class.FieldsDump and searchResult.config.FieldsDump ~= class.FieldsDump) 271 | or (class.MethodsDump and searchResult.config.MethodsDump ~= class.MethodsDump) then 272 | searchResult = {len = 0} 273 | end 274 | 275 | searchResult.isNew = true 276 | 277 | ---@type ClassInfoRaw[] | ErrorSearch 278 | local ClassInfo = 279 | (self.FindParamsCheck[type(class.Class)] or self.FindParamsCheck['default'])(self, class.Class, searchResult) 280 | if searchResult.isNew then 281 | for k = 1, #ClassInfo do 282 | ClassInfo[k] = self:UnpackClassInfo(ClassInfo[k], { 283 | FieldsDump = class.FieldsDump, 284 | MethodsDump = class.MethodsDump 285 | }) 286 | end 287 | searchResult.config = { 288 | Class = class.Class, 289 | FieldsDump = class.FieldsDump, 290 | MethodsDump = class.MethodsDump 291 | } 292 | searchResult.result = ClassInfo 293 | Il2cppMemory:SetInformationOfClass(class.Class, searchResult) 294 | else 295 | ClassInfo = searchResult.result 296 | end 297 | return ClassInfo 298 | end 299 | } 300 | 301 | return ClassApi -------------------------------------------------------------------------------- /il2cppstruct/field.lua: -------------------------------------------------------------------------------- 1 | local Protect = require("utils.protect") 2 | 3 | ---@class FieldApi 4 | ---@field Offset number 5 | ---@field Type number 6 | ---@field ClassOffset number 7 | ---@field Find fun(self : FieldApi, fieldSearchCondition : string | number) : FieldInfo[] | ErrorSearch 8 | local FieldApi = { 9 | 10 | 11 | ---@param self FieldApi 12 | ---@param FieldInfoAddress number 13 | UnpackFieldInfo = function(self, FieldInfoAddress) 14 | return { 15 | { -- Field Name 16 | address = FieldInfoAddress, 17 | flags = Il2cpp.MainType 18 | }, 19 | { -- Offset Field 20 | address = FieldInfoAddress + self.Offset, 21 | flags = gg.TYPE_WORD 22 | }, 23 | { -- Field type 24 | address = FieldInfoAddress + self.Type, 25 | flags = Il2cpp.MainType 26 | }, 27 | { -- Class address 28 | address = FieldInfoAddress + self.ClassOffset, 29 | flags = Il2cpp.MainType 30 | } 31 | } 32 | end, 33 | 34 | 35 | ---@param self FieldApi 36 | DecodeFieldsInfo = function(self, FieldsInfo, ClassCharacteristic) 37 | local index, _FieldsInfo = 0, {} 38 | local fieldStart = gg.getValues({{ 39 | address = ClassCharacteristic.TypeMetadataHandle + Il2cpp.Il2CppTypeDefinitionApi.fieldStart, 40 | flags = gg.TYPE_DWORD 41 | }})[1].value 42 | for i = 1, #FieldsInfo, 4 do 43 | index = index + 1 44 | local TypeInfo = Il2cpp.FixValue(FieldsInfo[i + 2].value) 45 | local _TypeInfo = gg.getValues({ 46 | { -- attrs 47 | address = TypeInfo + self.Type, 48 | flags = gg.TYPE_WORD 49 | }, 50 | { -- type index | type 51 | address = TypeInfo + Il2cpp.TypeApi.Type, 52 | flags = gg.TYPE_BYTE 53 | }, 54 | { -- index | data 55 | address = TypeInfo, 56 | flags = Il2cpp.MainType 57 | } 58 | }) 59 | local attrs = _TypeInfo[1].value 60 | local IsConst = (attrs & Il2CppFlags.Field.FIELD_ATTRIBUTE_LITERAL) ~= 0 61 | _FieldsInfo[index] = setmetatable({ 62 | ClassName = ClassCharacteristic.ClassName or Il2cpp.ClassApi:GetClassName(FieldsInfo[i + 3].value), 63 | ClassAddress = string.format('%X', Il2cpp.FixValue(FieldsInfo[i + 3].value)), 64 | FieldName = Il2cpp.Utf8ToString(Il2cpp.FixValue(FieldsInfo[i].value)), 65 | Offset = string.format('%X', FieldsInfo[i + 1].value), 66 | IsStatic = (not IsConst) and ((attrs & Il2CppFlags.Field.FIELD_ATTRIBUTE_STATIC) ~= 0), 67 | Type = Il2cpp.TypeApi:GetTypeName(_TypeInfo[2].value, _TypeInfo[3].value), 68 | IsConst = IsConst, 69 | Access = Il2CppFlags.Field.Access[attrs & Il2CppFlags.Field.FIELD_ATTRIBUTE_FIELD_ACCESS_MASK] or "", 70 | }, { 71 | __index = Il2cpp.FieldInfoApi, 72 | fieldIndex = fieldStart + index - 1 73 | }) 74 | end 75 | return _FieldsInfo 76 | end, 77 | 78 | 79 | ---@param self FieldApi 80 | ---@param fieldName string 81 | ---@return FieldInfo[] 82 | FindFieldWithName = function(self, fieldName) 83 | local fieldNamePoint = Il2cpp.GlobalMetadataApi.GetPointersToString(fieldName) 84 | local ResultTable = {} 85 | for k, v in ipairs(fieldNamePoint) do 86 | local classAddress = gg.getValues({{ 87 | address = v.address + self.ClassOffset, 88 | flags = Il2cpp.MainType 89 | }})[1].value 90 | if Il2cpp.ClassApi.IsClassInfo(classAddress) then 91 | local result = self.FindFieldInClass(fieldName, classAddress) 92 | table.move(result, 1, #result, #ResultTable + 1, ResultTable) 93 | end 94 | end 95 | assert(type(ResultTable) == "table" and #ResultTable > 0, string.format("The '%s' field is not initialized", fieldName)) 96 | return ResultTable 97 | end, 98 | 99 | 100 | ---@param self FieldApi 101 | FindFieldWithAddress = function(self, fieldAddress) 102 | local ObjectHead = Il2cpp.ObjectApi.FindHead(fieldAddress) 103 | local fieldOffset = fieldAddress - ObjectHead.address 104 | local classAddress = Il2cpp.FixValue(ObjectHead.value) 105 | local ResultTable = self.FindFieldInClass(fieldOffset, classAddress) 106 | assert(#ResultTable > 0, string.format("nothing was found for this address 0x%X", fieldAddress)) 107 | return ResultTable 108 | end, 109 | 110 | FindFieldInClass = function(fieldSearchCondition, classAddress) 111 | local ResultTable = {} 112 | local Il2cppClass = Il2cpp.FindClass({ 113 | { 114 | Class = classAddress, 115 | FieldsDump = true 116 | } 117 | })[1] 118 | for i, v in ipairs(Il2cppClass) do 119 | ResultTable[#ResultTable + 1] = type(fieldSearchCondition) == "number" 120 | and v:GetFieldWithOffset(fieldSearchCondition) 121 | or v:GetFieldWithName(fieldSearchCondition) 122 | end 123 | return ResultTable 124 | end, 125 | 126 | 127 | FindTypeCheck = { 128 | ---@param self FieldApi 129 | ---@param fieldName string 130 | ['string'] = function(self, fieldName) 131 | return Protect:Call(self.FindFieldWithName, self, fieldName) 132 | end, 133 | ---@param self FieldApi 134 | ---@param fieldAddress number 135 | ['number'] = function(self, fieldAddress) 136 | return Protect:Call(self.FindFieldWithAddress, self, fieldAddress) 137 | end, 138 | ['default'] = function() 139 | return { 140 | Error = 'Invalid search criteria' 141 | } 142 | end 143 | }, 144 | 145 | 146 | ---@param self FieldApi 147 | ---@param fieldSearchCondition number | string 148 | ---@return FieldInfo[] | ErrorSearch 149 | Find = function(self, fieldSearchCondition) 150 | local FieldsInfo = (self.FindTypeCheck[type(fieldSearchCondition)] or self.FindTypeCheck['default'])(self, fieldSearchCondition) 151 | return FieldsInfo 152 | end 153 | } 154 | 155 | return FieldApi 156 | -------------------------------------------------------------------------------- /il2cppstruct/globalmetadata.lua: -------------------------------------------------------------------------------- 1 | ---@class GlobalMetadataApi 2 | ---@field typeDefinitionsSize number 3 | ---@field typeDefinitionsOffset number 4 | ---@field stringOffset number 5 | ---@field fieldDefaultValuesOffset number 6 | ---@field fieldDefaultValuesSize number 7 | ---@field fieldAndParameterDefaultValueDataOffset number 8 | ---@field version number 9 | local GlobalMetadataApi = { 10 | 11 | 12 | ---@type table 13 | behaviorForTypes = { 14 | [2] = function(blob) 15 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_BYTE) 16 | end, 17 | [3] = function(blob) 18 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_BYTE) 19 | end, 20 | [4] = function(blob) 21 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_BYTE) 22 | end, 23 | [5] = function(blob) 24 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_BYTE) 25 | end, 26 | [6] = function(blob) 27 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_WORD) 28 | end, 29 | [7] = function(blob) 30 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_WORD) 31 | end, 32 | [8] = function(blob) 33 | local self = Il2cpp.GlobalMetadataApi 34 | return self.version < 29 and self.ReadNumberConst(blob, gg.TYPE_DWORD) or self.ReadCompressedInt32(blob) 35 | end, 36 | [9] = function(blob) 37 | local self = Il2cpp.GlobalMetadataApi 38 | return self.version < 29 and Il2cpp.FixValue(self.ReadNumberConst(blob, gg.TYPE_DWORD)) or self.ReadCompressedUInt32(blob) 39 | end, 40 | [10] = function(blob) 41 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_QWORD) 42 | end, 43 | [11] = function(blob) 44 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_QWORD) 45 | end, 46 | [12] = function(blob) 47 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_FLOAT) 48 | end, 49 | [13] = function(blob) 50 | return Il2cpp.GlobalMetadataApi.ReadNumberConst(blob, gg.TYPE_DOUBLE) 51 | end, 52 | [14] = function(blob) 53 | local self = Il2cpp.GlobalMetadataApi 54 | local length, offset = 0, 0 55 | if self.version >= 29 then 56 | length, offset = self.ReadCompressedInt32(blob) 57 | else 58 | length = self.ReadNumberConst(blob, gg.TYPE_DWORD) 59 | offset = 4 60 | end 61 | 62 | if length ~= -1 then 63 | return Il2cpp.Utf8ToString(blob + offset, length) 64 | end 65 | return "" 66 | end 67 | }, 68 | 69 | 70 | ---@param self GlobalMetadataApi 71 | ---@param index number 72 | GetStringFromIndex = function(self, index) 73 | local stringDefinitions = Il2cpp.globalMetadataStart + self.stringOffset 74 | return Il2cpp.Utf8ToString(stringDefinitions + index) 75 | end, 76 | 77 | 78 | ---@param self GlobalMetadataApi 79 | GetClassNameFromIndex = function(self, index) 80 | if (self.version < 27) then 81 | local typeDefinitions = Il2cpp.globalMetadataStart + self.typeDefinitionsOffset 82 | index = (self.typeDefinitionsSize * index) + typeDefinitions 83 | else 84 | index = Il2cpp.FixValue(index) 85 | end 86 | local typeDefinition = gg.getValues({{ 87 | address = index, 88 | flags = gg.TYPE_DWORD 89 | }})[1].value 90 | return self:GetStringFromIndex(typeDefinition) 91 | end, 92 | 93 | 94 | ---@param self GlobalMetadataApi 95 | ---@param dataIndex number 96 | GetFieldOrParameterDefalutValue = function(self, dataIndex) 97 | return self.fieldAndParameterDefaultValueDataOffset + Il2cpp.globalMetadataStart + dataIndex 98 | end, 99 | 100 | 101 | ---@param self GlobalMetadataApi 102 | ---@param index string 103 | GetIl2CppFieldDefaultValue = function(self, index) 104 | gg.clearResults() 105 | gg.setRanges(0) 106 | gg.setRanges(gg.REGION_C_HEAP | gg.REGION_C_HEAP | gg.REGION_ANONYMOUS | gg.REGION_C_BSS | gg.REGION_C_DATA | 107 | gg.REGION_OTHER | gg.REGION_C_ALLOC) 108 | gg.searchNumber(index, gg.TYPE_DWORD, false, gg.SIGN_EQUAL, 109 | Il2cpp.globalMetadataStart + self.fieldDefaultValuesOffset, 110 | Il2cpp.globalMetadataStart + self.fieldDefaultValuesOffset + self.fieldDefaultValuesSize) 111 | if gg.getResultsCount() > 0 then 112 | local Il2CppFieldDefaultValue = gg.getResults(1) 113 | gg.clearResults() 114 | return Il2CppFieldDefaultValue 115 | end 116 | return {} 117 | end, 118 | 119 | 120 | ---@param Address number 121 | ReadCompressedUInt32 = function(Address) 122 | local val, offset = 0, 0 123 | local read = gg.getValues({ 124 | { -- [1] 125 | address = Address, 126 | flags = gg.TYPE_BYTE 127 | }, 128 | { -- [2] 129 | address = Address + 1, 130 | flags = gg.TYPE_BYTE 131 | }, 132 | { -- [3] 133 | address = Address + 2, 134 | flags = gg.TYPE_BYTE 135 | }, 136 | { -- [4] 137 | address = Address + 3, 138 | flags = gg.TYPE_BYTE 139 | } 140 | }) 141 | local read1 = read[1].value & 0xFF 142 | offset = 1 143 | if (read1 & 0x80) == 0 then 144 | val = read1 145 | elseif (read1 & 0xC0) == 0x80 then 146 | val = (read1 & ~0x80) << 8 147 | val = val | (read[2].value & 0xFF) 148 | offset = offset + 1 149 | elseif (read1 & 0xE0) == 0xC0 then 150 | val = (read1 & ~0xC0) << 24 151 | val = val | ((read[2].value & 0xFF) << 16) 152 | val = val | ((read[3].value & 0xFF) << 8) 153 | val = val | (read[4].value & 0xFF) 154 | offset = offset + 3 155 | elseif read1 == 0xF0 then 156 | val = gg.getValues({{address = Address + 1, flags = gg.TYPE_DWORD}})[1].value 157 | offset = offset + 4 158 | elseif read1 == 0xFE then 159 | val = 0xffffffff - 1 160 | elseif read1 == 0xFF then 161 | val = 0xffffffff 162 | end 163 | return val, offset 164 | end, 165 | 166 | 167 | ---@param Address number 168 | ReadCompressedInt32 = function(Address) 169 | local encoded, offset = Il2cpp.GlobalMetadataApi.ReadCompressedUInt32(Address) 170 | 171 | if encoded == 0xffffffff then 172 | return -2147483647 - 1 173 | end 174 | 175 | local isNegative = (encoded & 1) == 1 176 | encoded = encoded >> 1 177 | if isNegative then 178 | return -(encoded + 1) 179 | end 180 | return encoded, offset 181 | end, 182 | 183 | 184 | ---@param Address number 185 | ---@param ggType number @gg.TYPE_ 186 | ReadNumberConst = function(Address, ggType) 187 | return gg.getValues({{ 188 | address = Address, 189 | flags = ggType 190 | }})[1].value 191 | end, 192 | 193 | 194 | ---@param self GlobalMetadataApi 195 | ---@param index number 196 | ---@return number | string | nil 197 | GetDefaultFieldValue = function(self, index) 198 | local Il2CppFieldDefaultValue = self:GetIl2CppFieldDefaultValue(tostring(index)) 199 | if #Il2CppFieldDefaultValue > 0 then 200 | local _Il2CppFieldDefaultValue = gg.getValues({ 201 | { -- TypeIndex [1] 202 | address = Il2CppFieldDefaultValue[1].address + 4, 203 | flags = gg.TYPE_DWORD, 204 | }, 205 | { -- dataIndex [2] 206 | address = Il2CppFieldDefaultValue[1].address + 8, 207 | flags = gg.TYPE_DWORD 208 | } 209 | }) 210 | local blob = self:GetFieldOrParameterDefalutValue(_Il2CppFieldDefaultValue[2].value) 211 | local Il2CppType = Il2cpp.MetadataRegistrationApi:GetIl2CppTypeFromIndex(_Il2CppFieldDefaultValue[1].value) 212 | local typeEnum = Il2cpp.TypeApi:GetTypeEnum(Il2CppType) 213 | ---@type string | fun(blob : number) : string | number 214 | local behavior = self.behaviorForTypes[typeEnum] or "Not support type" 215 | if type(behavior) == "function" then 216 | return behavior(blob) 217 | end 218 | return behavior 219 | end 220 | return nil 221 | end, 222 | 223 | 224 | ---@param name string 225 | GetPointersToString = function(name) 226 | local pointers = {} 227 | gg.clearResults() 228 | gg.setRanges(0) 229 | gg.setRanges(gg.REGION_C_HEAP | gg.REGION_C_HEAP | gg.REGION_ANONYMOUS | gg.REGION_C_BSS | gg.REGION_C_DATA | 230 | gg.REGION_OTHER | gg.REGION_C_ALLOC) 231 | gg.searchNumber(string.format("Q 00 '%s' 00", name), gg.TYPE_BYTE, false, gg.SIGN_EQUAL, 232 | Il2cpp.globalMetadataStart, Il2cpp.globalMetadataEnd) 233 | gg.searchPointer(0) 234 | pointers = gg.getResults(gg.getResultsCount()) 235 | assert(type(pointers) == 'table' and #pointers > 0, string.format("this '%s' is not in the global-metadata", name)) 236 | gg.clearResults() 237 | return pointers 238 | end 239 | } 240 | 241 | return GlobalMetadataApi -------------------------------------------------------------------------------- /il2cppstruct/il2cppstring.lua: -------------------------------------------------------------------------------- 1 | ---@class StringApi 2 | ---@field address number 3 | ---@field pointToStr number 4 | ---@field Fields table 5 | ---@field ClassAddress number 6 | local StringApi = { 7 | 8 | ---@param self StringApi 9 | ---@param newStr string 10 | EditString = function(self, newStr) 11 | local _stringLength = gg.getValues{{address = self.address + self.Fields._stringLength, flags = gg.TYPE_DWORD}}[1].value 12 | _stringLength = _stringLength * 2 13 | local bytes = gg.bytes(newStr, "UTF-16LE") 14 | if _stringLength == #bytes then 15 | local strStart = self.address + self.Fields._firstChar 16 | for i, v in ipairs(bytes) do 17 | bytes[i] = { 18 | address = strStart + (i - 1), 19 | flags = gg.TYPE_BYTE, 20 | value = v 21 | } 22 | end 23 | 24 | gg.setValues(bytes) 25 | elseif _stringLength > #bytes then 26 | local strStart = self.address + self.Fields._firstChar 27 | local _bytes = {} 28 | for i = 1, _stringLength do 29 | _bytes[#_bytes + 1] = { 30 | address = strStart + (i - 1), 31 | flags = gg.TYPE_BYTE, 32 | value = bytes[i] or 0 33 | } 34 | end 35 | 36 | gg.setValues(_bytes) 37 | elseif _stringLength < #bytes then 38 | self.address = Il2cpp.MemoryManager.MAlloc(self.Fields._firstChar + #bytes + 8) 39 | local length = #bytes % 2 == 1 and #bytes + 1 or #bytes 40 | local _bytes = { 41 | { -- Head 42 | address = self.address, 43 | flags = Il2cpp.MainType, 44 | value = self.ClassAddress 45 | }, 46 | { -- _stringLength 47 | address = self.address + self.Fields._stringLength, 48 | flags = gg.TYPE_DWORD, 49 | value = length / 2 50 | } 51 | } 52 | local strStart = self.address + self.Fields._firstChar 53 | for i = 1, length do 54 | _bytes[#_bytes + 1] = { 55 | address = strStart + (i - 1), 56 | flags = gg.TYPE_BYTE, 57 | value = bytes[i] or 0 58 | } 59 | end 60 | _bytes[#_bytes + 1] = { 61 | address = self.pointToStr, 62 | flags = Il2cpp.MainType, 63 | value = self.address 64 | } 65 | gg.setValues(_bytes) 66 | end 67 | end, 68 | 69 | 70 | 71 | ---@param self StringApi 72 | ---@return string 73 | ReadString = function(self) 74 | local _stringLength = gg.getValues{{address = self.address + self.Fields._stringLength, flags = gg.TYPE_DWORD}}[1].value 75 | local bytes = {} 76 | if _stringLength > 0 and _stringLength < 200 then 77 | local strStart = self.address + self.Fields._firstChar 78 | for i = 0, _stringLength do 79 | bytes[#bytes + 1] = { 80 | address = strStart + (i << 1), 81 | flags = gg.TYPE_WORD 82 | } 83 | end 84 | bytes = gg.getValues(bytes) 85 | local code = {[[return "]]} 86 | for i, v in ipairs(bytes) do 87 | code[#code + 1] = string.format([[\u{%x}]], v.value & 0xFFFF) 88 | end 89 | code[#code + 1] = '"' 90 | local read, err = load(table.concat(code)) 91 | if read then 92 | return read() 93 | end 94 | end 95 | return "" 96 | end 97 | } 98 | 99 | ---@class MyString 100 | ---@field From fun(address : number) : StringApi | nil 101 | local String = { 102 | 103 | ---@param address number 104 | ---@return StringApi | nil 105 | From = function(address) 106 | local pointToStr = gg.getValues({{address = Il2cpp.FixValue(address), flags = Il2cpp.MainType}})[1] 107 | local str = setmetatable( 108 | { 109 | address = Il2cpp.FixValue(pointToStr.value), 110 | Fields = {}, 111 | pointToStr = Il2cpp.FixValue(address) 112 | }, {__index = StringApi}) 113 | local pointClassAddress = gg.getValues({{address = str.address, flags = Il2cpp.MainType}})[1].value 114 | local stringInfo = Il2cpp.FindClass({{Class = Il2cpp.FixValue(pointClassAddress), FieldsDump = true}})[1] 115 | for i, v in ipairs(stringInfo) do 116 | if v.ClassNameSpace == "System" then 117 | str.ClassAddress = tonumber(v.ClassAddress, 16) 118 | for indexField, FieldInfo in ipairs(v.Fields) do 119 | str.Fields[FieldInfo.FieldName] = tonumber(FieldInfo.Offset, 16) 120 | end 121 | return str 122 | end 123 | end 124 | return nil 125 | end, 126 | 127 | } 128 | 129 | return String -------------------------------------------------------------------------------- /il2cppstruct/metadataRegistration.lua: -------------------------------------------------------------------------------- 1 | local Searcher = require("utils.universalsearcher") 2 | 3 | ---@class MetadataRegistrationApi 4 | ---@field metadataRegistration number 5 | ---@field types number 6 | local MetadataRegistrationApi = { 7 | 8 | 9 | ---@param self MetadataRegistrationApi 10 | ---@return number 11 | GetIl2CppTypeFromIndex = function(self, index) 12 | if not self.metadataRegistration then 13 | self:FindMetadataRegistration() 14 | end 15 | local types = gg.getValues({{address = self.metadataRegistration + self.types, flags = Il2cpp.MainType}})[1].value 16 | return Il2cpp.FixValue(gg.getValues({{address = types + (Il2cpp.pointSize * index), flags = Il2cpp.MainType}})[1].value) 17 | end, 18 | 19 | 20 | ---@param self MetadataRegistrationApi 21 | ---@return void 22 | FindMetadataRegistration = function(self) 23 | self.metadataRegistration = Searcher.Il2CppMetadataRegistration() 24 | end 25 | } 26 | 27 | return MetadataRegistrationApi -------------------------------------------------------------------------------- /il2cppstruct/method.lua: -------------------------------------------------------------------------------- 1 | local AndroidInfo = require("utils.androidinfo") 2 | local Protect = require("utils.protect") 3 | local Il2cppMemory = require("utils.il2cppmemory") 4 | 5 | ---@class MethodsApi 6 | ---@field ClassOffset number 7 | ---@field NameOffset number 8 | ---@field ParamCount number 9 | ---@field ReturnType number 10 | ---@field Flags number 11 | local MethodsApi = { 12 | 13 | 14 | ---@param self MethodsApi 15 | ---@param MethodName string 16 | ---@param searchResult MethodMemory 17 | ---@return MethodInfoRaw[] 18 | FindMethodWithName = function(self, MethodName, searchResult) 19 | local FinalMethods = {} 20 | local MethodNamePointers = Il2cpp.GlobalMetadataApi.GetPointersToString(MethodName) 21 | if searchResult.len < #MethodNamePointers then 22 | for methodPointIndex, methodPoint in ipairs(MethodNamePointers) do 23 | methodPoint.address = methodPoint.address - self.NameOffset 24 | local MethodAddress = Il2cpp.FixValue(gg.getValues({methodPoint})[1].value) 25 | if MethodAddress > Il2cpp.il2cppStart and MethodAddress < Il2cpp.il2cppEnd then 26 | FinalMethods[#FinalMethods + 1] = { 27 | MethodName = MethodName, 28 | MethodAddress = MethodAddress, 29 | MethodInfoAddress = methodPoint.address 30 | } 31 | end 32 | end 33 | else 34 | searchResult.isNew = false 35 | end 36 | assert(#FinalMethods > 0, string.format("The '%s' method is not initialized", MethodName)) 37 | return FinalMethods 38 | end, 39 | 40 | 41 | ---@param self MethodsApi 42 | ---@param MethodOffset number 43 | ---@param searchResult MethodMemory | nil 44 | ---@return MethodInfoRaw[] 45 | FindMethodWithOffset = function(self, MethodOffset, searchResult) 46 | local MethodsInfo = self:FindMethodWithAddressInMemory(Il2cpp.il2cppStart + MethodOffset, searchResult, MethodOffset) 47 | return MethodsInfo 48 | end, 49 | 50 | 51 | ---@param self MethodsApi 52 | ---@param MethodAddress number 53 | ---@param searchResult MethodMemory 54 | ---@param MethodOffset number | nil 55 | ---@return MethodInfoRaw[] 56 | FindMethodWithAddressInMemory = function(self, MethodAddress, searchResult, MethodOffset) 57 | local RawMethodsInfo = {} -- the same as MethodsInfo 58 | gg.clearResults() 59 | gg.setRanges(gg.REGION_C_HEAP | gg.REGION_C_ALLOC | gg.REGION_ANONYMOUS | gg.REGION_C_BSS | gg.REGION_C_DATA | 60 | gg.REGION_OTHER) 61 | if gg.BUILD < 16126 then 62 | gg.searchNumber(string.format("%Xh", MethodAddress), Il2cpp.MainType) 63 | else 64 | gg.loadResults({{ 65 | address = MethodAddress, 66 | flags = Il2cpp.MainType 67 | }}) 68 | gg.searchPointer(0) 69 | end 70 | local r_count = gg.getResultsCount() 71 | if r_count > searchResult.len then 72 | local r = gg.getResults(r_count) 73 | for j = 1, #r do 74 | RawMethodsInfo[#RawMethodsInfo + 1] = { 75 | MethodAddress = MethodAddress, 76 | MethodInfoAddress = r[j].address, 77 | Offset = MethodOffset 78 | } 79 | end 80 | else 81 | searchResult.isNew = false 82 | end 83 | gg.clearResults() 84 | assert(#RawMethodsInfo > 0, string.format("nothing was found for this address 0x%X", MethodAddress)) 85 | return RawMethodsInfo 86 | end, 87 | 88 | 89 | ---@param self MethodsApi 90 | ---@param _MethodsInfo MethodInfo[] 91 | DecodeMethodsInfo = function(self, _MethodsInfo, MethodsInfo) 92 | for i = 1, #_MethodsInfo do 93 | local index = (i - 1) * 6 94 | local TypeInfo = Il2cpp.FixValue(MethodsInfo[index + 5].value) 95 | local _TypeInfo = gg.getValues({{ -- type index 96 | address = TypeInfo + Il2cpp.TypeApi.Type, 97 | flags = gg.TYPE_BYTE 98 | }, { -- index 99 | address = TypeInfo, 100 | flags = Il2cpp.MainType 101 | }}) 102 | local MethodAddress = Il2cpp.FixValue(MethodsInfo[index + 1].value) 103 | local MethodFlags = MethodsInfo[index + 6].value 104 | 105 | _MethodsInfo[i] = { 106 | MethodName = _MethodsInfo[i].MethodName or 107 | Il2cpp.Utf8ToString(Il2cpp.FixValue(MethodsInfo[index + 2].value)), 108 | Offset = string.format("%X", _MethodsInfo[i].Offset or (MethodAddress == 0 and MethodAddress or MethodAddress - Il2cpp.il2cppStart)), 109 | AddressInMemory = string.format("%X", MethodAddress), 110 | MethodInfoAddress = _MethodsInfo[i].MethodInfoAddress, 111 | ClassName = _MethodsInfo[i].ClassName or Il2cpp.ClassApi:GetClassName(MethodsInfo[index + 3].value), 112 | ClassAddress = string.format('%X', Il2cpp.FixValue(MethodsInfo[index + 3].value)), 113 | ParamCount = MethodsInfo[index + 4].value, 114 | ReturnType = Il2cpp.TypeApi:GetTypeName(_TypeInfo[1].value, _TypeInfo[2].value), 115 | IsStatic = (MethodFlags & Il2CppFlags.Method.METHOD_ATTRIBUTE_STATIC) ~= 0, 116 | Access = Il2CppFlags.Method.Access[MethodFlags & Il2CppFlags.Method.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK] or "", 117 | IsAbstract = (MethodFlags & Il2CppFlags.Method.METHOD_ATTRIBUTE_ABSTRACT) ~= 0, 118 | } 119 | end 120 | end, 121 | 122 | 123 | ---@param self MethodsApi 124 | ---@param MethodInfo MethodInfoRaw 125 | UnpackMethodInfo = function(self, MethodInfo) 126 | return { 127 | { -- [1] Address Method in Memory 128 | address = MethodInfo.MethodInfoAddress, 129 | flags = Il2cpp.MainType 130 | }, 131 | { -- [2] Name Address 132 | address = MethodInfo.MethodInfoAddress + self.NameOffset, 133 | flags = Il2cpp.MainType 134 | }, 135 | { -- [3] Class address 136 | address = MethodInfo.MethodInfoAddress + self.ClassOffset, 137 | flags = Il2cpp.MainType 138 | }, 139 | { -- [4] Param Count 140 | address = MethodInfo.MethodInfoAddress + self.ParamCount, 141 | flags = gg.TYPE_BYTE 142 | }, 143 | { -- [5] Return Type 144 | address = MethodInfo.MethodInfoAddress + self.ReturnType, 145 | flags = Il2cpp.MainType 146 | }, 147 | { -- [6] Flags 148 | address = MethodInfo.MethodInfoAddress + self.Flags, 149 | flags = gg.TYPE_WORD 150 | } 151 | }, 152 | { 153 | MethodName = MethodInfo.MethodName or nil, 154 | Offset = MethodInfo.Offset or nil, 155 | MethodInfoAddress = MethodInfo.MethodInfoAddress, 156 | ClassName = MethodInfo.ClassName 157 | } 158 | end, 159 | 160 | 161 | FindParamsCheck = { 162 | ---@param self MethodsApi 163 | ---@param method number 164 | ---@param searchResult MethodMemory 165 | ['number'] = function(self, method, searchResult) 166 | if (method > Il2cpp.il2cppStart and method < Il2cpp.il2cppEnd) then 167 | return Protect:Call(self.FindMethodWithAddressInMemory, self, method, searchResult) 168 | else 169 | return Protect:Call(self.FindMethodWithOffset, self, method, searchResult) 170 | end 171 | end, 172 | ---@param self MethodsApi 173 | ---@param method string 174 | ---@param searchResult MethodMemory 175 | ['string'] = function(self, method, searchResult) 176 | return Protect:Call(self.FindMethodWithName, self, method, searchResult) 177 | end, 178 | ['default'] = function() 179 | return { 180 | Error = 'Invalid search criteria' 181 | } 182 | end 183 | }, 184 | 185 | 186 | ---@param self MethodsApi 187 | ---@param method number | string 188 | ---@return MethodInfo[] | ErrorSearch 189 | Find = function(self, method) 190 | local searchResult = Il2cppMemory:GetInformaionOfMethod(method) 191 | if not searchResult then 192 | searchResult = {len = 0} 193 | end 194 | searchResult.isNew = true 195 | 196 | ---@type MethodInfoRaw[] | ErrorSearch 197 | local _MethodsInfo = (self.FindParamsCheck[type(method)] or self.FindParamsCheck['default'])(self, method, searchResult) 198 | if searchResult.isNew then 199 | local MethodsInfo = {} 200 | for i = 1, #_MethodsInfo do 201 | local MethodInfo 202 | MethodInfo, _MethodsInfo[i] = self:UnpackMethodInfo(_MethodsInfo[i]) 203 | table.move(MethodInfo, 1, #MethodInfo, #MethodsInfo + 1, MethodsInfo) 204 | end 205 | MethodsInfo = gg.getValues(MethodsInfo) 206 | self:DecodeMethodsInfo(_MethodsInfo, MethodsInfo) 207 | 208 | -- save result 209 | searchResult.len = #_MethodsInfo 210 | searchResult.result = _MethodsInfo 211 | Il2cppMemory:SetInformaionOfMethod(method, searchResult) 212 | else 213 | _MethodsInfo = searchResult.result 214 | end 215 | 216 | return _MethodsInfo 217 | end 218 | } 219 | 220 | return MethodsApi -------------------------------------------------------------------------------- /il2cppstruct/object.lua: -------------------------------------------------------------------------------- 1 | local AndroidInfo = require("utils.androidinfo") 2 | 3 | ---@class ObjectApi 4 | local ObjectApi = { 5 | 6 | 7 | ---@param self ObjectApi 8 | ---@param Objects table 9 | FilterObjects = function(self, Objects) 10 | local FilterObjects = {} 11 | for k, v in ipairs(gg.getValuesRange(Objects)) do 12 | if v == 'A' then 13 | FilterObjects[#FilterObjects + 1] = Objects[k] 14 | end 15 | end 16 | Objects = FilterObjects 17 | gg.loadResults(Objects) 18 | gg.searchPointer(0) 19 | if gg.getResultsCount() <= 0 and AndroidInfo.platform and AndroidInfo.sdk >= 30 then 20 | local FixRefToObjects = {} 21 | for k, v in ipairs(Objects) do 22 | gg.searchNumber(tostring(v.address | 0xB400000000000000), gg.TYPE_QWORD) 23 | ---@type tablelib 24 | local RefToObject = gg.getResults(gg.getResultsCount()) 25 | table.move(RefToObject, 1, #RefToObject, #FixRefToObjects + 1, FixRefToObjects) 26 | gg.clearResults() 27 | end 28 | gg.loadResults(FixRefToObjects) 29 | end 30 | local RefToObjects, FilterObjects = gg.getResults(gg.getResultsCount()), {} 31 | gg.clearResults() 32 | for k, v in ipairs(gg.getValuesRange(RefToObjects)) do 33 | if v == 'A' then 34 | FilterObjects[#FilterObjects + 1] = { 35 | address = Il2cpp.FixValue(RefToObjects[k].value), 36 | flags = RefToObjects[k].flags 37 | } 38 | end 39 | end 40 | gg.loadResults(FilterObjects) 41 | local _FilterObjects = gg.getResults(gg.getResultsCount()) 42 | gg.clearResults() 43 | return _FilterObjects 44 | end, 45 | 46 | 47 | ---@param self ObjectApi 48 | ---@param ClassAddress string 49 | FindObjects = function(self, ClassAddress) 50 | gg.clearResults() 51 | gg.setRanges(0) 52 | gg.setRanges(gg.REGION_C_HEAP | gg.REGION_C_HEAP | gg.REGION_ANONYMOUS | gg.REGION_C_BSS | gg.REGION_C_DATA | 53 | gg.REGION_C_ALLOC) 54 | gg.loadResults({{ 55 | address = tonumber(ClassAddress, 16), 56 | flags = Il2cpp.MainType 57 | }}) 58 | gg.searchPointer(0) 59 | if gg.getResultsCount() <= 0 and AndroidInfo.platform and AndroidInfo.sdk >= 30 then 60 | gg.searchNumber(tostring(tonumber(ClassAddress, 16) | 0xB400000000000000), gg.TYPE_QWORD) 61 | end 62 | local FindsResult = gg.getResults(gg.getResultsCount()) 63 | gg.clearResults() 64 | return self:FilterObjects(FindsResult) 65 | end, 66 | 67 | 68 | ---@param self ObjectApi 69 | ---@param ClassesInfo ClassInfo[] 70 | Find = function(self, ClassesInfo) 71 | local Objects = {} 72 | for j = 1, #ClassesInfo do 73 | local FindResult = self:FindObjects(ClassesInfo[j].ClassAddress) 74 | table.move(FindResult, 1, #FindResult, #Objects + 1, Objects) 75 | end 76 | return Objects 77 | end, 78 | 79 | 80 | FindHead = function(Address) 81 | local validAddress = Il2cpp.GetValidAddress(Address) 82 | local mayBeHead = {} 83 | for i = 1, 1000 do 84 | mayBeHead[i] = { 85 | address = validAddress - (4 * (i - 1)), 86 | flags = Il2cpp.MainType 87 | } 88 | end 89 | mayBeHead = gg.getValues(mayBeHead) 90 | for i = 1, #mayBeHead do 91 | local mayBeClass = Il2cpp.FixValue(mayBeHead[i].value) 92 | if Il2cpp.ClassApi.IsClassInfo(mayBeClass) then 93 | return mayBeHead[i] 94 | end 95 | end 96 | return {value = 0, address = 0} 97 | end, 98 | } 99 | 100 | return ObjectApi -------------------------------------------------------------------------------- /il2cppstruct/type.lua: -------------------------------------------------------------------------------- 1 | local Il2cppMemory = require("utils.il2cppmemory") 2 | 3 | ---@class TypeApi 4 | ---@field Type number 5 | ---@field tableTypes table 6 | local TypeApi = { 7 | 8 | 9 | tableTypes = { 10 | [1] = "void", 11 | [2] = "bool", 12 | [3] = "char", 13 | [4] = "sbyte", 14 | [5] = "byte", 15 | [6] = "short", 16 | [7] = "ushort", 17 | [8] = "int", 18 | [9] = "uint", 19 | [10] = "long", 20 | [11] = "ulong", 21 | [12] = "float", 22 | [13] = "double", 23 | [14] = "string", 24 | [22] = "TypedReference", 25 | [24] = "IntPtr", 26 | [25] = "UIntPtr", 27 | [28] = "object", 28 | [17] = function(index) 29 | return Il2cpp.GlobalMetadataApi:GetClassNameFromIndex(index) 30 | end, 31 | [18] = function(index) 32 | return Il2cpp.GlobalMetadataApi:GetClassNameFromIndex(index) 33 | end, 34 | [29] = function(index) 35 | local typeMassiv = gg.getValues({ 36 | { 37 | address = Il2cpp.FixValue(index), 38 | flags = Il2cpp.MainType 39 | }, 40 | { 41 | address = Il2cpp.FixValue(index) + Il2cpp.TypeApi.Type, 42 | flags = gg.TYPE_BYTE 43 | } 44 | }) 45 | return Il2cpp.TypeApi:GetTypeName(typeMassiv[2].value, typeMassiv[1].value) .. "[]" 46 | end, 47 | [21] = function(index) 48 | if not (Il2cpp.GlobalMetadataApi.version < 27) then 49 | index = gg.getValues({{ 50 | address = Il2cpp.FixValue(index), 51 | flags = Il2cpp.MainType 52 | }})[1].value 53 | end 54 | index = gg.getValues({{ 55 | address = Il2cpp.FixValue(index), 56 | flags = Il2cpp.MainType 57 | }})[1].value 58 | return Il2cpp.GlobalMetadataApi:GetClassNameFromIndex(index) 59 | end 60 | }, 61 | 62 | 63 | ---@param self TypeApi 64 | ---@param typeIndex number @number for tableTypes 65 | ---@param index number @for an api that is higher than 24, this can be a reference to the index 66 | ---@return string 67 | GetTypeName = function(self, typeIndex, index) 68 | ---@type string | fun(index : number) : string 69 | local typeName = self.tableTypes[typeIndex] or string.format('(not support type -> 0x%X)', typeIndex) 70 | if (type(typeName) == 'function') then 71 | local resultType = Il2cppMemory:GetInformationOfType(index) 72 | if not resultType then 73 | resultType = typeName(index) 74 | Il2cppMemory:SetInformationOfType(index, resultType) 75 | end 76 | typeName = resultType 77 | end 78 | return typeName 79 | end, 80 | 81 | 82 | ---@param self TypeApi 83 | ---@param Il2CppType number 84 | GetTypeEnum = function(self, Il2CppType) 85 | return gg.getValues({{address = Il2CppType + self.Type, flags = gg.TYPE_BYTE}})[1].value 86 | end 87 | } 88 | 89 | return TypeApi -------------------------------------------------------------------------------- /index.lua: -------------------------------------------------------------------------------- 1 | require("utils.il2cppconst") 2 | require("il2cpp") 3 | 4 | ---@class ClassInfoRaw 5 | ---@field ClassName string | nil 6 | ---@field ClassInfoAddress number 7 | ---@field ImageName string 8 | 9 | ---@class ClassInfo 10 | ---@field ClassName string 11 | ---@field ClassAddress string 12 | ---@field Methods MethodInfo[] | nil 13 | ---@field Fields FieldInfo[] | nil 14 | ---@field Parent ParentClassInfo | nil 15 | ---@field ClassNameSpace string 16 | ---@field StaticFieldData number | nil 17 | ---@field IsEnum boolean 18 | ---@field TypeMetadataHandle number 19 | ---@field InstanceSize number 20 | ---@field Token string 21 | ---@field ImageName string 22 | ---@field GetFieldWithName fun(self : ClassInfo, name : string) : FieldInfo | nil @Get FieldInfo by Field Name. If Fields weren't dumped, then this function return `nil`. Also, if Field isn't found by name, then function will return `nil` 23 | ---@field GetMethodsWithName fun(self : ClassInfo, name : string) : MethodInfo[] | nil @Get MethodInfo[] by MethodName. If Methods weren't dumped, then this function return `nil`. Also, if Method isn't found by name, then function will return `table with zero size` 24 | ---@field GetFieldWithOffset fun(self : ClassInfo, fieldOffset : number) : FieldInfo | nil 25 | 26 | ---@class ParentClassInfo 27 | ---@field ClassName string 28 | ---@field ClassAddress string 29 | 30 | ---@class FieldInfoRaw 31 | ---@field FieldInfoAddress number 32 | ---@field ClassName string | nil 33 | 34 | 35 | ---@class ClassMemory 36 | ---@field config ClassConfig 37 | ---@field result ClassInfo[] | ErrorSearch 38 | ---@field len number 39 | ---@field isNew boolean | nil 40 | 41 | ---@class MethodMemory 42 | ---@field len number 43 | ---@field result MethodInfo[] | ErrorSearch 44 | ---@field isNew boolean | nil 45 | 46 | ---@class FieldInfo 47 | ---@field ClassName string 48 | ---@field ClassAddress string 49 | ---@field FieldName string 50 | ---@field Offset string 51 | ---@field IsStatic boolean 52 | ---@field Type string 53 | ---@field IsConst boolean 54 | ---@field Access string 55 | ---@field GetConstValue fun(self : FieldInfo) : nil | string | number 56 | 57 | 58 | ---@class MethodInfoRaw 59 | ---@field MethodName string | nil 60 | ---@field Offset number | nil 61 | ---@field MethodInfoAddress number 62 | ---@field ClassName string | nil 63 | ---@field MethodAddress number 64 | 65 | 66 | ---@class ErrorSearch 67 | ---@field Error string 68 | 69 | 70 | ---@class MethodInfo 71 | ---@field MethodName string 72 | ---@field Offset string 73 | ---@field AddressInMemory string 74 | ---@field MethodInfoAddress number 75 | ---@field ClassName string 76 | ---@field ClassAddress string 77 | ---@field ParamCount number 78 | ---@field ReturnType string 79 | ---@field IsStatic boolean 80 | ---@field IsAbstract boolean 81 | ---@field Access string 82 | 83 | 84 | ---@class Il2cppApi 85 | ---@field FieldApiOffset number 86 | ---@field FieldApiType number 87 | ---@field FieldApiClassOffset number 88 | ---@field ClassApiNameOffset number 89 | ---@field ClassApiMethodsStep number 90 | ---@field ClassApiCountMethods number 91 | ---@field ClassApiMethodsLink number 92 | ---@field ClassApiFieldsLink number 93 | ---@field ClassApiFieldsStep number 94 | ---@field ClassApiCountFields number 95 | ---@field ClassApiParentOffset number 96 | ---@field ClassApiNameSpaceOffset number 97 | ---@field ClassApiStaticFieldDataOffset number 98 | ---@field ClassApiEnumType number 99 | ---@field ClassApiEnumRsh number 100 | ---@field ClassApiTypeMetadataHandle number 101 | ---@field ClassApiInstanceSize number 102 | ---@field ClassApiToken number 103 | ---@field MethodsApiClassOffset number 104 | ---@field MethodsApiNameOffset number 105 | ---@field MethodsApiParamCount number 106 | ---@field MethodsApiReturnType number 107 | ---@field MethodsApiFlags number 108 | ---@field typeDefinitionsSize number 109 | ---@field typeDefinitionsOffset number 110 | ---@field stringOffset number 111 | ---@field fieldDefaultValuesOffset number 112 | ---@field fieldDefaultValuesSize number 113 | ---@field fieldAndParameterDefaultValueDataOffset number 114 | ---@field TypeApiType number 115 | ---@field Il2CppTypeDefinitionApifieldStart number 116 | ---@field MetadataRegistrationApitypes number 117 | 118 | 119 | ---@class ClassConfig 120 | ---@field Class number | string @Class Name or Address Class 121 | ---@field FieldsDump boolean 122 | ---@field MethodsDump boolean 123 | 124 | 125 | ---@class Il2cppConfig 126 | ---@field libilcpp table | nil 127 | ---@field globalMetadata table | nil 128 | ---@field il2cppVersion number | nil 129 | ---@field globalMetadataHeader number | nil 130 | ---@field metadataRegistration number | nil 131 | 132 | 133 | ---@class Il2CppTypeDefinitionApi 134 | ---@field fieldStart number 135 | 136 | ---@class MethodFlags 137 | ---@field Access string[] 138 | ---@field METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK number 139 | ---@field METHOD_ATTRIBUTE_STATIC number 140 | ---@field METHOD_ATTRIBUTE_ABSTRACT number 141 | 142 | 143 | ---@class FieldFlags 144 | ---@field Access string[] 145 | ---@field FIELD_ATTRIBUTE_FIELD_ACCESS_MASK number 146 | ---@field FIELD_ATTRIBUTE_STATIC number 147 | ---@field FIELD_ATTRIBUTE_LITERAL number 148 | 149 | 150 | return Il2cpp -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ggil2cpp", 3 | "version": "1.11.0", 4 | "description": "", 5 | "main": "build.ts", 6 | "scripts": { 7 | "start": "ts-node build.ts" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@types/node": "^18.6.5", 14 | "luabundle": "^1.6.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/1.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kruvcraft21/GGIl2cpp/9045be55519d0ee7257044b1caf597801a774df6/test/1.apk -------------------------------------------------------------------------------- /test/img/Screenshot_20220712-090652.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kruvcraft21/GGIl2cpp/9045be55519d0ee7257044b1caf597801a774df6/test/img/Screenshot_20220712-090652.png -------------------------------------------------------------------------------- /test/img/TestModule.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kruvcraft21/GGIl2cpp/9045be55519d0ee7257044b1caf597801a774df6/test/img/TestModule.gif -------------------------------------------------------------------------------- /test/img/photo_2023-03-17_22-35-52.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kruvcraft21/GGIl2cpp/9045be55519d0ee7257044b1caf597801a774df6/test/img/photo_2023-03-17_22-35-52.jpg -------------------------------------------------------------------------------- /test/test.lua: -------------------------------------------------------------------------------- 1 | io.open('il2cppapi.lua',"w+"):write(gg.makeRequest("https://raw.githubusercontent.com/kruvcraft21/GGIl2cpp/master/build/Il2cppApi.lua").content):close() 2 | require('il2cppapi') 3 | os.remove('il2cppapi.lua') 4 | 5 | Il2cpp() 6 | 7 | ---@type ClassConfig 8 | local TestClassConfig = {} 9 | 10 | TestClassConfig.Class = "TestClass" 11 | TestClassConfig.FieldsDump = true 12 | 13 | local TestClasses = Il2cpp.FindClass({TestClassConfig})[1] 14 | 15 | local ChangeTestClasses = {} 16 | 17 | print(TestClasses) 18 | 19 | for k,v in ipairs(TestClasses) do 20 | local TestClassObject = Il2cpp.FindObject({tonumber(v.ClassAddress, 16)})[1] 21 | if v.Parent and v.Parent.ClassName ~= "ValueType" and #v.ClassNameSpace == 0 then 22 | for i = 1, #TestClassObject do 23 | ChangeTestClasses[#ChangeTestClasses + 1] = { 24 | address = TestClassObject[i].address + tonumber(v:GetFieldWithName("Field1").Offset, 16), 25 | flags = gg.TYPE_DWORD, 26 | value = 40 27 | } 28 | ChangeTestClasses[#ChangeTestClasses + 1] = { 29 | address = TestClassObject[i].address + tonumber(v:GetFieldWithName("Field2").Offset, 16), 30 | flags = gg.TYPE_FLOAT, 31 | value = 33 32 | } 33 | end 34 | 35 | ChangeTestClasses[#ChangeTestClasses + 1] = { 36 | address = v.StaticFieldData + tonumber(v:GetFieldWithName("Field3").Offset, 16), 37 | flags = gg.TYPE_DWORD, 38 | value = 12 39 | } 40 | end 41 | 42 | end 43 | 44 | gg.setValues(ChangeTestClasses) 45 | 46 | for k,v in ipairs(TestClasses) do 47 | local Methods = v:GetMethodsWithName("GetField4") 48 | if #Methods > 0 then 49 | for i = 1, #Methods do 50 | Il2cpp.PatchesAddress(tonumber(Methods[i].AddressInMemory, 16), Il2cpp.MainType == gg.TYPE_QWORD and "\x40\x02\x80\x52\xc0\x03\x5f\xd6" or "\x12\x00\xa0\xe3\x1e\xff\x2f\xe1") 51 | end 52 | end 53 | end 54 | 55 | os.exit() -------------------------------------------------------------------------------- /utils/androidinfo.lua: -------------------------------------------------------------------------------- 1 | local AndroidInfo = { 2 | platform = gg.getTargetInfo().x64, 3 | sdk = gg.getTargetInfo().targetSdkVersion 4 | } 5 | 6 | return AndroidInfo -------------------------------------------------------------------------------- /utils/il2cppconst.lua: -------------------------------------------------------------------------------- 1 | local AndroidInfo = require("utils.androidinfo") 2 | 3 | ---@type table 4 | Il2CppConst = { 5 | [20] = { 6 | FieldApiOffset = 0xC, 7 | FieldApiType = 0x4, 8 | FieldApiClassOffset = 0x8, 9 | ClassApiNameOffset = 0x8, 10 | ClassApiMethodsStep = 2, 11 | ClassApiCountMethods = 0x9C, 12 | ClassApiMethodsLink = 0x3C, 13 | ClassApiFieldsLink = 0x30, 14 | ClassApiFieldsStep = 0x18, 15 | ClassApiCountFields = 0xA0, 16 | ClassApiParentOffset = 0x24, 17 | ClassApiNameSpaceOffset = 0xC, 18 | ClassApiStaticFieldDataOffset = 0x50, 19 | ClassApiEnumType = 0xB0, 20 | ClassApiEnumRsh = 2, 21 | ClassApiTypeMetadataHandle = 0x2C, 22 | ClassApiInstanceSize = 0x78, 23 | ClassApiToken = 0x98, 24 | MethodsApiClassOffset = 0xC, 25 | MethodsApiNameOffset = 0x8, 26 | MethodsApiParamCount = 0x2E, 27 | MethodsApiReturnType = 0x10, 28 | MethodsApiFlags = 0x28, 29 | typeDefinitionsSize = 0x70, 30 | typeDefinitionsOffset = 0xA0, 31 | stringOffset = 0x18, 32 | fieldDefaultValuesOffset = 0x40, 33 | fieldDefaultValuesSize = 0x44, 34 | fieldAndParameterDefaultValueDataOffset = 0x48, 35 | TypeApiType = 0x6, 36 | Il2CppTypeDefinitionApifieldStart = 0x38, 37 | MetadataRegistrationApitypes = 0x1C, 38 | }, 39 | [21] = { 40 | FieldApiOffset = 0xC, 41 | FieldApiType = 0x4, 42 | FieldApiClassOffset = 0x8, 43 | ClassApiNameOffset = 0x8, 44 | ClassApiMethodsStep = 2, 45 | ClassApiCountMethods = 0x9C, 46 | ClassApiMethodsLink = 0x3C, 47 | ClassApiFieldsLink = 0x30, 48 | ClassApiFieldsStep = 0x18, 49 | ClassApiCountFields = 0xA0, 50 | ClassApiParentOffset = 0x24, 51 | ClassApiNameSpaceOffset = 0xC, 52 | ClassApiStaticFieldDataOffset = 0x50, 53 | ClassApiEnumType = 0xB0, 54 | ClassApiEnumRsh = 2, 55 | ClassApiTypeMetadataHandle = 0x2C, 56 | ClassApiInstanceSize = 0x78, 57 | ClassApiToken = 0x98, 58 | MethodsApiClassOffset = 0xC, 59 | MethodsApiNameOffset = 0x8, 60 | MethodsApiParamCount = 0x2E, 61 | MethodsApiReturnType = 0x10, 62 | MethodsApiFlags = 0x28, 63 | typeDefinitionsSize = 0x78, 64 | typeDefinitionsOffset = 0xA0, 65 | stringOffset = 0x18, 66 | fieldDefaultValuesOffset = 0x40, 67 | fieldDefaultValuesSize = 0x44, 68 | fieldAndParameterDefaultValueDataOffset = 0x48, 69 | TypeApiType = 0x6, 70 | Il2CppTypeDefinitionApifieldStart = 0x40, 71 | MetadataRegistrationApitypes = 0x1C, 72 | }, 73 | [22] = { 74 | FieldApiOffset = 0xC, 75 | FieldApiType = 0x4, 76 | FieldApiClassOffset = 0x8, 77 | ClassApiNameOffset = 0x8, 78 | ClassApiMethodsStep = 2, 79 | ClassApiCountMethods = 0x94, 80 | ClassApiMethodsLink = 0x3C, 81 | ClassApiFieldsLink = 0x30, 82 | ClassApiFieldsStep = 0x18, 83 | ClassApiCountFields = 0x98, 84 | ClassApiParentOffset = 0x24, 85 | ClassApiNameSpaceOffset = 0xC, 86 | ClassApiStaticFieldDataOffset = 0x4C, 87 | ClassApiEnumType = 0xA9, 88 | ClassApiEnumRsh = 2, 89 | ClassApiTypeMetadataHandle = 0x2C, 90 | ClassApiInstanceSize = 0x70, 91 | ClassApiToken = 0x90, 92 | MethodsApiClassOffset = 0xC, 93 | MethodsApiNameOffset = 0x8, 94 | MethodsApiParamCount = 0x2E, 95 | MethodsApiReturnType = 0x10, 96 | MethodsApiFlags = 0x28, 97 | typeDefinitionsSize = 0x78, 98 | typeDefinitionsOffset = 0xA0, 99 | stringOffset = 0x18, 100 | fieldDefaultValuesOffset = 0x40, 101 | fieldDefaultValuesSize = 0x44, 102 | fieldAndParameterDefaultValueDataOffset = 0x48, 103 | TypeApiType = 0x6, 104 | Il2CppTypeDefinitionApifieldStart = 0x40, 105 | MetadataRegistrationApitypes = 0x1C, 106 | }, 107 | [23] = { 108 | FieldApiOffset = 0xC, 109 | FieldApiType = 0x4, 110 | FieldApiClassOffset = 0x8, 111 | ClassApiNameOffset = 0x8, 112 | ClassApiMethodsStep = 2, 113 | ClassApiCountMethods = 0x9C, 114 | ClassApiMethodsLink = 0x40, 115 | ClassApiFieldsLink = 0x34, 116 | ClassApiFieldsStep = 0x18, 117 | ClassApiCountFields = 0xA0, 118 | ClassApiParentOffset = 0x24, 119 | ClassApiNameSpaceOffset = 0xC, 120 | ClassApiStaticFieldDataOffset = 0x50, 121 | ClassApiEnumType = 0xB1, 122 | ClassApiEnumRsh = 2, 123 | ClassApiTypeMetadataHandle = 0x2C, 124 | ClassApiInstanceSize = 0x78, 125 | ClassApiToken = 0x98, 126 | MethodsApiClassOffset = 0xC, 127 | MethodsApiNameOffset = 0x8, 128 | MethodsApiParamCount = 0x2E, 129 | MethodsApiReturnType = 0x10, 130 | MethodsApiFlags = 0x28, 131 | typeDefinitionsSize = 104, 132 | typeDefinitionsOffset = 0xA0, 133 | stringOffset = 0x18, 134 | fieldDefaultValuesOffset = 0x40, 135 | fieldDefaultValuesSize = 0x44, 136 | fieldAndParameterDefaultValueDataOffset = 0x48, 137 | TypeApiType = 0x6, 138 | Il2CppTypeDefinitionApifieldStart = 0x30, 139 | MetadataRegistrationApitypes = 0x1C, 140 | }, 141 | [24.1] = { 142 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 143 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 144 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 145 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 146 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 147 | ClassApiCountMethods = AndroidInfo.platform and 0x110 or 0xA8, 148 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 149 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 150 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 151 | ClassApiCountFields = AndroidInfo.platform and 0x114 or 0xAC, 152 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 153 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 154 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 155 | ClassApiEnumType = AndroidInfo.platform and 0x126 or 0xBE, 156 | ClassApiEnumRsh = 3, 157 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 158 | ClassApiInstanceSize = AndroidInfo.platform and 0xEC or 0x84, 159 | ClassApiToken = AndroidInfo.platform and 0x10c or 0xa4, 160 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 161 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 162 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 163 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 164 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 165 | typeDefinitionsSize = 100, 166 | typeDefinitionsOffset = 0xA0, 167 | stringOffset = 0x18, 168 | fieldDefaultValuesOffset = 0x40, 169 | fieldDefaultValuesSize = 0x44, 170 | fieldAndParameterDefaultValueDataOffset = 0x48, 171 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 172 | Il2CppTypeDefinitionApifieldStart = 0x2C, 173 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 174 | }, 175 | [24] = { 176 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 177 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 178 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 179 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 180 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 181 | ClassApiCountMethods = AndroidInfo.platform and 0x114 or 0xAC, 182 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 183 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 184 | ClassApiFieldsStep = AndroidInfo.platform and 0x28 or 0x18, 185 | ClassApiCountFields = AndroidInfo.platform and 0x118 or 0xB0, 186 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 187 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 188 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 189 | ClassApiEnumType = AndroidInfo.platform and 0x129 or 0xC1, 190 | ClassApiEnumRsh = 2, 191 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 192 | ClassApiInstanceSize = AndroidInfo.platform and 0xF0 or 0x88, 193 | ClassApiToken = AndroidInfo.platform and 0x110 or 0xa8, 194 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 195 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 196 | MethodsApiParamCount = AndroidInfo.platform and 0x4E or 0x2E, 197 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 198 | MethodsApiFlags = AndroidInfo.platform and 0x48 or 0x28, 199 | typeDefinitionsSize = 104, 200 | typeDefinitionsOffset = 0xA0, 201 | stringOffset = 0x18, 202 | fieldDefaultValuesOffset = 0x40, 203 | fieldDefaultValuesSize = 0x44, 204 | fieldAndParameterDefaultValueDataOffset = 0x48, 205 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 206 | Il2CppTypeDefinitionApifieldStart = 0x30, 207 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 208 | }, 209 | [24.2] = { 210 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 211 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 212 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 213 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 214 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 215 | ClassApiCountMethods = AndroidInfo.platform and 0x118 or 0xA4, 216 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 217 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 218 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 219 | ClassApiCountFields = AndroidInfo.platform and 0x11c or 0xA8, 220 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 221 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 222 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 223 | ClassApiEnumType = AndroidInfo.platform and 0x12e or 0xBA, 224 | ClassApiEnumRsh = 3, 225 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 226 | ClassApiInstanceSize = AndroidInfo.platform and 0xF4 or 0x80, 227 | ClassApiToken = AndroidInfo.platform and 0x114 or 0xa0, 228 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 229 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 230 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 231 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 232 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 233 | typeDefinitionsSize = 92, 234 | typeDefinitionsOffset = 0xA0, 235 | stringOffset = 0x18, 236 | fieldDefaultValuesOffset = 0x40, 237 | fieldDefaultValuesSize = 0x44, 238 | fieldAndParameterDefaultValueDataOffset = 0x48, 239 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 240 | Il2CppTypeDefinitionApifieldStart = 0x24, 241 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 242 | }, 243 | [24.3] = { 244 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 245 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 246 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 247 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 248 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 249 | ClassApiCountMethods = AndroidInfo.platform and 0x118 or 0xA4, 250 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 251 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 252 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 253 | ClassApiCountFields = AndroidInfo.platform and 0x11c or 0xA8, 254 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 255 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 256 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 257 | ClassApiEnumType = AndroidInfo.platform and 0x12e or 0xBA, 258 | ClassApiEnumRsh = 3, 259 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 260 | ClassApiInstanceSize = AndroidInfo.platform and 0xF4 or 0x80, 261 | ClassApiToken = AndroidInfo.platform and 0x114 or 0xa0, 262 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 263 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 264 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 265 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 266 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 267 | typeDefinitionsSize = 92, 268 | typeDefinitionsOffset = 0xA0, 269 | stringOffset = 0x18, 270 | fieldDefaultValuesOffset = 0x40, 271 | fieldDefaultValuesSize = 0x44, 272 | fieldAndParameterDefaultValueDataOffset = 0x48, 273 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 274 | Il2CppTypeDefinitionApifieldStart = 0x24, 275 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 276 | }, 277 | [24.4] = { 278 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 279 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 280 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 281 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 282 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 283 | ClassApiCountMethods = AndroidInfo.platform and 0x118 or 0xA4, 284 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 285 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 286 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 287 | ClassApiCountFields = AndroidInfo.platform and 0x11c or 0xA8, 288 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 289 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 290 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 291 | ClassApiEnumType = AndroidInfo.platform and 0x12e or 0xBA, 292 | ClassApiEnumRsh = 3, 293 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 294 | ClassApiInstanceSize = AndroidInfo.platform and 0xF4 or 0x80, 295 | ClassApiToken = AndroidInfo.platform and 0x114 or 0xa0, 296 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 297 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 298 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 299 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 300 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 301 | typeDefinitionsSize = 92, 302 | typeDefinitionsOffset = 0xA0, 303 | stringOffset = 0x18, 304 | fieldDefaultValuesOffset = 0x40, 305 | fieldDefaultValuesSize = 0x44, 306 | fieldAndParameterDefaultValueDataOffset = 0x48, 307 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 308 | Il2CppTypeDefinitionApifieldStart = 0x24, 309 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 310 | }, 311 | [24.5] = { 312 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 313 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 314 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 315 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 316 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 317 | ClassApiCountMethods = AndroidInfo.platform and 0x118 or 0xA4, 318 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 319 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 320 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 321 | ClassApiCountFields = AndroidInfo.platform and 0x11c or 0xA8, 322 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 323 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 324 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 325 | ClassApiEnumType = AndroidInfo.platform and 0x12e or 0xBA, 326 | ClassApiEnumRsh = 3, 327 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 328 | ClassApiInstanceSize = AndroidInfo.platform and 0xF4 or 0x80, 329 | ClassApiToken = AndroidInfo.platform and 0x114 or 0xa0, 330 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 331 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 332 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 333 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 334 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 335 | typeDefinitionsSize = 92, 336 | typeDefinitionsOffset = 0xA0, 337 | stringOffset = 0x18, 338 | fieldDefaultValuesOffset = 0x40, 339 | fieldDefaultValuesSize = 0x44, 340 | fieldAndParameterDefaultValueDataOffset = 0x48, 341 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 342 | Il2CppTypeDefinitionApifieldStart = 0x24, 343 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 344 | }, 345 | [27] = { 346 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 347 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 348 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 349 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 350 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 351 | ClassApiCountMethods = AndroidInfo.platform and 0x11C or 0xA4, 352 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 353 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 354 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 355 | ClassApiCountFields = AndroidInfo.platform and 0x120 or 0xA8, 356 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 357 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 358 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 359 | ClassApiEnumType = AndroidInfo.platform and 0x132 or 0xBA, 360 | ClassApiEnumRsh = 3, 361 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 362 | ClassApiInstanceSize = AndroidInfo.platform and 0xF8 or 0x80, 363 | ClassApiToken = AndroidInfo.platform and 0x118 or 0xa0, 364 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 365 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 366 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 367 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 368 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 369 | typeDefinitionsSize = 88, 370 | typeDefinitionsOffset = 0xA0, 371 | stringOffset = 0x18, 372 | fieldDefaultValuesOffset = 0x40, 373 | fieldDefaultValuesSize = 0x44, 374 | fieldAndParameterDefaultValueDataOffset = 0x48, 375 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 376 | Il2CppTypeDefinitionApifieldStart = 0x20, 377 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 378 | }, 379 | [27.1] = { 380 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 381 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 382 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 383 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 384 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 385 | ClassApiCountMethods = AndroidInfo.platform and 0x11C or 0xA4, 386 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 387 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 388 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 389 | ClassApiCountFields = AndroidInfo.platform and 0x120 or 0xA8, 390 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 391 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 392 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 393 | ClassApiEnumType = AndroidInfo.platform and 0x132 or 0xBA, 394 | ClassApiEnumRsh = 3, 395 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 396 | ClassApiInstanceSize = AndroidInfo.platform and 0xF8 or 0x80, 397 | ClassApiToken = AndroidInfo.platform and 0x118 or 0xa0, 398 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 399 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 400 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 401 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 402 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 403 | typeDefinitionsSize = 88, 404 | typeDefinitionsOffset = 0xA0, 405 | stringOffset = 0x18, 406 | fieldDefaultValuesOffset = 0x40, 407 | fieldDefaultValuesSize = 0x44, 408 | fieldAndParameterDefaultValueDataOffset = 0x48, 409 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 410 | Il2CppTypeDefinitionApifieldStart = 0x20, 411 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 412 | }, 413 | [27.2] = { 414 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 415 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 416 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 417 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 418 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 419 | ClassApiCountMethods = AndroidInfo.platform and 0x11C or 0xA4, 420 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 421 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 422 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 423 | ClassApiCountFields = AndroidInfo.platform and 0x120 or 0xA8, 424 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 425 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 426 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 427 | ClassApiEnumType = AndroidInfo.platform and 0x132 or 0xBA, 428 | ClassApiEnumRsh = 2, 429 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 430 | ClassApiInstanceSize = AndroidInfo.platform and 0xF8 or 0x80, 431 | ClassApiToken = AndroidInfo.platform and 0x118 or 0xa0, 432 | MethodsApiClassOffset = AndroidInfo.platform and 0x18 or 0xC, 433 | MethodsApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 434 | MethodsApiParamCount = AndroidInfo.platform and 0x4A or 0x2A, 435 | MethodsApiReturnType = AndroidInfo.platform and 0x20 or 0x10, 436 | MethodsApiFlags = AndroidInfo.platform and 0x44 or 0x24, 437 | typeDefinitionsSize = 88, 438 | typeDefinitionsOffset = 0xA0, 439 | stringOffset = 0x18, 440 | fieldDefaultValuesOffset = 0x40, 441 | fieldDefaultValuesSize = 0x44, 442 | fieldAndParameterDefaultValueDataOffset = 0x48, 443 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 444 | Il2CppTypeDefinitionApifieldStart = 0x20, 445 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 446 | }, 447 | [29] = { 448 | FieldApiOffset = AndroidInfo.platform and 0x18 or 0xC, 449 | FieldApiType = AndroidInfo.platform and 0x8 or 0x4, 450 | FieldApiClassOffset = AndroidInfo.platform and 0x10 or 0x8, 451 | ClassApiNameOffset = AndroidInfo.platform and 0x10 or 0x8, 452 | ClassApiMethodsStep = AndroidInfo.platform and 3 or 2, 453 | ClassApiCountMethods = AndroidInfo.platform and 0x11C or 0xA4, 454 | ClassApiMethodsLink = AndroidInfo.platform and 0x98 or 0x4C, 455 | ClassApiFieldsLink = AndroidInfo.platform and 0x80 or 0x40, 456 | ClassApiFieldsStep = AndroidInfo.platform and 0x20 or 0x14, 457 | ClassApiCountFields = AndroidInfo.platform and 0x120 or 0xA8, 458 | ClassApiParentOffset = AndroidInfo.platform and 0x58 or 0x2C, 459 | ClassApiNameSpaceOffset = AndroidInfo.platform and 0x18 or 0xC, 460 | ClassApiStaticFieldDataOffset = AndroidInfo.platform and 0xB8 or 0x5C, 461 | ClassApiEnumType = AndroidInfo.platform and 0x132 or 0xBA, 462 | ClassApiEnumRsh = 2, 463 | ClassApiTypeMetadataHandle = AndroidInfo.platform and 0x68 or 0x34, 464 | ClassApiInstanceSize = AndroidInfo.platform and 0xF8 or 0x80, 465 | ClassApiToken = AndroidInfo.platform and 0x118 or 0xa0, 466 | MethodsApiClassOffset = AndroidInfo.platform and 0x20 or 0x10, 467 | MethodsApiNameOffset = AndroidInfo.platform and 0x18 or 0xC, 468 | MethodsApiParamCount = AndroidInfo.platform and 0x52 or 0x2E, 469 | MethodsApiReturnType = AndroidInfo.platform and 0x28 or 0x14, 470 | MethodsApiFlags = AndroidInfo.platform and 0x4C or 0x28, 471 | typeDefinitionsSize = 88, 472 | typeDefinitionsOffset = 0xA0, 473 | stringOffset = 0x18, 474 | fieldDefaultValuesOffset = 0x40, 475 | fieldDefaultValuesSize = 0x44, 476 | fieldAndParameterDefaultValueDataOffset = 0x48, 477 | TypeApiType = AndroidInfo.platform and 0xA or 0x6, 478 | Il2CppTypeDefinitionApifieldStart = 0x20, 479 | MetadataRegistrationApitypes = AndroidInfo.platform and 0x38 or 0x1C, 480 | } 481 | } 482 | 483 | 484 | ---@class Il2CppFlags 485 | ---@field Method MethodFlags 486 | ---@field Field FieldFlags 487 | Il2CppFlags = { 488 | Method = { 489 | METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK = 0x0007, 490 | Access = { 491 | "private", -- METHOD_ATTRIBUTE_PRIVATE 492 | "internal", -- METHOD_ATTRIBUTE_FAM_AND_ASSEM 493 | "internal", -- METHOD_ATTRIBUTE_ASSEM 494 | "protected", -- METHOD_ATTRIBUTE_FAMILY 495 | "protected internal", -- METHOD_ATTRIBUTE_FAM_OR_ASSEM 496 | "public", -- METHOD_ATTRIBUTE_PUBLIC 497 | }, 498 | METHOD_ATTRIBUTE_STATIC = 0x0010, 499 | METHOD_ATTRIBUTE_ABSTRACT = 0x0400, 500 | }, 501 | Field = { 502 | FIELD_ATTRIBUTE_FIELD_ACCESS_MASK = 0x0007, 503 | Access = { 504 | "private", -- FIELD_ATTRIBUTE_PRIVATE 505 | "internal", -- FIELD_ATTRIBUTE_FAM_AND_ASSEM 506 | "internal", -- FIELD_ATTRIBUTE_ASSEMBLY 507 | "protected", -- FIELD_ATTRIBUTE_FAMILY 508 | "protected internal", -- FIELD_ATTRIBUTE_FAM_OR_ASSEM 509 | "public", -- FIELD_ATTRIBUTE_PUBLIC 510 | }, 511 | FIELD_ATTRIBUTE_STATIC = 0x0010, 512 | FIELD_ATTRIBUTE_LITERAL = 0x0040, 513 | } 514 | } -------------------------------------------------------------------------------- /utils/il2cppmemory.lua: -------------------------------------------------------------------------------- 1 | -- Memorizing Il2cpp Search Result 2 | ---@class Il2cppMemory 3 | ---@field Methods table 4 | ---@field Classes table 5 | ---@field Fields table 6 | ---@field Results table 7 | ---@field Types table 8 | ---@field DefaultValues table 9 | ---@field GetInformaionOfMethod fun(self : Il2cppMemory, searchParam : number | string) : MethodMemory | nil 10 | ---@field SetInformaionOfMethod fun(self : Il2cppMemory, searchParam : string | number, searchResult : MethodMemory) : void 11 | ---@field GetInformationOfClass fun(self : Il2cppMemory, searchParam : string | number) : ClassMemory | nil 12 | ---@field SetInformationOfClass fun(self : Il2cppMemory, searchParam : string | number, searchResult : ClassMemory) : void 13 | ---@field GetInformationOfField fun(self : Il2cppMemory, searchParam : number | string) : FieldInfo[] | nil | ErrorSearch 14 | ---@field SetInformationOfField fun(self : Il2cppMemory, searchParam : string | number, searchResult : FieldInfo[] | ErrorSearch) : void 15 | ---@field GetInformationOfType fun(self : Il2cppMemory, index : number) : string | nil 16 | ---@field SetInformationOfType fun(self : Il2cppMemory, index : number, typeName : string) 17 | ---@field SaveResults fun(self : Il2cppMemory) : void 18 | ---@field ClearSavedResults fun(self : Il2cppMemory) : void 19 | local Il2cppMemory = { 20 | Methods = {}, 21 | Classes = {}, 22 | Fields = {}, 23 | DefaultValues = {}, 24 | Results = {}, 25 | Types = {}, 26 | 27 | 28 | ---@param self Il2cppMemory 29 | ---@return nil | string 30 | GetInformationOfType = function(self, index) 31 | return self.Types[index] 32 | end, 33 | 34 | 35 | ---@param self Il2cppMemory 36 | SetInformationOfType = function(self, index, typeName) 37 | self.Types[index] = typeName 38 | end, 39 | 40 | ---@param self Il2cppMemory 41 | SaveResults = function(self) 42 | if gg.getResultsCount() > 0 then 43 | self.Results = gg.getResults(gg.getResultsCount()) 44 | end 45 | end, 46 | 47 | 48 | ---@param self Il2cppMemory 49 | ClearSavedResults = function(self) 50 | self.Results = {} 51 | end, 52 | 53 | 54 | ---@param self Il2cppMemory 55 | ---@param fieldIndex number 56 | ---@return string | number | nil 57 | GetDefaultValue = function(self, fieldIndex) 58 | return self.DefaultValues[fieldIndex] 59 | end, 60 | 61 | 62 | ---@param self Il2cppMemory 63 | ---@param fieldIndex number 64 | ---@param defaultValue number | string | nil 65 | SetDefaultValue = function(self, fieldIndex, defaultValue) 66 | self.DefaultValues[fieldIndex] = defaultValue or "nil" 67 | end, 68 | 69 | 70 | ---@param self Il2cppMemory 71 | ---@param searchParam number | string 72 | ---@return FieldInfo[] | nil | ErrorSearch 73 | GetInformationOfField = function(self, searchParam) 74 | return self.Fields[searchParam] 75 | end, 76 | 77 | 78 | ---@param self Il2cppMemory 79 | ---@param searchParam number | string 80 | ---@param searchResult FieldInfo[] | ErrorSearch 81 | SetInformationOfField = function(self, searchParam, searchResult) 82 | if not searchResult.Error then 83 | self.Fields[searchParam] = searchResult 84 | end 85 | end, 86 | 87 | 88 | GetInformaionOfMethod = function(self, searchParam) 89 | return self.Methods[searchParam] 90 | end, 91 | 92 | 93 | SetInformaionOfMethod = function(self, searchParam, searchResult) 94 | if not searchResult.Error then 95 | self.Methods[searchParam] = searchResult 96 | end 97 | end, 98 | 99 | 100 | GetInformationOfClass = function(self, searchParam) 101 | return self.Classes[searchParam] 102 | end, 103 | 104 | 105 | SetInformationOfClass = function(self, searchParam, searchResult) 106 | self.Classes[searchParam] = searchResult 107 | end, 108 | 109 | 110 | ---@param self Il2cppMemory 111 | ---@return void 112 | ClearMemorize = function(self) 113 | self.Methods = {} 114 | self.Classes = {} 115 | self.Fields = {} 116 | self.DefaultValues = {} 117 | self.Results = {} 118 | self.Types = {} 119 | end 120 | } 121 | 122 | return Il2cppMemory 123 | -------------------------------------------------------------------------------- /utils/malloc.lua: -------------------------------------------------------------------------------- 1 | local MemoryManager = { 2 | availableMemory = 0, 3 | lastAddress = 0, 4 | 5 | NewAlloc = function(self) 6 | self.lastAddress = gg.allocatePage(gg.PROT_READ | gg.PROT_WRITE) 7 | self.availableMemory = 4096 8 | end, 9 | } 10 | 11 | local M = { 12 | ---@param size number 13 | MAlloc = function(size) 14 | local manager = MemoryManager 15 | if size > manager.availableMemory then 16 | manager:NewAlloc() 17 | end 18 | local address = manager.lastAddress 19 | manager.availableMemory = manager.availableMemory - size 20 | manager.lastAddress = manager.lastAddress + size 21 | return address 22 | end, 23 | } 24 | 25 | return M -------------------------------------------------------------------------------- /utils/patchapi.lua: -------------------------------------------------------------------------------- 1 | ---@class Patch 2 | ---@field oldBytes table 3 | ---@field newBytes table 4 | ---@field Create fun(self : Patch, patchCode : table) : Patch 5 | ---@field Patch fun(self : Patch) : void 6 | ---@field Undo fun(self : Patch) : void 7 | local PatchApi = { 8 | 9 | ---@param self Patch 10 | ---@param patchCode table 11 | Create = function(self, patchCode) 12 | return setmetatable({ 13 | newBytes = patchCode, 14 | oldBytes = gg.getValues(patchCode) 15 | }, 16 | { 17 | __index = self, 18 | }) 19 | end, 20 | 21 | ---@param self Patch 22 | Patch = function(self) 23 | if self.newBytes then 24 | gg.setValues(self.newBytes) 25 | end 26 | end, 27 | 28 | ---@param self Patch 29 | Undo = function(self) 30 | if self.oldBytes then 31 | gg.setValues(self.oldBytes) 32 | end 33 | end, 34 | } 35 | 36 | return PatchApi -------------------------------------------------------------------------------- /utils/protect.lua: -------------------------------------------------------------------------------- 1 | local Protect = { 2 | ErrorHandler = function(err) 3 | return {Error = err} 4 | end, 5 | Call = function(self, fun, ...) 6 | return ({xpcall(fun, self.ErrorHandler, ...)})[2] 7 | end 8 | } 9 | 10 | return Protect -------------------------------------------------------------------------------- /utils/stringutils.lua: -------------------------------------------------------------------------------- 1 | ---@class StringUtils 2 | local StringUtils = { 3 | 4 | ---@param classInfo ClassInfo 5 | ClassInfoToDumpCS = function(classInfo) 6 | local dumpClass = { 7 | "// ", classInfo.ImageName, "\n", 8 | "// Namespace: ", classInfo.ClassNameSpace, "\n"; 9 | 10 | "class ", classInfo.ClassName, classInfo.Parent and " : " .. classInfo.Parent.ClassName or "", "\n", 11 | "{\n" 12 | } 13 | 14 | if classInfo.Fields and #classInfo.Fields > 0 then 15 | dumpClass[#dumpClass + 1] = "\n\t// Fields\n" 16 | for i, v in ipairs(classInfo.Fields) do 17 | local dumpField = { 18 | "\t", v.Access, " ", v.IsStatic and "static " or "", v.IsConst and "const " or "", v.Type, " ", v.FieldName, "; // 0x", v.Offset, "\n" 19 | } 20 | table.move(dumpField, 1, #dumpField, #dumpClass + 1, dumpClass) 21 | end 22 | end 23 | 24 | if classInfo.Methods and #classInfo.Methods > 0 then 25 | dumpClass[#dumpClass + 1] = "\n\t// Methods\n" 26 | for i, v in ipairs(classInfo.Methods) do 27 | local dumpMethod = { 28 | i == 1 and "" or "\n", 29 | "\t// Offset: 0x", v.Offset, " VA: 0x", v.AddressInMemory, " ParamCount: ", v.ParamCount, "\n", 30 | "\t", v.Access, " ", v.IsStatic and "static " or "", v.IsAbstract and "abstract " or "", v.ReturnType, " ", v.MethodName, "() { } \n" 31 | } 32 | table.move(dumpMethod, 1, #dumpMethod, #dumpClass + 1, dumpClass) 33 | end 34 | end 35 | 36 | table.insert(dumpClass, "\n}\n") 37 | return table.concat(dumpClass) 38 | end 39 | } 40 | 41 | return StringUtils -------------------------------------------------------------------------------- /utils/universalsearcher.lua: -------------------------------------------------------------------------------- 1 | local AndroidInfo = require("utils.androidinfo") 2 | 3 | ---@class Searcher 4 | local Searcher = { 5 | searchWord = ":EnsureCapacity", 6 | 7 | ---@param self Searcher 8 | FindGlobalMetaData = function(self) 9 | gg.clearResults() 10 | gg.setRanges(gg.REGION_C_HEAP | gg.REGION_C_ALLOC | gg.REGION_ANONYMOUS | gg.REGION_C_BSS | gg.REGION_C_DATA | 11 | gg.REGION_OTHER) 12 | local globalMetadata = gg.getRangesList('global-metadata.dat') 13 | if not self:IsValidData(globalMetadata) then 14 | globalMetadata = {} 15 | gg.clearResults() 16 | gg.searchNumber(self.searchWord, gg.TYPE_BYTE) 17 | gg.refineNumber(self.searchWord:sub(1, 2), gg.TYPE_BYTE) 18 | local EnsureCapacity = gg.getResults(gg.getResultsCount()) 19 | gg.clearResults() 20 | for k, v in ipairs(gg.getRangesList()) do 21 | if (v.state == 'Ca' or v.state == 'A' or v.state == 'Cd' or v.state == 'Cb' or v.state == 'Ch' or 22 | v.state == 'O') then 23 | for key, val in ipairs(EnsureCapacity) do 24 | globalMetadata[#globalMetadata + 1] = 25 | (Il2cpp.FixValue(v.start) <= Il2cpp.FixValue(val.address) and Il2cpp.FixValue(val.address) < 26 | Il2cpp.FixValue(v['end'])) and v or nil 27 | end 28 | end 29 | end 30 | end 31 | return globalMetadata[1].start, globalMetadata[#globalMetadata]['end'] 32 | end, 33 | 34 | ---@param self Searcher 35 | IsValidData = function(self, globalMetadata) 36 | if #globalMetadata ~= 0 then 37 | gg.searchNumber(self.searchWord, gg.TYPE_BYTE, false, gg.SIGN_EQUAL, globalMetadata[1].start, 38 | globalMetadata[#globalMetadata]['end']) 39 | if gg.getResultsCount() > 0 then 40 | gg.clearResults() 41 | return true 42 | end 43 | end 44 | return false 45 | end, 46 | 47 | FindIl2cpp = function() 48 | local il2cpp = gg.getRangesList('libil2cpp.so') 49 | if #il2cpp == 0 then 50 | il2cpp = gg.getRangesList('split_config.') 51 | local _il2cpp = {} 52 | gg.setRanges(gg.REGION_CODE_APP) 53 | for k, v in ipairs(il2cpp) do 54 | if (v.state == 'Xa') then 55 | gg.searchNumber(':il2cpp', gg.TYPE_BYTE, false, gg.SIGN_EQUAL, v.start, v['end']) 56 | if (gg.getResultsCount() > 0) then 57 | _il2cpp[#_il2cpp + 1] = v 58 | gg.clearResults() 59 | end 60 | end 61 | end 62 | il2cpp = _il2cpp 63 | else 64 | local _il2cpp = {} 65 | for k,v in ipairs(il2cpp) do 66 | if (string.find(v.type, "..x.") or v.state == "Xa") then 67 | _il2cpp[#_il2cpp + 1] = v 68 | end 69 | end 70 | il2cpp = _il2cpp 71 | end 72 | return il2cpp[1].start, il2cpp[#il2cpp]['end'] 73 | end, 74 | 75 | Il2CppMetadataRegistration = function() 76 | gg.clearResults() 77 | gg.setRanges(gg.REGION_C_HEAP | gg.REGION_C_ALLOC | gg.REGION_ANONYMOUS | gg.REGION_C_BSS | gg.REGION_C_DATA | 78 | gg.REGION_OTHER) 79 | gg.loadResults({{ 80 | address = Il2cpp.globalMetadataStart, 81 | flags = Il2cpp.MainType 82 | }}) 83 | gg.searchPointer(0) 84 | if gg.getResultsCount() == 0 and AndroidInfo.platform and AndroidInfo.sdk >= 30 then 85 | gg.searchNumber(tostring(Il2cpp.globalMetadataStart | 0xB400000000000000), Il2cpp.MainType) 86 | end 87 | if gg.getResultsCount() > 0 then 88 | local GlobalMetadataPointers, s_GlobalMetadata = gg.getResults(gg.getResultsCount()), 0 89 | for i = 1, #GlobalMetadataPointers do 90 | if i ~= 1 then 91 | local difference = GlobalMetadataPointers[i].address - GlobalMetadataPointers[i - 1].address 92 | if (difference == Il2cpp.pointSize) then 93 | s_GlobalMetadata = Il2cpp.FixValue(gg.getValues({{ 94 | address = GlobalMetadataPointers[i].address - (AndroidInfo.platform and 0x10 or 0x8), 95 | flags = Il2cpp.MainType 96 | }})[1].value) 97 | end 98 | end 99 | end 100 | return s_GlobalMetadata 101 | end 102 | return 0 103 | end 104 | } 105 | 106 | return Searcher 107 | -------------------------------------------------------------------------------- /utils/version.lua: -------------------------------------------------------------------------------- 1 | local semver = require("semver.semver") 2 | 3 | ---@class VersionEngine 4 | local VersionEngine = { 5 | ConstSemVer = { 6 | ['2018_3'] = semver(2018, 3), 7 | ['2019_4_21'] = semver(2019, 4, 21), 8 | ['2019_4_15'] = semver(2019, 4, 15), 9 | ['2019_3_7'] = semver(2019, 3, 7), 10 | ['2020_2_4'] = semver(2020, 2, 4), 11 | ['2020_2'] = semver(2020, 2), 12 | ['2020_1_11'] = semver(2020, 1, 11), 13 | ['2021_2'] = semver(2021, 2) 14 | }, 15 | Year = { 16 | [2017] = function(self, unityVersion) 17 | return 24 18 | end, 19 | ---@param self VersionEngine 20 | [2018] = function(self, unityVersion) 21 | return (not (unityVersion < self.ConstSemVer['2018_3'])) and 24.1 or 24 22 | end, 23 | ---@param self VersionEngine 24 | [2019] = function(self, unityVersion) 25 | local version = 24.2 26 | if not (unityVersion < self.ConstSemVer['2019_4_21']) then 27 | version = 24.5 28 | elseif not (unityVersion < self.ConstSemVer['2019_4_15']) then 29 | version = 24.4 30 | elseif not (unityVersion < self.ConstSemVer['2019_3_7']) then 31 | version = 24.3 32 | end 33 | return version 34 | end, 35 | ---@param self VersionEngine 36 | [2020] = function(self, unityVersion) 37 | local version = 24.3 38 | if not (unityVersion < self.ConstSemVer['2020_2_4']) then 39 | version = 27.1 40 | elseif not (unityVersion < self.ConstSemVer['2020_2']) then 41 | version = 27 42 | elseif not (unityVersion < self.ConstSemVer['2020_1_11']) then 43 | version = 24.4 44 | end 45 | return version 46 | end, 47 | ---@param self VersionEngine 48 | [2021] = function(self, unityVersion) 49 | return (not (unityVersion < self.ConstSemVer['2021_2'])) and 29 or 27.2 50 | end, 51 | [2022] = function(self, unityVersion) 52 | return 29 53 | end, 54 | }, 55 | ---@return number 56 | GetUnityVersion = function() 57 | gg.setRanges(gg.REGION_ANONYMOUS) 58 | gg.clearResults() 59 | gg.searchNumber("00h;32h;30h;0~~0;0~~0;2Eh;0~~0;2Eh::9", gg.TYPE_BYTE, false, gg.SIGN_EQUAL, nil, nil, 1) 60 | local result = gg.getResultsCount() > 0 and gg.getResults(3)[3].address or 0 61 | gg.clearResults() 62 | return result 63 | end, 64 | ReadUnityVersion = function(versionAddress) 65 | local verisonName = Il2cpp.Utf8ToString(versionAddress) 66 | return string.gmatch(verisonName, "(%d+)%p(%d+)%p(%d+)")() 67 | end, 68 | ---@param self VersionEngine 69 | ---@param version? number 70 | ChooseVersion = function(self, version, globalMetadataHeader) 71 | if not version then 72 | local unityVersionAddress = self.GetUnityVersion() 73 | if unityVersionAddress == 0 then 74 | version = gg.getValues({{address = globalMetadataHeader + 0x4, flags = gg.TYPE_DWORD}})[1].value 75 | else 76 | local p1, p2, p3 = self.ReadUnityVersion(unityVersionAddress) 77 | local unityVersion = semver(tonumber(p1), tonumber(p2), tonumber(p3)) 78 | ---@type number | fun(self: VersionEngine, unityVersion: table): number 79 | version = self.Year[unityVersion.major] or 29 80 | if type(version) == 'function' then 81 | version = version(self, unityVersion) 82 | end 83 | end 84 | 85 | end 86 | ---@type Il2cppApi 87 | local api = assert(Il2CppConst[version], 'Not support this il2cpp version') 88 | Il2cpp.FieldApi.Offset = api.FieldApiOffset 89 | Il2cpp.FieldApi.Type = api.FieldApiType 90 | Il2cpp.FieldApi.ClassOffset = api.FieldApiClassOffset 91 | 92 | Il2cpp.ClassApi.NameOffset = api.ClassApiNameOffset 93 | Il2cpp.ClassApi.MethodsStep = api.ClassApiMethodsStep 94 | Il2cpp.ClassApi.CountMethods = api.ClassApiCountMethods 95 | Il2cpp.ClassApi.MethodsLink = api.ClassApiMethodsLink 96 | Il2cpp.ClassApi.FieldsLink = api.ClassApiFieldsLink 97 | Il2cpp.ClassApi.FieldsStep = api.ClassApiFieldsStep 98 | Il2cpp.ClassApi.CountFields = api.ClassApiCountFields 99 | Il2cpp.ClassApi.ParentOffset = api.ClassApiParentOffset 100 | Il2cpp.ClassApi.NameSpaceOffset = api.ClassApiNameSpaceOffset 101 | Il2cpp.ClassApi.StaticFieldDataOffset = api.ClassApiStaticFieldDataOffset 102 | Il2cpp.ClassApi.EnumType = api.ClassApiEnumType 103 | Il2cpp.ClassApi.EnumRsh = api.ClassApiEnumRsh 104 | Il2cpp.ClassApi.TypeMetadataHandle = api.ClassApiTypeMetadataHandle 105 | Il2cpp.ClassApi.InstanceSize = api.ClassApiInstanceSize 106 | Il2cpp.ClassApi.Token = api.ClassApiToken 107 | 108 | Il2cpp.MethodsApi.ClassOffset = api.MethodsApiClassOffset 109 | Il2cpp.MethodsApi.NameOffset = api.MethodsApiNameOffset 110 | Il2cpp.MethodsApi.ParamCount = api.MethodsApiParamCount 111 | Il2cpp.MethodsApi.ReturnType = api.MethodsApiReturnType 112 | Il2cpp.MethodsApi.Flags = api.MethodsApiFlags 113 | 114 | Il2cpp.GlobalMetadataApi.typeDefinitionsSize = api.typeDefinitionsSize 115 | Il2cpp.GlobalMetadataApi.version = version 116 | 117 | local consts = gg.getValues({ 118 | { -- [1] 119 | address = Il2cpp.globalMetadataHeader + api.typeDefinitionsOffset, 120 | flags = gg.TYPE_DWORD 121 | }, 122 | { -- [2] 123 | address = Il2cpp.globalMetadataHeader + api.stringOffset, 124 | flags = gg.TYPE_DWORD, 125 | }, 126 | { -- [3] 127 | address = Il2cpp.globalMetadataHeader + api.fieldDefaultValuesOffset, 128 | flags = gg.TYPE_DWORD, 129 | }, 130 | { -- [4] 131 | address = Il2cpp.globalMetadataHeader + api.fieldDefaultValuesSize, 132 | flags = gg.TYPE_DWORD 133 | }, 134 | { -- [5] 135 | address = Il2cpp.globalMetadataHeader + api.fieldAndParameterDefaultValueDataOffset, 136 | flags = gg.TYPE_DWORD 137 | } 138 | }) 139 | Il2cpp.GlobalMetadataApi.typeDefinitionsOffset = consts[1].value 140 | Il2cpp.GlobalMetadataApi.stringOffset = consts[2].value 141 | Il2cpp.GlobalMetadataApi.fieldDefaultValuesOffset = consts[3].value 142 | Il2cpp.GlobalMetadataApi.fieldDefaultValuesSize = consts[4].value 143 | Il2cpp.GlobalMetadataApi.fieldAndParameterDefaultValueDataOffset = consts[5].value 144 | 145 | Il2cpp.TypeApi.Type = api.TypeApiType 146 | 147 | Il2cpp.Il2CppTypeDefinitionApi.fieldStart = api.Il2CppTypeDefinitionApifieldStart 148 | 149 | Il2cpp.MetadataRegistrationApi.types = api.MetadataRegistrationApitypes 150 | end, 151 | } 152 | 153 | return VersionEngine --------------------------------------------------------------------------------