Il2CppExplorer is a library for Game Guardian scripts which is designed to make script creation for games built with Unity easier. To get function and class names and more get Il2CppDumper
Add this code to start of your script:
--With simple integrity check
--Don't change the path, so other scripts using framework can access it too
function init()
local file = io.open(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua', 'r')
if file == nil then
response = gg.makeRequest('https://github.com/HTCheater/Il2CppExplorer/releases/latest/download/Il2CppExplorer.lua')
if response.code ~= 200 then
print('Check internet connection')
os.exit()
end
file = io.open(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua', 'w')
file:write(response.content)
else
checksumResponse = gg.makeRequest('https://github.com/HTCheater/Il2CppExplorer/releases/latest/download/Il2CppExplorer.checksum')
if checksumResponse.code ~= 200 then
print('Check internet connection')
os.exit()
end
file:close()
file = io.open(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua', 'rb')
local size = file:seek('end')
local checksum = 0
file:seek('set', 0)
while file:seek() < size do
checksum = checksum + file:read(1):byte()
end
if (checksumResponse.content ~= tostring(checksum)) then
os.remove(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua')
init()
end
end
file:close()
framework = loadfile(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua')
framework()
end
init()
or use this if you don't want to check script integrity and recieve updates
--Without simple integrity check
--Don't change the path, so other scripts using framework can access it too
function init()
local file = io.open(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua', 'r')
if file == nil then
response = gg.makeRequest('https://github.com/HTCheater/Il2CppExplorer/releases/latest/download/Il2CppExplorer.lua')
if response.code ~= 200 then
print('Check internet connection')
os.exit()
end
file = io.open(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua', 'w')
file:write(response.content)
end
file:close()
framework = loadfile(gg.EXT_FILES_DIR .. '/Il2CppExplorer.lua')
framework()
end
init()
Control debug messages output, recommended to set value to true if you make script.
Default value is false
Let user know what are you using :D. You need to set value before running the framework.
Default value is true
Exit if selected process isn't a Unity game, it isn't recommended to change. You need to set value before running framework
Default value is true
Set maximum string length to read
Default value is 1000
Find instances of class.
Returns a table with search results
Parameters:
1st parameter is a string
Example:
explorer.getInstances('RGHand')
Get field's value
Parameters:
1st parameter is an element from explorer.getInstances table
2nd parameter is offset for 64-bit architecture
3rd parameter is offset for 32-bit architecture
4th parameter is one of gg.TYPE_*
Example:
explorer.getField(explorer.getInstances('RGHand')[1], 0x10, 0x8, gg.TYPE_DWORD)
Edit field's value
Parameters:
1st parameter is an element from explorer.getInstances table
2nd parameter is offset for 64-bit architecture
3rd parameter is offset for 32-bit architecture
4th parameter is one of gg.TYPE_*
5th parameter is value to set
Example:
explorer.editField(explorer.getInstances('RGHand')[1], 0x10, 0x8, gg.TYPE_DWORD, 99999)
Get start address of libil2cpp.so. Returns 0 if explorer.getLib wasn't called or library isn't loaded
Edit assembly of function. You should specify className to prevent finding functions with the same name. Target class must be loaded in memory to find offset (e. g. you are in menu, so you need to enter game at first place to modificate functions related to heal points ). If 1st parameter is nil, class name will be ignored (can boost search speed)
You can put nil in 3rd or 4th parameter if you don't want to specify information for some architecture.
patchedBytes is a table that can contain either numbers or strings with opcodes or strings with hex (must start with h)
Parameters:
1st parameter is name of class
2nd parameter is name of function located in the classs
3rd parameter is values table for 64-bit architecture
4th parameter is values table for 32-bit architecture
Example:
explorer.editFunction(nil, 'get_hp', {'MOV X0, #99999', 'RET'})
Get function offset in il2cpp.so. You should specify className to prevent finding functions with the same name. Target class must be loaded in memory to find offset (e. g. you are in menu, so you need to enter game at first place to modificate functions related to heal points ). If 1st parameter is nil, class name will be ignored (can boost search speed)
Parameters:
1st parameter is name of class
2nd parameter is name of function located in the classs
3rd parameter is values table for 64-bit architecture
4th parameter is values table for 32-bit architecture
Example:
local off = explorer.getFunction(nil, 'get_hp')
print('get_hp offset: ' .. string.format('%X', off))
CONSIDER USING explorer.editFunction! This function shouldn't be used in your script
Edit assembly in libil2cpp.so.
Put nil if you don't want to specify information for some architecture.
patchedBytes is a table that can contain either numbers or strings with opcodes or hex (must start with h)
Parameters:
1st parameter is offset for 64-bit architecture
2nd parameter is offset for 32-bit architecture
3rd parameter is values table for 64-bit architecture
4th parameter is values table for 32-bit architecture
Example:
explorer.patchLib(0x19CFDA, 0x9DFCA, {'RET'}, {'h1EFF2FE1'})
explorer.patchLib(0x19CFDA, nil, {-698416192})
Run if you need explorer.getLibStart before you called either explorer.editFunction or explorer.patchLib
Read string at desired address. If string length is too large, returns empty string. You can modify maximum length in explorer.maxStringLength field. If you want to read non-ASCII characters, you should check out explorer.setAlphabet
Parameters:
1st parameter is a pointer to String instance
Example:
local isx64 = gg.getTargetInfo().x64
local ptrLength = isx64 and gg.TYPE_QWORD or gg.TYPE_DWORD
local instances = explorer.getInstances('ClassWithStringField')
local ptr = explorer.getField(instances[1], 0x10, 0x8, ptrLength)
local str = explorer.readString(ptr)
print(str)
To read read non-ASCII characters you need to call this function.
Parameters:
1st parameter is a string with all needed characters
Example:
local isx64 = gg.getTargetInfo().x64
local ptrLength = isx64 and gg.TYPE_QWORD or gg.TYPE_DWORD
local instances = explorer.getInstances('ClassWithStringField')
local ptr = explorer.getField(instances[1], 0x10, 0x8, ptrLength)
--attemp to read string "бамбетель" without setting alphabet
--if explorer.debug is true, you will get warnings with missing UTF-16LE character codes
local str = explorer.readString(ptr)
print(str) --result is an empty string
explorer.setAlphabet('АаБбВвГ㥴ДдЕеЄєЖжЗзИиІіЇїЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщьЮюЯя') --ASCII characters included automatically
--attemp to read "бамбетель" after setting alphabet
str = explorer.readString(ptr)
print(str) --result is "бамбетель"
Pull requests are welcome.