muhammadrizwan87/il2cppdumper
GitHub: muhammadrizwan87/il2cppdumper
一款无需 root 的 Android IL2CPP 运行时 dumper,直接在目标进程内从内存中提取 Unity IL2CPP 应用的类、方法和字段信息并生成 dump.cs。
Stars: 12 | Forks: 3
# Il2Cpp Self‑Dumper
## 📖 概述
**一个**无需 Zygisk、无需 root** 的 il2cpp 运行时 dumper,它直接**在目标进程内部**运行。通过 `system.loadlibrary()` 加载后,它会自动查找 `libil2cpp.so`,解析所有 Unity il2cpp API,并将 `dump.cs` 写入应用自身的文件目录。**
*直接从运行中的 IL2CPP 运行时内存中,提取每种托管类型(类、结构体、枚举、接口)的类 C# 伪源码,以及字段偏移量和方法地址。*
## 📋 目录
1. [特殊优势](#-1-special-advantages)
1.1 [支持加密 Metadata](#-encrypted-metadata-support)
1.2 [容器 / 虚拟机原生支持](#-container--vm-native-support)
1.3 [防崩溃安全操作](#-crash-safe-operation)
1.4 [对应用行为零影响](#-zero-impact-on-app-behaviour)
1.5 [多策略枚举](#-multi-strategy-enumeration)
2. [局限性](#-2-limitations)
3. [安全性视角](#%EF%B8%8F-3-security-perspective)
3.1 [本库可以访问的内容](#-what-this-library-can-access)
3.2 [本库不会执行的操作](#-what-this-library-does-not-do)
3.3 [政策合规性](#%EF%B8%8F-policy-compliance)
4. [输出位置与回退顺序](#-4-output-locations--fallback-order)
5. [自定义输出路径](#-5-customising-the-output-path)
6. [使用指南](#-6-usage-guide)
6.1 [前置条件](#-prerequisites)
6.2 [构建说明](#%EF%B8%8F-build-instructions)
6.3 [集成说明](#-implementation-instructions)
7. [致谢](#-7-acknowledgments)
## 🚀 1. 特殊优势
### ✅ 支持加密 Metadata
本库**不会解密任何内容**。它会等待 IL2CPP 自身将解密后的 metadata 加载到内存中,然后再 dump 活动状态。适用于任何加密方案——无需提取密钥,无需解析文件。
### ✅ 容器 / 虚拟机原生支持
### ✅ 防崩溃安全操作
所有 IL2CPP 调用都在备用栈上使用信号处理程序(`SIGSEGV`/`SIGBUS`)进行了包装。如果函数指针有误,崩溃将被捕获并记录,dump 线程会干净地退出——宿主应用绝不会崩溃。
### ✅ 对应用行为零影响
- ❎ 无方法 Hook
- ❎ 无字节码修改
- 🧵 dump 线程以默认的 `SCHED_OTHER` 优先级分离运行
- ❄️ 所有轮询循环均使用 `sleep(1)`——无 CPU 忙等待,不耗电
- 😑 本库作为被动观察者加载,游戏的 FPS、网络和 UI 均不受影响
### ✅ 多策略枚举
dumper 会自动尝试三种枚举方法,如果一种不可用,则会优雅地失败并回退到下一种:
1. **基于 Image** – `il2cpp_image_get_class`(快速,结构良好)
2. **基于回调** – `il2cpp_class_for_each`(较新的 IL2CPP 构建版本)
3. **基于反射** – `Assembly.Load` + `GetTypes()`(即使在被剥离/混淆的构建版本上也能保证工作,但速度较慢)
这保证了在从 Unity 2017.4 到最新的 6000.x 版本上都能成功 dump。
## ⛔ 2. 局限性
- **泛型类型参数显示**:泛型类显示为 `List\`1` 而不是 `List`。完整的实例化细节需要解析 `Il2CppGenericInst`,该功能已计划但尚未实现。
- **XOR/自定义加密的运行时符号**:如果内存中的 `methodPointer` 值被混淆(不仅仅是 metadata 文件被混淆),RVA/VA 注释将显示错误的地址。
- **2017.1 之前的 Unity 版本**:非常旧的 IL2CPP ABI 可能具有不同的结构体布局;在这种情况下,本库会尽最大努力生成部分 dump。
- **反混淆**:dumper **不会**重命名符号、解密字符串或恢复控制流。它输出的完全是引擎所看到的原始 metadata。
## 🛡️ 3. 安全性视角
### 🔑 本库可以访问的内容
本库**完全在目标进程现有的安全边界内**运作。它:
- ✅ 读取 `/proc/self/maps` 和 `/proc/self/cmdline` — 根据系统设计,每个进程均可访问
- ✅ 读取进程自身映射的内存 — 因为它就在进程内部
- ✅ 写入应用自身的文件目录 — 使用的是进程已经拥有的存储空间
- ✅ 使用应用自身的 `JavaVM` 进行 JNI 调用 — 标准 Android API
**未发出任何应用自身无法进行的系统调用。**
### ❎ 本库不会执行的操作
- ❌ 不提升权限
- ❌ 不通过网络进行通信
- ❌ 不访问其他应用的数据
- ❌ 不修改**任何**内存(无 Hook、无补丁、无代码注入)
- ❌ 在进程退出后不进行任何驻留
- ❌ 不请求额外的 Android 权限
### 🏛️ 政策合规性
由于本库是在应用的 UID 下作为应用自身进程的一部分加载的,因此它完全在 Android 的标准应用沙箱内运行。没有违反任何安全策略。本库在功能上等同于一个应用检查自身的运行时状态——这是一种正常且被允许的操作。
## 📁 4. 输出位置与回退顺序
本库按以下顺序**依次**尝试这些目录。如果其中一个失败(例如,权限被拒绝、挂载命名空间问题),它会转向下一个。最终文件始终命名为 `dump.cs`。
| 步骤 | 策略 | 示例路径 |
|------|--------------------------------------------|----------------------------------------------------------------|
| 1 | JNI `Context.getFilesDir()` | `/data/data//files/il2cpp_dump/` |
| 2 | 硬编码 `/data/data//files/` | `/data/data//files/il2cpp_dump/` |
| 3 | `/sdcard/il2cpp_dump/`(包名未知) | `/sdcard/il2cpp_dump/` |
| 4* | 限定作用域的外部存储 (Android 10+) | `/sdcard/Android/data//files/il2cpp_dump/` |
| 5* | 完整模拟路径 | `/storage/emulated/0/Android/data//files/il2cpp_dump/` |
| 6* | 最终的 `/sdcard` 回退 | `/sdcard/il2cpp_dump/` |
*步骤 4‑6 仅在主 `fopen()` 失败时尝试,此时会使用从原始路径中提取的包名。它们是 dump 函数内部的次要回退方案。
## 📁 5. 自定义输出路径
你可以通过编辑 `jni_entry.c` 来硬编码一个自定义目录。
例如,要始终写入到:
`/storage/emulated/0/Android/data/com.example.vm/rootfs/storage/emulated/0/il2cpp_dump//dump.cs`
请将 `dump_thread()` 函数中的 `output_dir` 构建代码块替换为:
```
char output_dir[PATH_MAX] = {0};
if (pkg[0] && strcmp(pkg, "unknown") != 0) {
snprintf(output_dir, sizeof(output_dir),
"/storage/emulated/0/Android/data/com.example.vm/rootfs"
"/storage/emulated/0/il2cpp_dump/%s", pkg);
mkdir_p(output_dir);
LOGI("Output dir (custom): %s", output_dir);
} else {
snprintf(output_dir, sizeof(output_dir),
"/storage/emulated/0/Android/data/com.example.vm/rootfs"
"/storage/emulated/0/il2cpp_dump/unknown");
mkdir_p(output_dir);
LOGW("Output dir (custom, unknown pkg): %s", output_dir);
}
```
重新构建库后,dump 将准确地生成在该硬编码路径下。
## 💡 6. 使用指南
### 📝 前置条件
- Android NDK(用于原生编译)
- Termux 应用(用于在设备上构建)
### 🛠️ 构建说明
```
# Clone 仓库
git clone https://github.com/muhammadrizwan87/il2cppdumper.git
cd il2cppdumper
# 设置 NDK 路径
export NDK_HOME=/path/to/your/ndk
# export NDK_HOME=/data/data/com.termux/files/home/android-sdk/ndk/24.0.8215888
# 为所有架构构建
$NDK_HOME/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=./jni/Application.mk
# 输出将在 libs/ 中
ls libs/
# armeabi-v7a/ arm64-v8a/ x86/ x86_64/
```
### 🔀 集成说明
原生库必须**尽早加载**——理想情况下是在应用的 `Application` 类静态初始化器或其对应的 Smali 代码中。
#### 选项 A:修补现有的 APK (Smali)
**1. 加载库的 Smali 代码:**
```
.method static constructor ()V
.registers 1
const-string v0, "il2cppdumper"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method
```
**2. 添加原生库:**
```
lib/armeabi-v7a/libil2cppdumper.so
lib/arm64-v8a/libil2cppdumper.so
lib/x86/libil2cppdumper.so
lib/x86_64/libil2cppdumper.so
```
#### 选项 B:集成到你自己的 Android 项目中
**1. 添加到你的 Application 类中:**
```
public class MyApp extends Application {
static {
System.loadLibrary("il2cppdumper"); // note: correct spelling from Android.mk
}
@Override
public void onCreate() {
super.onCreate();
// Dump starts automatically when library loads
}
}
```
**2. 更新 `build.gradle`:**
```
android {
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
```
## 🤝 7. 致谢
*基于 Perfare 的 [Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper) 基础构建。*
标签:Android安全, App安全检测, C#伪代码生成, Hook工具, IL2CPP逆向, libil2cpp.so, Native库, SO库分析, Unity游戏逆向, 云资产清单, 内存Dump, 加密元数据处理, 安卓注入, 客户端加密, 无需Root, 流量嗅探, 游戏安全, 移动安全工具, 移动端脱壳, 网络安全, 进程内注入, 逆向工程, 隐私保护