Skip to main content

il2cpp

Unity IL2CPP game reversing — Il2CppDumper metadata recovery, global-metadata.dat decryption, IDA/Ghidra symbol restore via generated scripts, Frida method hooking, IAP/license bypass, and zygisk-il2cpp-dumper for obfuscated metadata.

Informations de source

Dépôt
BitterSecurity/Decepticon
Dernière activité de la source
30 mai 2026 à 11:41
Langue détectée de SKILL.md
anglais
Étoiles
5 666
Forks
1 067

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
il2cpp
description
Unity IL2CPP game reversing — Il2CppDumper metadata recovery, global-metadata.dat decryption, IDA/Ghidra symbol restore via generated scripts, Frida method hooking, IAP/license bypass, and zygisk-il2cpp-dumper for obfuscated metadata.
allowed-tools
Bash Read Write
metadata
{"subdomain":"mobile","when_to_use":"unity il2cpp libil2cpp.so global-metadata.dat il2cppdumper il2cppinspector mono game reversing anti-cheat license iap inapp purchase ghidra ida symbol restore zygisk","tags":"unity, il2cpp, game, reverse-engineering, il2cppdumper, global-metadata, ghidra, frida, iap, anti-cheat","mitre_attack":"T1635, T1406, T1407"}
# Unity IL2CPP Game Reversing Playbook > Unity IL2CPP compiles C# to C++ then to native `libil2cpp.so`. The > managed bytecode is stripped — `jadx` and `apktool` expose only the > thin Java bootstrap and reveal nothing of game logic. This playbook > recovers readable symbols and hooks runtime methods for license/IAP > bypass and vulnerability assessment. ## Prerequisites - APK obtained (see `mobile/android/SKILL.md` for pull methods). - **Il2CppDumper** (Windows .NET or mono CLI): https://github.com/Perfare/Il2CppDumper - **Il2CppInspector** (alternative with plugin support): https://github.com/djkaty/Il2CppInspector - Ghidra (via MCP `ghidra` server) or IDA (host-side). - Frida + Objection for runtime hooking (see `mobile/android/SKILL.md` Frida setup section). - **zygisk-il2cpp-dumper** for runtime metadata on protected apps: https://github.com/Perfare/Zygisk-Il2CppDumper ## Step 1: Identify Unity IL2CPP App ```bash unzip -o base.apk -d /tmp/apk-out/ # Confirm IL2CPP backend ls /tmp/apk-out/lib/arm64-v8a/ # Must contain: libil2cpp.so ls /tmp/apk-out/assets/bin/Data/Managed/Metadata/ # Must contain: global-metadata.dat # If only libmono.so present → Mono backend (smali/jadx works; this skill N/A) # If libil2cpp.so present but no global-metadata.dat → encrypted/obfuscated (go to Step 5) file /tmp/apk-out/lib/arm64-v8a/libil2cpp.so # output: ELF 64-bit LSB shared object, ARM aarch64 ``` ## Step 2: Recover Symbols with Il2CppDumper ```bash # Extract libs from APK cp /tmp/apk-out/lib/arm64-v8a/libil2cpp.so /tmp/ cp /tmp/apk-out/assets/bin/Data/Managed/Metadata/global-metadata.dat /tmp/ # Run Il2CppDumper (mono CLI on Linux/macOS) mono Il2CppDumper.exe /tmp/libil2cpp.so /tmp/global-metadata.dat /tmp/dump-output/ # Windows .NET: # Il2CppDumper.exe <libil2cpp.so> <global-metadata.dat> <output-dir> ``` Output files: | File | Content | |---|---| | `dump.cs` | All C# class/method/field definitions with offsets | | `script.json` | Machine-readable symbol map (used by IDA/Ghidra scripts) | | `il2cpp.h` | C-style struct definitions for IL2CPP internals | | `stringliteral.json` | All managed string literals with addresses | ```bash # Quick scan of dump.cs for interesting classes grep -i "licen\|premium\|iap\|purchase\|unlock\|cheat\|anti\|integrity" /tmp/dump-output/dump.cs | head -30 # Find method offsets for hooks grep -A2 "IsPremium\|CheckLicense\|VerifyReceipt\|IsSubscribed" /tmp/dump-output/dump.cs # Output: // RVA: 0x<offset> — this is the function RVA in libil2cpp.so ``` ## Step 3: Apply Symbols in Ghidra / IDA ### Ghidra (via MCP ghidra server — batch mode) ``` # 1. Import libil2cpp.so into Ghidra project # 2. Run auto-analysis (aarch64) # 3. Execute the Il2CppDumper Ghidra script: # Script: ghidra_with_struct.py (from Il2CppDumper/tools/) # Input: script.json + il2cpp.h # 4. All methods now have their managed C# names ``` ```bash # Command-line Ghidra headless analysis + script "$GHIDRA_HOME/support/analyzeHeadless" /tmp/ghidra-project IL2CPP \ -import /tmp/libil2cpp.so \ -postScript ghidra_with_struct.py /tmp/dump-output/script.json \ -processor AARCH64:LE:64:v8A \ -noanalysis ``` ### IDA (host-side) ```python # In IDA scripting console (Python): # Run ida_with_struct_py3.py from Il2CppDumper/tools/ # File → Script File → ida_with_struct_py3.py # Provide path to script.json when prompted # IDA applies all function names + struct types ``` After symbol restore, navigate to `IsPremiumUser`, `CheckLicense`, `VerifyIAP`, `IsCheatDetected`, etc. by name. ## Step 4: Frida Runtime Hooking ### Hook via RVA from dump.cs ```javascript // Read RVA from dump.cs comment line: // RVA: 0x<hex> // Base address of libil2cpp.so changes per run; use Module.findBaseAddress var il2cpp_base = Module.findBaseAddress("libil2cpp.so"); // Example: hook IsPremiumUser at RVA 0x1A4F80 var RVA = 0x1A4F80; var isPremium = il2cpp_base.add(RVA); Interceptor.attach(isPremium, { onEnter: function(args) { console.log("[+] IsPremiumUser called"); }, onLeave: function(retval) { console.log("[+] Original return:", retval.toInt32()); retval.replace(ptr(1)); // return true console.log("[+] Replaced with: 1"); } }); ``` ```bash # Load hook script frida -U -f com.unity.targetgame -l hook-il2cpp.js --no-pause ``` ### Static libil2cpp.so patch (persistent, no Frida needed) ```bash # Patch return value of IsPremiumUser at computed file offset python3 - <<'EOF' import struct RVA = 0x1A4F80 LOAD_OFFSET = 0x0 # verify with readelf -l libil2cpp.so with open("/tmp/libil2cpp.so", "r+b") as f: file_offset = RVA - LOAD_OFFSET f.seek(file_offset) # AArch64: MOV W0, #1 (0x20008052) + RET (0xC003_5FD6) f.write(b"\x20\x00\x80\x52\xC0\x03\x5F\xD6") print(f"[+] Patched at file offset 0x{file_offset:X}") EOF # Repack APK apktool b /tmp/apk-smali/ -o /tmp/patched.apk # Replace libs/arm64-v8a/libil2cpp.so with patched version zip -u /tmp/patched.apk lib/arm64-v8a/libil2cpp.so uber-apk-signer.jar --allowResign -a /tmp/patched.apk -o /tmp/ adb install /tmp/patched-aligned-signed.apk ``` ## Step 5: Encrypted / Obfuscated global-metadata.dat Some apps (particularly heavily monetized games) encrypt or obfuscate `global-metadata.dat` to frustrate IL2CPP reversing. ### Detect obfuscation ```bash # Check magic bytes — valid global-metadata starts with: AF 1B B1 FA xxd /tmp/global-metadata.dat | head -2 # If first 4 bytes ≠ AF 1B B1 FA → encrypted/custom header ``` ### Common obfuscation patterns | Pattern | Detection | Counter | |---|---|---| | XOR with static key | First 4 bytes XOR'd from AF 1B B1 FA | Brute short key or key in `libil2cpp.so` strings | | Custom header / prepended garbage | File larger than expected; magic at offset N | Scan for `\xAF\x1B\xB1\xFA` pattern in file | | RC4/AES at init | `libil2cpp.so` contains crypto init before metadata load | Frida hook on `il2cpp_codegen_initialize_method` | ```bash # Search libil2cpp.so for crypto key material near metadata init r2 -qc 'iz~metadata\|iz~global' /tmp/libil2cpp.so | head -20 strings /tmp/libil2cpp.so | grep -iE "meta|key|init" | head -20 ``` ### zygisk-il2cpp-dumper (runtime dump, bypasses all static obfuscation) ```bash # Install Zygisk-Il2CppDumper module via Magisk Manager # Flash zip: ZygiskIl2CppDumper-v<version>.zip # Configure target package in /data/adb/modules/zygisk_il2cpp_dumper/config.json cat /data/adb/modules/zygisk_il2cpp_dumper/config.json # { "package_name": "com.unity.targetgame" } # Launch the target app adb shell am start -n com.unity.targetgame/.MainActivity # Dumped files appear in /data/local/tmp/il2cpp_dump/ adb pull /data/local/tmp/il2cpp_dump/ ls il2cpp_dump/ # global-metadata.dat libil2cpp.so (decrypted at runtime) ``` Feed the runtime-dumped files to Il2CppDumper per Step 2. ## Step 6: Il2CppInspector (Alternative — Richer Output) ```bash # Il2CppInspector CLI mode mono Il2CppInspector.exe \ --select-outputs Frida \ --output /tmp/frida-hooks.js \ /tmp/libil2cpp.so /tmp/global-metadata.dat # Produces a ready-to-load Frida script with all class/method stubs # Load and customize the method of interest # Also supports IDA, C# pseudo-code, and Roslyn output modes ``` ## Evidence ```python kg_add_node( kind="finding", label="Unity IL2CPP client-side IAP bypass", props={ "key": f"il2cpp-iap-bypass::{package_id}", "severity": "high", "cvss": 8.1, "package": package_id, "hooked_method": "IsPremiumUser / VerifyReceipt", "rva": "0x<from-dump.cs>", "bypass_proof": "Frida hook returns true; premium features unlocked", }, ) kg_add_node( kind="finding", label="Unity IL2CPP anti-cheat bypass", props={ "key": f"il2cpp-anticheat-bypass::{package_id}", "severity": "medium", "method": "IsCheatDetected", "details": "Client-only check; server-authoritative validation absent", }, ) ``` ## ZFP 1. `dump.cs` excerpt showing `IsPremiumUser` with RVA comment. 2. Screenshot/screen-recording of the patched/hooked app with premium features unlocked or anti-cheat bypassed. 3. Frida console output showing hook fired + return value replaced. ## OPSEC Notes - Il2CppDumper runs entirely offline on extracted APK files. No network activity required for analysis. - Static patching changes the APK signature; Play Integrity / SafetyNet will flag it. Use Frida hooks on a rooted device for non-persistent testing. - zygisk-il2cpp-dumper requires Zygisk (Magisk Delta or native Zygisk). It runs in the app process at startup and can be detected by some anti-cheat engines (EAC, BattlEye mobile). Use only in scope. - Dumped `dump.cs` may contain plaintext user-data class names that reveal the developer's internal naming conventions — treat as sensitive during an engagement. ## Severity Table | Bug | Severity | |---|---| | Client-side IAP bypass (server trusts client result) | High 8.1 | | License check entirely client-side | High 7.5 | | Anti-cheat only client-side (game balance impact) | Medium 5.5 | | Encrypted metadata recovered via runtime dump | Informational (enables further bugs) | | Hardcoded API key / secret in `dump.cs` string literals | Critical 9.0 | ## References - Il2CppDumper: https://github.com/Perfare/Il2CppDumper - Zygisk-Il2CppDumper: https://github.com/Perfare/Zygisk-Il2CppDumper - Il2CppInspector: https://github.com/djkaty/Il2CppInspector - Cross-ref: `mobile/android/SKILL.md` (Frida setup, APK pull) - Cross-ref: `mobile/flutter/SKILL.md` (Dart AOT — different toolchain) - Cross-ref: `reverser/triage/SKILL.md` (binary triage)
Voir sur GitHub