Hacking and reverse engineering il2cpp games with ghidra
Last writeup, we talk about how to hack unity games compiled on mono. This time, we will be hacking unity games compiled in il2cpp. IL2CPP is a Unity3d technology for converting C# code to C++ code and from there native compilation for a particular platform. Unlike mono, it is harder to decompile games in il2cpp since they are compiled to machine code. It is harder to hack than mono but it is still fairly simple. For this writeup, we will be using again a demo game i made. You can download it in https://noobexploiter.itch.io/slightly-modified.
When unity games are compiled to il2cpp, its metadata are stored in
\il2cpp_data\Metadata . This is what allows hackers to easily reverse engineer these games. To start, download il2cppdumper and dump the game’s GameAssembly.dll file.
It will generate multiple files. One of those files is il2cpp.h, we can include this header file when making our own hacks to aid us. We can also include these header files to ghidra to add its datatypes to ghidra. But we cant, due to a bug. https://github.com/Perfare/Il2CppDumper/pull/538 . But, fortunately for us, il2cppdumper provided us a script, to make this header file compatible with ghidra. The script is called
il2cpp_header_to_ghidra.py. Run the python script on the same directory of the header file and it will make a new header file called
il2cpp_ghidra.h,which we can then use to ghidra.
Reverse engineering with ghidra
To start reverse engineering, open up ghidra and load the original
gameassembly.dll in to it. Then, import the
il2cpp_ghidra.h by going to File>Parse C Code and add the
il2cpp_ghidra.h . Next, we need to run a script given to us by il2cppdumper called
ghidra_with_struct.py . Click on the script tab, add the directory of il2cppdumper to your script directories and run the ghidra_with_struct script. In there, select the script.json file generated by il2cppdumper.
When done right, you should now have detailed data types and functions in your ghidra.
While looking through the functions, i found one interesting function called
It takes a Health object as an argument, and it will set the CurrentHealth_k__BackingField field of the Health Object to 0.0 which i assume is the current Health of the object. It will also invoke the OnDamaged function stored in the OnDamaged Field. So this function do as what it sounds like, it will kill the object.
While reversing the EnemyController class, i found out that it has a health field called m_Health which i assume handles the Health of the Enemy Object
So if we call the Kill function on the Health field of the enemyobject, we should be able to kill that enemy object.
In the start function of EnemyController Class, it get the Health component of the object and pass it to the m_health field. This suggests that the EnemyController has a health component.
Making A Hack
Now lets make a real hack from the data that we collected. Like i said earlier, we can include the il2cpp.h header file to our hack. On my case, the header file doesnt work by default, since custom data types like int32_t are not recognized. It can be fixed by adding
#include <stdint.h> at the top of the header file.
In this hack, i hooked the update function of enemycontroller class.
This function is called on every frame and its argument is an enemyController Object. I used minhook for hooking.
Then, i made my own Kill function in line 28. In my EnemyController hook, it gets the first argument, which is a pointer to the EnemyClass Object, the it get its m_health field and pass it to the Kill function. Since we included the Header file provided by il2cppdumper, getting the health field is as easy as
Now when we inject this exploit, this will kill all the EnemyController Object in the Game
Thanks for reading.