|
| 1 | +# Il2Cpp Self‑Dumper |
| 2 | + |
| 3 | +## 📖 Overview |
| 4 | + |
| 5 | +**A **Zygisk-free, root-free** il2cpp runtime dumper that runs **inside the target |
| 6 | +process itself**. load it via `system.loadlibrary()` and it automatically finds |
| 7 | +`libil2cpp.so`, resolves all Unity il2cpp APIs, and writes a `dump.cs` to the |
| 8 | +app's own files directory.** |
| 9 | + |
| 10 | +*Extracts a C#‑like pseudo‑source of every managed type (classes, structs, enums, interfaces) along with field offsets and method addresses, directly from the live IL2CPP runtime memory.* |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## 📋 Table of Contents |
| 15 | + |
| 16 | +1. [Special Advantages](#-1-special-advantages) |
| 17 | + 1.1 [Encrypted Metadata Support](#-encrypted-metadata-support) |
| 18 | + 1.2 [Container / Virtual Machine Native Support](#-container--vm-native-support) |
| 19 | + 1.3 [Crash-Safe Operation](#-crash-safe-operation) |
| 20 | + 1.4 [Zero Impact on App Behaviour](#-zero-impact-on-app-behaviour) |
| 21 | + 1.5 [Multi-Strategy Enumeration](#-multi-strategy-enumeration) |
| 22 | +2. [Limitations](#-2-limitations) |
| 23 | +3. [Security Perspective](#%EF%B8%8F-3-security-perspective) |
| 24 | + 3.1 [What This Library Can Access](#-what-this-library-can-access) |
| 25 | + 3.2 [What This Library Does NOT Do](#-what-this-library-does-not-do) |
| 26 | + 3.3 [Policy Compliance](#%EF%B8%8F-policy-compliance) |
| 27 | +4. [Output Locations & Fallback Order](#-4-output-locations--fallback-order) |
| 28 | +5. [Customising the Output Path](#-5-customising-the-output-path) |
| 29 | +6. [Usage Guide](#-6-usage-guide) |
| 30 | + 6.1 [Prerequisites](#-prerequisites) |
| 31 | + 6.2 [Build Instructions](#%EF%B8%8F-build-instructions) |
| 32 | + 6.3 [Implementation Instructions](#-implementation-instructions) |
| 33 | +7. [Acknowledgments](#-7-acknowledgments) |
| 34 | + |
| 35 | +--- |
| 36 | + |
| 37 | +## 🚀 1. Special Advantages |
| 38 | + |
| 39 | +### ✅ Encrypted Metadata Support |
| 40 | + |
| 41 | +The library **does not decrypt anything**. It waits until IL2CPP itself has loaded the decrypted metadata into memory, then dumps the live state. Works with any encryption scheme — no key extraction, no file parsing. |
| 42 | + |
| 43 | +### ✅ Container / VM Native Support |
| 44 | + |
| 45 | +>🔥 **Special Feature** |
| 46 | +>Works inside **any container or virtual machine**. Dumps official apps/games without tampering their integrity. |
| 47 | +
|
| 48 | +>- Implement the library inside the container |
| 49 | +>- Clone and run the target app inside the container |
| 50 | +>- The `dump.cs` is written directly to a shared folder, accessible from the host |
| 51 | +
|
| 52 | +### ✅ Crash-Safe Operation |
| 53 | + |
| 54 | +All IL2CPP calls are wrapped with a signal handler (`SIGSEGV`/`SIGBUS`) on an alternate stack. If a function pointer is wrong, the crash is caught, logged, and the dump thread exits cleanly — the host app never crashes. |
| 55 | + |
| 56 | +### ✅ Zero Impact on App Behaviour |
| 57 | + |
| 58 | +- ❎ No method hooking |
| 59 | +- ❎ No bytecode modification |
| 60 | +- 🧵 The dump thread runs detached at default `SCHED_OTHER` priority |
| 61 | +- ❄️ All polling loops use `sleep(1)` — no CPU busy‑wait, no battery drain |
| 62 | +- 😑 The library loads as a passive observer, the game’s FPS, network, and UI are unaffected |
| 63 | + |
| 64 | +### ✅ Multi-Strategy Enumeration |
| 65 | + |
| 66 | +The dumper automatically tries three enumeration methods, failing gracefully to the next if one is unavailable: |
| 67 | + |
| 68 | +1. **Image‑based** – `il2cpp_image_get_class` (fast, well‑structured) |
| 69 | +2. **Callback‑based** – `il2cpp_class_for_each` (newer IL2CPP builds) |
| 70 | +3. **Reflection‑based** – `Assembly.Load` + `GetTypes()` (slow but guaranteed to work even on stripped/obfuscated builds) |
| 71 | + |
| 72 | +This guarantees a successful dump on Unity versions from 2017.4 to the latest 6000.x releases. |
| 73 | + |
| 74 | +--- |
| 75 | + |
| 76 | +## ⛔ 2. Limitations |
| 77 | + |
| 78 | +- **Generic type argument display**: Generic classes appear as `List\`1` not `List<int>`. Full instantiation details require `Il2CppGenericInst` parsing, which is planned but not yet implemented. |
| 79 | +- **XOR/custom‑encrypted runtime symbols**: If `methodPointer` values are obfuscated in memory (not just the metadata file), the RVA/VA comments will show incorrect addresses. |
| 80 | +- **Unity versions before 2017.1**: Very old IL2CPP ABIs may have different struct layouts; in such cases the library produces a best‑effort partial dump. |
| 81 | +- **Deobfuscation**: The dumper does **not** rename symbols, decrypt strings, or restore control flow. It outputs raw metadata exactly as the engine sees it. |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +## 🛡️ 3. Security Perspective |
| 86 | + |
| 87 | +### 🔑 What This Library Can Access |
| 88 | + |
| 89 | +The library operates **entirely within the existing security boundary** of the target process. It: |
| 90 | +- ✅ Reads `/proc/self/maps` and `/proc/self/cmdline` — accessible to every process by design |
| 91 | +- ✅ Reads the process’s own mapped memory — it is inside the process |
| 92 | +- ✅ Writes to the app’s own files directory — storage the process already owns |
| 93 | +- ✅ Makes JNI calls using the app’s own `JavaVM` — standard Android API |
| 94 | + |
| 95 | +**No system call is made that the app itself could not make.** |
| 96 | + |
| 97 | +### ❎ What This Library Does NOT Do |
| 98 | + |
| 99 | +- ❌ Does not escalate privileges |
| 100 | +- ❌ Does not communicate over the network |
| 101 | +- ❌ Does not access other apps’ data |
| 102 | +- ❌ Does not modify **any** memory (no hooks, no patches, no code injection) |
| 103 | +- ❌ Does not persist after the process exits |
| 104 | +- ❌ Does not request additional Android permissions |
| 105 | + |
| 106 | +### 🏛️ Policy Compliance |
| 107 | + |
| 108 | +Because the library loads as part of the app’s own process under the app’s UID, it operates entirely within Android’s standard application sandbox. No security policy is violated. The library is functionally equivalent to an app examining its own runtime state — a normal and permitted operation. |
| 109 | + |
| 110 | +--- |
| 111 | + |
| 112 | +## 📁 4. Output Locations & Fallback Order |
| 113 | + |
| 114 | +The library tries the following directories **in order**. If one fails (e.g., permission denied, mount namespace issue), it moves to the next. The final file is always `dump.cs`. |
| 115 | + |
| 116 | +| Step | Strategy | Example path | |
| 117 | +|------|--------------------------------------------|----------------------------------------------------------------| |
| 118 | +| 1 | JNI `Context.getFilesDir()` | `/data/data/<pkg>/files/il2cpp_dump/` | |
| 119 | +| 2 | Hardcoded `/data/data/<pkg>/files/` | `/data/data/<pkg>/files/il2cpp_dump/` | |
| 120 | +| 3 | `/sdcard/il2cpp_dump/` (package unknown) | `/sdcard/il2cpp_dump/` | |
| 121 | +| 4* | Scoped external storage (Android 10+) | `/sdcard/Android/data/<pkg>/files/il2cpp_dump/` | |
| 122 | +| 5* | Full emulated path | `/storage/emulated/0/Android/data/<pkg>/files/il2cpp_dump/` | |
| 123 | +| 6* | Final `/sdcard` fallback | `/sdcard/il2cpp_dump/` | |
| 124 | + |
| 125 | +*Steps 4‑6 are only attempted if the primary `fopen()` fails, using the package name extracted from the original path. They are secondary fallbacks inside the dump function itself. |
| 126 | + |
| 127 | +--- |
| 128 | + |
| 129 | +## 📁 5. Customising the Output Path |
| 130 | + |
| 131 | +You can hardcode a custom directory by editing `jni_entry.c`. |
| 132 | + |
| 133 | +For example, to always write to: |
| 134 | +`/storage/emulated/0/Android/data/com.example.vm/rootfs/storage/emulated/0/il2cpp_dump/<package>/dump.cs` |
| 135 | + |
| 136 | +Replace the `output_dir` construction block in the `dump_thread()` function with: |
| 137 | + |
| 138 | +```c |
| 139 | +char output_dir[PATH_MAX] = {0}; |
| 140 | + |
| 141 | +if (pkg[0] && strcmp(pkg, "unknown") != 0) { |
| 142 | + snprintf(output_dir, sizeof(output_dir), |
| 143 | + "/storage/emulated/0/Android/data/com.example.vm/rootfs" |
| 144 | + "/storage/emulated/0/il2cpp_dump/%s", pkg); |
| 145 | + mkdir_p(output_dir); |
| 146 | + LOGI("Output dir (custom): %s", output_dir); |
| 147 | +} else { |
| 148 | + snprintf(output_dir, sizeof(output_dir), |
| 149 | + "/storage/emulated/0/Android/data/com.example.vm/rootfs" |
| 150 | + "/storage/emulated/0/il2cpp_dump/unknown"); |
| 151 | + mkdir_p(output_dir); |
| 152 | + LOGW("Output dir (custom, unknown pkg): %s", output_dir); |
| 153 | +} |
| 154 | +``` |
| 155 | + |
| 156 | +Rebuild the library and the dump will appear exactly at that hardcoded path. |
| 157 | + |
| 158 | +--- |
| 159 | + |
| 160 | +## 💡 6. Usage Guide |
| 161 | + |
| 162 | +### 📝 Prerequisites |
| 163 | + |
| 164 | +- Android NDK (for native compilation) |
| 165 | +- Termux app (for on-device building) |
| 166 | + |
| 167 | +> 💡 Tip: |
| 168 | +> If you encounter issues with NDK builds or Termux setup, you can use the GitHub Actions workflow to auto-compile the source — no manual setup needed, handles dependencies, and builds for all architectures. |
| 169 | +
|
| 170 | +### 🛠️ Build Instructions |
| 171 | + |
| 172 | +```bash |
| 173 | +# Clone the repository |
| 174 | +git clone https://github.com/muhammadrizwan87/il2cppdumper.git |
| 175 | +cd il2cppdumper |
| 176 | + |
| 177 | +# Set NDK path |
| 178 | +export NDK_HOME=/path/to/your/ndk |
| 179 | +# export NDK_HOME=/data/data/com.termux/files/home/android-sdk/ndk/24.0.8215888 |
| 180 | + |
| 181 | +# Build for all architectures |
| 182 | +$NDK_HOME/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=./jni/Application.mk |
| 183 | + |
| 184 | +# Output will be in libs/ |
| 185 | +ls libs/ |
| 186 | +# armeabi-v7a/ arm64-v8a/ x86/ x86_64/ |
| 187 | +``` |
| 188 | + |
| 189 | +### 🔀 Implementation Instructions |
| 190 | + |
| 191 | +The native library must be loaded **as early as possible** — ideally in the app’s `Application` class static initialiser or its Smali equivalent. |
| 192 | + |
| 193 | +#### Option A: Patch an existing APK (Smali) |
| 194 | + |
| 195 | +**1. Smali code to load the library:** |
| 196 | +```smali |
| 197 | +.method static constructor <clinit>()V |
| 198 | + .registers 1 |
| 199 | +
|
| 200 | + const-string v0, "il2cppdumper" |
| 201 | +
|
| 202 | + invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V |
| 203 | +
|
| 204 | + return-void |
| 205 | +.end method |
| 206 | +``` |
| 207 | + |
| 208 | +**2. Add the native libraries:** |
| 209 | +``` |
| 210 | +lib/armeabi-v7a/libil2cppdumper.so |
| 211 | +lib/arm64-v8a/libil2cppdumper.so |
| 212 | +lib/x86/libil2cppdumper.so |
| 213 | +lib/x86_64/libil2cppdumper.so |
| 214 | +``` |
| 215 | + |
| 216 | +#### Option B: Integrate into your own Android project |
| 217 | + |
| 218 | +**1. Add to your Application class:** |
| 219 | +```java |
| 220 | +public class MyApp extends Application { |
| 221 | + static { |
| 222 | + System.loadLibrary("il2cppdumper"); // note: correct spelling from Android.mk |
| 223 | + } |
| 224 | + |
| 225 | + @Override |
| 226 | + public void onCreate() { |
| 227 | + super.onCreate(); |
| 228 | + // Dump starts automatically when library loads |
| 229 | + } |
| 230 | +} |
| 231 | +``` |
| 232 | + |
| 233 | +**2. Update `build.gradle`:** |
| 234 | +```gradle |
| 235 | +android { |
| 236 | + sourceSets { |
| 237 | + main { |
| 238 | + jniLibs.srcDirs = ['libs'] |
| 239 | + } |
| 240 | + } |
| 241 | +} |
| 242 | +``` |
| 243 | + |
| 244 | +--- |
| 245 | + |
| 246 | +## 🤝 7. Acknowledgments |
| 247 | + |
| 248 | +*Built on the foundation of [Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper) by Perfare.* |
0 commit comments