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.

来源信息

仓库
BitterSecurity/Decepticon
最近来源活动
2026年5月30日 11:41
检测到的 SKILL.md 语言
英语
星标
5,611
分支
1,061

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
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)
在 GitHub 查看