--- name: rev-u3d-dump description: Dump Unity IL2CPP symbols from iOS/Android builds. Extract method names, addresses, and type info from IL2CPP binaries and global-metadata.dat, then generate IDA/Ghidra import scripts. --- # rev-u3d-dump - Unity IL2CPP Symbol Dumper Extract C# method names, addresses, and type definitions from Unity IL2CPP builds for IDA/Ghidra analysis. --- ## Overview Unity IL2CPP compiles C# to native code. The original class/method names are stripped from the binary but preserved in `global-metadata.dat`. This skill recovers the mapping between native function addresses and their original C# names. ### Key Files in Unity Build | File | Location | Purpose | |------|----------|---------| | Native binary | iOS: `Frameworks/UnityFramework.framework/UnityFramework`
Android: `lib/{arch}/libil2cpp.so` | Compiled C# code (Mach-O / ELF) | | Metadata | `Data/Managed/Metadata/global-metadata.dat` | All type/method/string info | --- ## Tool Selection ### Il2CppDumper (recommended for metadata v39+) Use the **v39 fork** for Unity 6+ builds: - Repo: `https://github.com/roytu/Il2CppDumper` (branch: `v39`) - Supports metadata v24–v39 - Outputs `script.json` with function addresses — ready for IDA/Ghidra import The original Il2CppDumper (`https://github.com/Perfare/Il2CppDumper`) only supports up to v29. ### Cpp2IL (alternative) - Repo: `https://github.com/SamboyCoding/Cpp2IL` - Supports metadata v39, but dummy DLLs lack `[Address]` attributes - Useful for C# source reconstruction, not ideal for IDA import --- ## Step-by-Step Workflow ### Step 1: Locate IL2CPP Files **iOS (IPA):** ```bash # Unzip IPA unzip -o app.ipa -d . # Binary BINARY="Payload/.app/Frameworks/UnityFramework.framework/UnityFramework" # Metadata METADATA="Payload/.app/Data/Managed/Metadata/global-metadata.dat" ``` **Android (APK):** ```bash # Unzip APK unzip -o app.apk -d . # Binary (pick target arch) BINARY="lib/arm64-v8a/libil2cpp.so" # Metadata METADATA="assets/bin/Data/Managed/Metadata/global-metadata.dat" ``` ### Step 2: Check Metadata Version ```bash # First 8 bytes: magic (4) + version (4), little-endian xxd -l 8 "$METADATA" # Expected: af1b b1fa 2700 0000 → magic OK, version = 0x27 = 39 ``` | Version | Unity | Tool | |---------|-------|------| | ≤ 29 | Unity 2021 and earlier | Original Il2CppDumper | | 31 | Unity 2022 | Original Il2CppDumper (partial) | | 39 | Unity 6 (6000.x) | **roytu/Il2CppDumper v39 fork** | ### Step 3: Build & Run Il2CppDumper (v39 fork) ```bash # Clone v39 fork git clone -b v39 https://github.com/roytu/Il2CppDumper.git # Build cd Il2CppDumper DOTNET_ROLL_FORWARD=LatestMajor dotnet build -c Release # Run (use net8.0 framework) DOTNET_ROLL_FORWARD=LatestMajor dotnet run \ --project Il2CppDumper/Il2CppDumper.csproj \ -c Release --framework net8.0 \ -- "$BINARY" "$METADATA" output_dir ``` **Notes:** - `DOTNET_ROLL_FORWARD=LatestMajor` allows running on .NET 9/10 even though the project targets .NET 6/8 - Exit code 134 is normal in non-interactive mode (caused by `Console.ReadKey()` at the end) - On macOS, if the binary gets SIGKILL'd, ad-hoc sign it: `codesign -s - ` ### Step 4: Verify Output Successful run produces these files in the output directory: | File | Size (typical) | Purpose | |------|----------------|---------| | `script.json` | 50–100 MB | Function addresses + names + signatures (IDA/Ghidra import) | | `dump.cs` | 10–30 MB | C# class dump with RVA/VA addresses | | `il2cpp.h` | 50–100 MB | C struct definitions for type import | | `ida_py3.py` | ~2 KB | IDA Python import script | Check `script.json` format: ```json { "ScriptMethod": [ { "Address": 40865744, "Name": "ClassName$$MethodName", "Signature": "ReturnType ClassName__MethodName (args...);", "TypeSignature": "viii" } ] } ``` Check `dump.cs` format: ```csharp // RVA: 0x1A2B3C4 Offset: 0x1A2B3C4 VA: 0x1A2B3C4 public void MethodName() { } ``` ### Step 5: Import into IDA 1. Open the native binary in IDA (UnityFramework / libil2cpp.so) 2. Place `script.json` and `ida_py3.py` in the same directory 3. `File → Script file...` → select `ida_py3.py` 4. The script reads `script.json` and renames all functions automatically 5. Optional: `File → Load file → Parse C header file...` → select `il2cpp.h` for struct types ### Step 5 (alt): Import into Ghidra 1. Open the binary in Ghidra 2. Use the `ghidra.py` or `ghidra_with_struct.py` script from Il2CppDumper 3. `Window → Script Manager → Run` with `script.json` in the same directory --- ## Troubleshooting | Error | Cause | Fix | |-------|-------|-----| | `not a supported version[39]` | Using original Il2CppDumper | Switch to roytu/Il2CppDumper v39 fork | | Exit code 137 (SIGKILL) | macOS unsigned binary | `codesign -s - ` | | `Cannot read keys` (exit 134) | Non-interactive console | Ignore — dump completed successfully | | `DOTNET_ROLL_FORWARD` error | .NET version mismatch | Set `DOTNET_ROLL_FORWARD=LatestMajor` | | Empty output | Wrong binary/metadata pair | Verify both files are from the same build | --- ## Output Usage Tips - `dump.cs` is the quickest reference — search for class/method names with RVA addresses - `script.json` Address values are decimal — convert to hex for IDA: `hex(40865744)` → `0x26F8FD0` - Field offsets in `dump.cs` (e.g., `// 0x20`) are relative to object base, useful for memory inspection with Frida