Dump Unity IL2CPP symbols from iOS/Android builds. Extract method names, addresses, and type info from IL2CPP binaries and global-metadata.dat, then generate…
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/UnityFrameworkAndroid: 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):
# Unzip IPA
unzip -o app.ipa -d .
# Binary
BINARY="Payload/<AppName>.app/Frameworks/UnityFramework.framework/UnityFramework"
# Metadata
METADATA="Payload/<AppName>.app/Data/Managed/Metadata/global-metadata.dat"
Android (APK):
# 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
# 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)
# 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 - <binary>
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:
{
"ScriptMethod": [
{
"Address": 40865744,
"Name": "ClassName$$MethodName",
"Signature": "ReturnType ClassName__MethodName (args...);",
"TypeSignature": "viii"
}
]
}
Check dump.cs format:
// RVA: 0x1A2B3C4 Offset: 0x1A2B3C4 VA: 0x1A2B3C4
public void MethodName() { }
Step 5: Import into IDA
Open the native binary in IDA (UnityFramework / libil2cpp.so)
Place script.json and ida_py3.py in the same directory
File → Script file... → select ida_py3.py
The script reads script.json and renames all functions automatically
Optional: File → Load file → Parse C header file... → select il2cpp.h for struct types
Step 5 (alt): Import into Ghidra
Open the binary in Ghidra
Use the ghidra.py or ghidra_with_struct.py script from Il2CppDumper
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 - <binary>
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 Fridadon't have the plugin yet? install it then click "run inline in claude" again.
formalized 6 missing components (intent, inputs with external tool and env setup, explicit numbered procedure with inputs/outputs per step, decision points covering version logic and error cases, output contract with format specs, outcome signal with verification steps), clarified metadata version detection, added edge cases for macos code signing and network timeouts, preserved original procedure and author attribution.
---
name: rev-u3d-dump
slug: 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-ready symbol maps.
author: p4nda0s
---
## intent
extract c# method names, addresses, and type definitions from unity il2cpp builds for ida/ghidra reverse engineering. use this when you have an ios ipa or android apk built with unity's il2cpp backend and need to recover the mapping between native function addresses and their original c# symbol names. il2cpp strips names from the binary but preserves them in global-metadata.dat, so this skill bridges that gap.
## inputs
**files (required)**
- native binary: iOS path is `Payload/<AppName>.app/Frameworks/UnityFramework.framework/UnityFramework` (mach-o format). Android path is `lib/{arch}/libil2cpp.so` (elf format, typically arm64-v8a).
- metadata file: `global-metadata.dat` located at `Data/Managed/Metadata/global-metadata.dat` (iOS) or `assets/bin/Data/Managed/Metadata/global-metadata.dat` (Android).
- both files must come from the same build.
**environment setup (required)**
- .NET 6+ runtime installed (dotnet cli). .NET 8+ preferred for v39 fork compatibility.
- DOTNET_ROLL_FORWARD env var set to `LatestMajor` if running on .NET 9/10 against a project targeting .NET 6/8.
- on macOS, ad-hoc code signing capability if binary is unsigned (codesign binary available in Xcode tools).
- git cli for cloning the dumper tool repository.
**external tool (required)**
- Il2CppDumper v39 fork (roytu/Il2CppDumper, branch v39) for Unity 6 / metadata v39+. original Il2CppDumper (Perfare) only handles metadata up to v29, so it will fail on modern builds.
**context**
- metadata version extracted from first 8 bytes of global-metadata.dat: bytes 0-3 are magic (af 1b b1 fa), bytes 4-7 are version in little-endian uint32. version 39 = unity 6, version 31 = unity 2022, version <= 29 = unity 2021 and earlier.
## procedure
**step 1: extract binary and metadata from app package**
input: app.ipa (iOS) or app.apk (Android).
1a. for iOS: run `unzip -o app.ipa -d .` in a clean directory.
- output: directory tree with `Payload/<AppName>.app/` and framework structure visible.
- locate `BINARY="Payload/<AppName>.app/Frameworks/UnityFramework.framework/UnityFramework"` (no file extension, mach-o binary).
- locate `METADATA="Payload/<AppName>.app/Data/Managed/Metadata/global-metadata.dat"`.
1b. for Android: run `unzip -o app.apk -d .` in a clean directory.
- output: directory tree with lib/, assets/, and AndroidManifest.xml visible.
- pick target architecture: `BINARY="lib/arm64-v8a/libil2cpp.so"` (or armv7, x86, x86_64 if arm64 unavailable).
- locate `METADATA="assets/bin/Data/Managed/Metadata/global-metadata.dat"`.
**step 2: verify metadata version and tool choice**
input: global-metadata.dat file path.
2a. run `xxd -l 8 "$METADATA"` to dump first 8 bytes in hex.
- expected output: `af1b b1fa 2700 0000` (or similar, first 4 bytes are magic, last 4 are version in little-endian).
- parse version: in the example above, `2700 0000` in little-endian is 0x00000027 = 39 decimal.
- output: metadata version number (integer).
2b. map version to tool:
- version 39 (unity 6): use roytu/Il2CppDumper v39 fork.
- version 31 (unity 2022): use original Il2CppDumper (Perfare).
- version <= 29 (unity 2021 and earlier): use original Il2CppDumper.
**step 3: clone and build Il2CppDumper**
input: tool choice from step 2b, git cli, .NET runtime with DOTNET_ROLL_FORWARD env var.
3a. run `git clone -b v39 https://github.com/roytu/Il2CppDumper.git` (for v39 fork) or `git clone https://github.com/Perfare/Il2CppDumper.git` (for original).
- output: Il2CppDumper/ directory with full source tree.
3b. cd into Il2CppDumper directory.
3c. run `DOTNET_ROLL_FORWARD=LatestMajor dotnet build -c Release`.
- output: compiled binaries in Il2CppDumper/bin/Release/.
- note: build may take 1-3 minutes depending on network (nuget package fetch).
**step 4: execute il2cppdumper**
input: binary path, metadata path, output directory path (create it or leave blank for default).
4a. run:
DOTNET_ROLL_FORWARD=LatestMajor dotnet run
--project Il2CppDumper/Il2CppDumper.csproj
-c Release --framework net8.0
-- "$BINARY" "$METADATA" output_dir
- replace `$BINARY`, `$METADATA`, `output_dir` with actual paths.
- note: on macOS, if the dumper binary itself is unsigned, run `codesign -s - Il2CppDumper/bin/Release/net8.0/Il2CppDumper` first (or the binary may be killed by the os).
4b. monitor stdout. expected output includes progress lines like "reading binary..." and "parsing metadata...".
- exit code 0: success (rare, tool exits with 134 in non-interactive mode).
- exit code 134: normal in cli mode (caused by Console.ReadKey() at end of tool, but dump already completed).
- exit code 137 (sigkill): binary unsigned on macOS, re-sign and retry.
- exit code other: genuine error, check stderr.
4c. output: files written to `output_dir/` (or Il2CppDumper's default output location if not specified).
**step 5: verify output files**
input: output directory from step 4c.
5a. check file existence:
- `script.json` (50-100 MB typical): function addresses and names.
- `dump.cs` (10-30 MB typical): c# class dump with rva/va annotations.
- `il2cpp.h` (50-100 MB typical): c struct definitions.
- `ida_py3.py` (~2 KB): ida python import automation script.
5b. spot-check script.json format: run `head -20 script.json | python3 -m json.tool` to verify valid json and presence of ScriptMethod array with Address, Name, Signature fields.
5c. spot-check dump.cs: run `head -30 dump.cs` and confirm lines match pattern `// RVA: 0xHEX Offset: 0xHEX VA: 0xHEX` followed by c# method declarations.
**step 6: import into ida**
input: native binary (UnityFramework or libil2cpp.so), script.json, ida_py3.py (all in same or known directory).
6a. open native binary in IDA Pro (File → Open → select binary).
- IDA auto-detects mach-o or elf and loads architecture.
6b. once binary is loaded, go to File → Script file... and select ida_py3.py.
- the script reads script.json from the same directory and applies renames to all functions.
- output: function names in IDA's disassembly now show c# method names (e.g., `ClassName$$MethodName`).
6c. (optional) import struct definitions: File → Load file → Parse C header file... and select il2cpp.h.
- output: type definitions available for struct member analysis in IDA.
**step 6 (alternative): import into ghidra**
input: native binary, ghidra.py (or ghidra_with_struct.py) from Il2CppDumper output, script.json.
6a-alt. open binary in Ghidra.
6b-alt. go to Window → Script Manager, locate and run ghidra.py (or ghidra_with_struct.py).
- script will prompt for script.json path or auto-detect in same directory.
- output: function names updated in Ghidra's listing.
## decision points
**if metadata version is 39 (unity 6):** use roytu/Il2CppDumper v39 fork (branch v39). the original Il2CppDumper will fail with "not a supported version [39]" error.
**if metadata version is <= 29 (unity 2021 and earlier):** use original Il2CppDumper (Perfare/Il2CppDumper). v39 fork is overkill and adds unnecessary dependencies.
**if running on macOS and dumper binary is unsigned:** run `codesign -s - Il2CppDumper/bin/Release/net8.0/Il2CppDumper` before executing step 4a. if skipped, dumper will be killed with sigkill (exit 137) and produce no output.
**if exit code is 134 and output_dir/ contains script.json:** the dump succeeded despite the exit code. console.readkey() at the tool's end causes the 134 in non-interactive mode. this is expected behavior, proceed to step 5.
**if exit code is 137 or binary is unsigned on macOS:** re-sign the dumper binary and re-run. do not skip this on macOS.
**if output_dir/ is empty:** binary and metadata file mismatch (not from same build) or wrong paths passed. verify both file paths with `ls -la` and ensure they point to the same app build. re-run step 4a with correct paths.
**if network timeout or dotnet nuget fetch fails during build:** re-run step 3c. transient network issues are common with large package downloads. if persistent, use `dotnet nuget disable source nuget.org` and configure a local nuget cache, or use a ci/cd pipeline with pre-cached packages.
**if dump.cs is present but script.json is empty or malformed:** metadata parsing succeeded but function enumeration failed. this is rare. verify metadata version with step 2a, confirm tool matches version requirement, and re-run step 4a in verbose mode (add `--verbosity diagnostic` to dotnet run command).
## output contract
**script.json**
- format: json array of ScriptMethod objects.
- each object has keys: Address (decimal int), Name (string, format ClassName$$MethodName), Signature (string, c-like type signature), TypeSignature (string, type code abbreviation like "viii").
- typical size: 50-100 MB.
- ready for ida import via ida_py3.py script.
**dump.cs**
- format: c# code with comments.
- each method/property line prefixed with comment: `// RVA: 0xHEX Offset: 0xHEX VA: 0xHEX`.
- human-readable class and method names preserved.
- typical size: 10-30 MB.
- quick reference for searching by symbol name.
**il2cpp.h**
- format: c struct definitions (typedef struct declarations).
- contains all unity il2cpp type definitions (e.g., Il2CppString, Il2CppArray).
- typical size: 50-100 MB.
- importable into ida for struct member analysis.
**ida_py3.py**
- format: python script for ida pro.
- reads script.json from same directory and applies function renames.
- output: renamed functions in ida database (idb file modified in-place).
## outcome signal
after running step 6 (ida or ghidra import), open the native binary in the disassembler and navigate to any address from script.json (convert address from decimal to hex: e.g., 40865744 becomes 0x26F8FD0). the function at that address should now be labeled with its c# name (e.g., `ClassName$$MethodName`) instead of a generic auto-generated name like `sub_26F8FD0`. if function names are updated and match the names in script.json / dump.cs, the skill succeeded.
additional success markers: dump.cs can be opened in a text editor and searched by class or method name to find rva/va addresses. il2cpp.h can be parsed by ida's c header importer with no parse errors.