Il2CppDumper 逆向实战:从 APK 到 DummyDll 的 4 步还原流程与 3 大报错排查
【免费下载链接】Il2CppDumperUnity il2cpp reverse engineer项目地址: https://gitcode.com/gh_mirrors/il/Il2CppDumper
当你费尽力气解压一个 Unity 手游的 APK,却在lib/arm64-v8a/里只找到一堆没有符号的原生机器码,而assets/bin/Data/global-metadata.dat又像天书一样打不开时,你就遇到了 IL2CPP 逆向最典型的双重障碍。Il2CppDumper 正是为打通这条还原链路而生的开源逆向工具:它读取libil2cpp.so与global-metadata.dat这对"二进制 + 元数据"组合,还原出可供 dnSpy 直接浏览的类型结构与函数签名。本文不罗列功能,而是带着你从零跑通一条完整链路,再逐一拆解最常见的报错现场。
能力速览:先判断这个工具适不适合你
| 核心能力 | 适用场景 | 上手难度 | 目标人群 |
|---|---|---|---|
| 解析 IL2CPP 二进制与元数据,生成 DummyDll | 还原类结构、方法签名、字段偏移 | ★★☆☆☆ | 逆向新手 |
| 支持 ELF / Mach-O / PE / NSO / WASM 五种格式 | 覆盖 Android / iOS / Windows / Switch / WebGL | ★★★☆☆ | 跨平台分析者 |
| 生成 IDA / Ghidra / Binary Ninja 脚本 | 将类型信息导入反汇编器辅助分析 | ★★★★☆ | 中级及以上 |
| 支持内存 dump 文件与简单加壳绕过 | 处理加密 metadata、被保护的 so | ★★★★☆ | 有逆向基础者 |
如果你是第一次接触 IL2CPP 逆向,建议从下一节开始;如果已经被某个报错卡了很久,可以直接跳到报错排查部分。
新手四步:从 APK 到可浏览的 DLL
第一步:准备工具与源码
准备运行环境:Il2CppDumper 是 .NET 项目,Windows 下直接运行编译产物即可;Linux 下需要 .NET 运行时。先克隆源码:
git clone https://gitcode.com/gh_mirrors/il/Il2CppDumper项目使用命令行方式调用,格式固定为三个参数(参考 Program.cs):
Il2CppDumper <可执行文件> <global-metadata> <输出目录>第二步:提取关键文件
提取 APK 内容:用 7-Zip 解压目标游戏包:
7z x game.apk -oextracted_apk然后定位两个核心文件:
cd extracted_apk/lib/arm64-v8a/ ls libil2cpp.so cd ../../assets/bin/Data/ ls global-metadata.dat⚠️ 注意:如果你的目标游戏同时存在libil2cpp.so和libil2cpp.so.bak之类的同名备份,优先取体积较大、未被占位的那一个。
第三步:运行还原命令
执行解析:回到 Il2CppDumper 目录,运行:
Il2CppDumper libil2cpp.so global-metadata.dat output正常执行时,控制台会依次输出Metadata Version、Il2Cpp Version和Searching...,最终打印Done!。此时output/目录下已经生成了全套产物:
DummyDll/:还原出的伪 DLL 集合,这是后续分析的主战场dump.cs:人类可读的类型声明文本,含字段偏移与函数 RVA 注释script.json、stringliteral.json:供反汇编器脚本消费的地址映射数据il2cpp.h:结构体头文件,供 IDA / Ghidra 导入类型ida.py、ida_with_struct.py、ghidra.py、ghidra_with_struct.py等辅助脚本
第四步:用 dnSpy 浏览还原结果
查看还原结构:打开 dnSpy,把output/DummyDll/下的 DLL 全部拖入,左侧导航树中就能看到命名空间、类、字段和方法签名。搜索PlayerController、GameManager这类常见游戏类,即可定位目标逻辑的位置。
原理点睛:IL2CPP 编译的本质是把 C# 代码先转成 C++ 中间层,再编译成原生机器码,同时把类型元数据单独写进global-metadata.dat。Il2CppDumper 做的事是"逆向这两步"——它先校验 metadata 文件头部的魔数0xFAB11BAF并探测版本号,再在二进制中扫描CodeRegistration/MetadataRegistration结构定位函数指针表,最后把"元数据中的类型定义"与"二进制中的方法地址"一一配对,重建出只含类型信息、不含方法体的 DummyDll。所以它还原的是"骨架"而非"血肉",方法体仍需要在反汇编器中结合地址注释查看。
进阶排查:三个高频报错一次说清
报错一:Metadata file supplied is not valid
这是出现频率最高的一条。Il2CppDumper 在校验 metadata 头部的 sanity 字段与版本号时失败(判断逻辑见 Il2Cpp/Metadata.cs),绝大多数原因是文件被加密或混淆。
排查路径:
- 用十六进制编辑器打开
global-metadata.dat,确认头部前四个字节是否为AF 1B B1 FA(即魔数0xFAB11BAF)。不是则说明文件被处理过。 - 若确认加密,常规做法是从运行中的进程内存里 dump 解密后的 metadata:用调试器附加游戏进程,在
il2cpp::metadata::Init或类似初始化函数处下断,待命中后定位内存中的 metadata 区域并导出。 - 拿到 dump 出的 metadata 后,配合强制版本参数重新解析:
{ "ForceIl2CppVersion": true, "ForceVersion": 24.3, "ForceDump": true }原理点睛:metadata 是纯静态数据,运行时会被整体加载到内存;只要游戏自己能读取,内存中就必然存在一份"已解密"的副本。dump 方案利用的正是这个事实。ForceVersion的作用是绕过版本自动探测——某些 Unity 版本的二进制结构与元数据版本号并不一一对应,手工指定可跳过错误分支。
报错二:Can't use auto mode to process file, try manual mode
自动模式需要在二进制中搜索CodeRegistration与MetadataRegistration两个关键结构,搜不到就会退回手动输入。常见原因有两个:文件被加壳导致特征被抹掉,或是 PC 平台的文件名并非libil2cpp.so而是GameAssembly.dll。
排查路径:
- 确认你喂给程序的是正确平台的文件:Android 是
libil2cpp.so(ELF),PC 是GameAssembly.dll(PE)。 - 若确认无误仍报错,多半是加壳保护。此时改用内存 dump 的
libil2cpp.so重新解析。 - 手动模式兜底:程序会提示输入
CodeRegistration和MetadataRegistration的十六进制地址,需要你结合反汇编器自行定位这两个结构,属于较高阶操作。
原理点睛:自动模式本质是"特征扫描"——在可执行文件里寻找符合 IL2CPP 初始化结构布局的内存片段。加壳或代码混淆会破坏这些特征,导致扫描失效;而内存中的镜像已经过脱壳和解压,特征完整,这就是"dump 大法"能绕过大多数保护的根本原因。
报错三:Il2Cpp file not supported
程序按文件头魔数识别格式(ELF、Mach-O、PE、NSO、WASM),认不出来就会抛出此错。排查时先确认文件确实属于以上五种格式之一,再检查是否被压缩或加壳。
原理点睛:文件头的前几个字节决定了解析器分支,例如 ELF64 以0x464c457f开头且第 5 个字节为2,NSO 以0x304F534E开头。识别失败通常是文件本身已被保护处理,而非程序缺陷。
高手技巧:让反汇编器听懂你的类型
导入类型信息:在 IDA 中打开还原出的script.json与il2cpp.h,执行项目自带的 ida_with_struct.py,脚本会批量完成三件事:按Addresses列表切分函数边界、把ScriptMethod中的方法名重命名到对应地址、把方法签名套用到函数上。执行完成后,原本满屏的sub_123456会变成PlayerController_Update_xxx这样可读的调用。
Ghidra 用户则运行 ghidra_with_struct.py,Binary Ninja 用户加载Il2CppBinaryNinja/目录下的插件,原理一致:先用il2cpp.h建立结构体类型库,再按script.json的地址映射批量标注。
批量自动化:对于需要反复分析多个版本的游戏,可以写一个简单的脚本串联全流程——解压 APK → 定位文件 → 调用Il2CppDumper命令行 → 用 dnSpy 的脚本接口导出关键类清单。项目中的 Utils/Il2CppExecutor.cs 提供了程序化调用入口,适合在二次开发中直接复用。
避坑指南
⚠️误区一:以为 DummyDll 里能看到完整逻辑。DummyDll 只有类型骨架,方法体是空的。正确的分析姿势是:用 DummyDll 定位类与字段,再用dump.cs里的 RVA 注释到反汇编器中找到真实函数,两者配合使用。
⚠️误区二:忽略平台差异。iOS 是 Mach-O、Android 是 ELF、PC 是 PE,三种格式的解析路径完全不同。把 iOS 的二进制喂给针对 ELF 的流程,第一步就会失败。遇到"文件不支持"先检查平台是否匹配。
⚠️误区三:上来就分析加壳文件。商业游戏的libil2cpp.so十有八九加了壳,直接解析必然失败。先判断是否被保护,必要时从内存 dump,再交给 Il2CppDumper,而不是反复重试同样的命令。
总结:比工具更重要的是三种思维
回看整条链路,真正支撑你走完全程的是三个底层认知:元数据是逆向的锚点——类型信息永远在 metadata 里,理解了它的结构,加密与否只是多一步解密的差别;地址映射是分析的桥梁——dump.cs里的 RVA 注释就是连接 C# 层与汇编层的坐标轴,顺着它走就不会迷路;运行时镜像是最诚实的样本——保护手段能藏起磁盘文件,却藏不住内存中的真相。
最后提醒一句:逆向分析请在合法合规的前提下进行,确保你的分析对象和使用方式符合软件授权条款与所在地区法律法规。工具是中立的能力放大器,如何使用,取决于你的选择。
【免费下载链接】Il2CppDumperUnity il2cpp reverse engineer项目地址: https://gitcode.com/gh_mirrors/il/Il2CppDumper
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考