Thanks to visit codestin.com
Credit goes to github.com

Skip to content

jakzo/Il2CppDecompiler

Repository files navigation

Ghidra extension for decompiling code from a Unity IL2CPP game to C#.

➡️ Usage

Note that it is powered by GPT4 so will require an OpenAI account to decompile functions.

  1. Get an OpenAI platform account
  2. Get game outputs from Il2CppDumper
    • Install Il2CppDumper
    • Dump outputs (example command below)
      ./Il2CppDumper /path/to/game/GameAssembly.dll /path/to/game/resources/global-metadata.dat ./il2cpp_out
  3. Set up Ghidra project
    • Install Ghidra
    • Run ghidraRun -> create new project -> Import game code file (GameAssembly.dll)
    • Open game file -> auto analyze (default options) -> wait until done (could be an hour or more)
    • File -> Parse C source -> add il2cpp.h from Il2CppDumper output -> parse and wait until done
    • Window -> Script manager -> add Il2CppDumper directory (the one containing ghidra_with_structs.py) -> run ghidra_with_structs.py from the list -> follow prompts and wait until done
  4. Check that decompilation works correctly
    • Find a function from the game in Ghidra and look through the decompiled C code to make sure it makes sense
    • For my game (Boneworks) the il2cpp.h generated by Il2CppDumper was missing a field in all class instances which made all field offsets wrong and caused property accesses to be off by 8 bytes
  5. Rename functions (usually exception throwing functions)
    • The script will not run if there are unnamed functions being called (eg. FUN_1234abcd) in the method being decompiled
    • Find your function in Ghidra and look at the decompiled C code
    • There should be lots of if (someVar != (SomeType)0x0) { ... } FUN_1234abcd(); which are null checks (since C# will throw a NullReferenceException if x is null in x.y)
    • Rename the exception function (FUN_1234abcd in the example above) to ThrowNullReferenceException and mark it as "No Return"
    • In future I may automate this step
  6. Install the Il2CppDecompiler.java script
    • Download the Il2CppDecompiler.java script
    • Open the script manager in Ghidra (Window -> Script Manager)
    • Click the "Manage Script Directories" button
    • Add the directory containing the downloaded Il2CppDecompiler.java script
  7. Run the Il2CppDecompiler.java script
    • Navigate to the method you want to decompile
    • Window -> Script Manager -> Il2CppDecompiler -> Follow the prompts

You can also run it in headless mode. First make sure the project is not currently open in Ghidra then run the command from test-script.sh.

🛠️ Development

This repo contains an extension which doesn't really do anything yet. I planned to convert Ghidra's P-code (intermediate representation of machine code) to C# and build a UI for viewing/editing decompiled C# inside Ghidra (similar to the existing C decompiler) but this approach was taking too long so I pivoted to writing a script which sends the code to an LLM to do all the work for me. 🤷

Script

./ghidra_scripts/Il2CppDecompiler.java contains the LLM-based script. It also still contains the proof-of-concept hacky string replacement approach I started with. You can edit the file as-is, but I like to clone the Ghidra source code, set that up and symlink Il2CppDecompiler.java into one of the ghidra_scripts folders there so that I get autocomplete with doc comments and can go to source of internal Ghidra functions. Run link.sh to automatically set that up then edit the Il2CppDecompiler.java which is linked inside the ghidra directory.

Debugging

You can run the script during development by making sure Ghidra is closed then running test-script.sh. Before first run, make sure you set the variables in the script in gradle.properties or as environment variables. You can also attach a debugger by running the script like this:

MODE=debug-suspend ./test-script.sh

Note that this script is for Unix systems. You're probably using Windows so you'll have to convert it to a .bat script or something. Please open a PR if you do. 😄

Extension

Note that the extension doesn't do anything yet. I originally intended to build an interface for the decompiled C# code, like the existing interface for decompiled C.

  1. Create/modify gradle.properties to contain:
    GHIDRA_INSTALL_DIR=<absolute_path_to_your_ghidra_installation>
  2. Then build with:
    gradle

About

Ghidra extension for decompiling code from a Unity IL2CPP game to C#.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published