Il2CppDumper入门到进阶:3个阶段拆解Unity IL2CPP逆向黑盒
【免费下载链接】Il2CppDumperUnity il2cpp reverse engineer项目地址: https://gitcode.com/gh_mirrors/il/Il2CppDumper
先把问题摆到桌面上
很多做Unity游戏分析的朋友都遇到过同一种困惑:安装包里翻来翻去,就是找不到熟悉的Assembly-CSharp.dll;把libil2cpp.so拖进反编译工具,满屏都是看不懂的机器码;好不容易拿到global-metadata.dat,解析时又被一句"文件无效"直接劝退。
这些症状其实指向同一个病根:Unity的IL2CPP编译模式。你可以把它想象成一次"翻译+打包"的过程——C#代码先被翻译成C++,再被编译成原生机器码,而所有类型信息被单独塞进了一个叫global-metadata.dat的"档案袋"里。于是,你手里只剩下一堆代码(二进制)和一份目录(元数据),两者缺一不可,却都不直接可读。
本篇文章不打算堆砌术语,而是用三个阶段带你把整个流程走通:先搞懂要准备什么,再亲手跑通第一次解析,最后学会排查报错和进阶玩法。读完你就能用Il2CppDumper把"黑盒"拆成一份看得懂的"图纸"。
阶段一:开工前的两样必需品
为什么要凑齐两个文件
Il2CppDumper的工作原理可以概括成一句话:一个负责给代码"对上号",一个负责给名字"补齐"。单靠任何一个文件都无法还原出完整的类型结构。
- libil2cpp.so(或其他平台的等价物):这是IL2CPP编译出的原生二进制,包含实际逻辑,但函数名、类型名都被"抹掉"了。
- global-metadata.dat:这是元数据文件,相当于整座建筑的"结构图纸",里面记录了类名、方法签名、字段布局等信息。
你可能会问:把两个文件放在一起,工具怎么知道谁是谁?答案在文件头部——Il2CppDumper会先检查元数据文件头部的特殊标记,确认"这确实是我们要找的档案袋",再去二进制里找对应的数据结构。这个检查逻辑就写在项目的Il2Cpp/Metadata.cs中,感兴趣的话可以翻源码看看那个熟悉的0xFAB11BAF标记。
不同平台的"等价物"要认清
注意,可执行文件的名字会因为平台不同而变化,千万别找错:
- Android平台:通常位于APK解包后的
lib/arm64-v8a/目录下,文件名是libil2cpp.so - Windows平台:不是
.so,而是GameAssembly.dll或*Assembly.dll - iOS平台:对应Mach-O格式的二进制
- 部分游戏机或特殊场景:还可能是NSO或WASM格式
元数据文件的名字倒是比较统一,多数叫global-metadata.dat,通常放在assets目录下。如果你解包APK时发现它不见了,很可能被藏进了其他路径或做了混淆。
获取Il2CppDumper
获取工具很简单,直接克隆项目仓库即可:
git clone https://gitcode.com/gh_mirrors/il/Il2CppDumper克隆下来后,项目里包含了完整源码、示例脚本和配置文件。如果你只是想要现成的可执行文件,也可以关注项目的持续集成产物,或者用Visual Studio等工具自行编译Il2CppDumper.csproj。另外别忘了看一眼README.zh-CN.md,里面有官方给出的功能清单和使用说明,遇到疑问先查这里。
阶段二:跑通你的第一次解析
第一步:解包拿到原始文件
假设你手头有一个Android平台的APK,需要先用压缩工具解开它(7-Zip、WinRAR都行):
# 解压APK文件 7z x game.apk -oextracted_apk解压完成后,定位两个关键文件:
cd extracted_apk/lib/arm64-v8a/ ls libil2cpp.so cd ../../assets/bin/Data/ ls global-metadata.dat把这两个文件复制到一个独立的目录里,方便后面操作。顺带提醒一句:如果APK本身被加固,解压出来的libil2cpp.so可能是壳文件,真正的代码要到后面"进阶"章节再处理。
第二步:两种启动方式任选
Il2CppDumper支持两种用法,新手建议先从图形界面入手:
- 图形界面模式:直接运行程序,会弹出文件选择对话框,依次选中
libil2cpp.so和global-metadata.dat,按提示操作即可。整个过程不需要记任何命令。 - 命令行模式:适合脚本化和批量处理,格式非常固定:
Il2CppDumper.exe <可执行文件> <元数据文件> <输出目录>例如:
Il2CppDumper.exe libil2cpp.so global-metadata.dat output程序跑完后,所有结果会生成到你指定的输出目录里。
第三步:理解输出目录里有什么
我第一次跑完程序时,看着满屏文件也有点懵。别急,输出内容其实可以分成四类:
DummyDll文件夹:这是最直观的成果,里面是一堆还原出来的DLL文件。注意它们只是"骨架",只包含类型信息、方法签名和字段定义,没有方法体逻辑。用dnSpy或ILSpy打开,就能像浏览普通C#项目一样,在左侧导航树里查看命名空间、类和成员。想找某个关键类(比如控制角色逻辑的PlayerController),直接用搜索功能即可。
dump.cs:一份纯文本的类结构清单,适合快速检索类型名、字段偏移量和方法地址。
script.json:这是给IDA和Ghidra准备的"翻译对照表",把每个方法地址和它的原始名字一一对应起来。
il2cpp.h:包含结构体定义的头文件,配合IDA的脚本使用,能让反汇编代码瞬间"有名字"。
另外还有stringliteral.json(包含所有字符串字面量信息)和给BinaryNinja准备的脚本等,按需使用即可。
第四步:学会调整config.json
程序目录下有一个config.json配置文件,它决定了输出内容的"瘦身程度"。几个常用开关:
GenerateDummyDll:是否生成DummyDll文件夹,默认开启DumpMethod、DumpField、DumpProperty、DumpAttribute:控制dump.cs中要输出哪些内容DummyDllAddToken:是否在DummyDll中附加token信息RequireAnyKey:程序结束时是否需要按任意键退出(批量运行时建议关掉)
我自己的习惯是:日常分析保持默认配置,只有遇到超大项目、输出文件过多时才考虑关闭部分开关。完整的配置项说明都在README.zh-CN.md的"关于config.json"一节里。
阶段三:高频报错逐个击破
跑通一次不难,难的是面对各种报错不慌。这里把我见过的最高频的几个问题整理出来,你遇到时直接对号入座。
报错一:Metadata file supplied is not valid metadata file
这是出镜率最高的一条。它的意思是:Il2CppDumper读文件头部时,没找到预期的标记,也就是说这个global-metadata.dat被加密或修改过了。
遇到这种情况,先别急着跟它死磕。几个方向供参考:
- 确认文件来源是否完整,是不是解包时出了问题
- 如果确定被加密,那就需要从运行时的内存中"抢救"真实数据——用调试器或内存dump工具,在游戏运行时把解密后的元数据抓出来
- 抓到内存dump后,把
config.json里的ForceDump改为true,强制把文件当作dump处理
你可能会问:dump出来的文件就能直接解析吗?大部分情况下可以,但要注意个别设备dump出的文件指针状态特殊,如果解析仍有异常,试试把NoRedirectedPointer改为true。
报错二:This file may be protected
这条提示说明可执行文件本身被加壳保护了,直接从安装包里拿到的libil2cpp.so是"空的壳",真正的代码在运行后才被加载进内存。
对付加壳的思路核心就四个字:内存dump。用调试器附加到游戏进程,等壳解完、真实代码加载进内存之后,把内存里的libil2cpp.so整个dump出来,再用Il2CppDumper分析这份"热乎"的文件。这个技巧能绕过大多数保护方案。
报错三:Can't use auto mode to process file
自动模式解析失败时,程序会提示这条信息。最常见的原因是你给错了文件——比如在Windows平台上传了.so文件,而实际应该用GameAssembly.dll。先检查文件格式是否与平台匹配,再考虑换用手动模式。
版本相关的坑:IL2CPP版本不一致
Unity版本跨度大,IL2CPP的内部格式也在不断变化。Il2CppDumper本身支持较广的版本范围,但如果你拿到的文件来自很老的Unity版本,可以尝试在config.json中启用ForceIl2CppVersion并指定ForceVersion,强制按某个版本解析。判断版本的一个简单方法是看元数据文件头部记录的版本号——想知道具体判断逻辑,可以去源码Il2Cpp/Metadata.cs里翻翻版本校验那段。
进阶玩法:让反汇编工具"看懂"代码
给IDA/Ghidra灌入类型信息
前面提到的script.json和il2cpp.h,到这里终于派上用场了。项目仓库里已经准备好了现成的脚本:
ida.py:把方法名、字符串等信息导入IDAida_with_struct.py:在导入信息的同时,把il2cpp.h里的结构体定义也应用进去ghidra.py:对应Ghidra的导入脚本
以IDA为例,大致流程是:先用IDA加载libil2cpp.so,然后在脚本窗口运行ida_with_struct.py,选择输出目录里的script.json。导入完成后,你会发现原本满屏的无名函数,全部变成了带有可读名称的调用,结构体成员也有了名字。这个体验上的变化,用"从黑屏到白天"来形容都不夸张。
用Il2CppExecutor做程序化集成
如果你需要批量分析多个游戏,或者想把解析流程嵌入自己的工具链,可以看看项目里的Utils/Il2CppExecutor.cs。它把"读取元数据→解析二进制→生成结果"的核心流程封装成了可调用的类,相当于给开发者留了一扇"编程入口"。配合Python脚本实现APK自动解包、批量调用命令行、再用dnSpy脚本导出关键类信息,一条自动化逆向流水线就成型了。
当然,自动化属于进阶话题,新手阶段先把单个游戏的流程跑顺,再考虑规模化也不迟。
三个容易踩的思维误区
误区一:以为DummyDll里有完整逻辑。DummyDll只有类型信息,没有方法实现。想要看逻辑,得结合原生二进制的反汇编结果一起分析。它更像一张"地图",而不是"实景"。
误区二:忽视平台差异。同样的流程,换一个平台就要换对应的可执行文件格式,ELF、Mach-O、PE各有各的规矩。配置文件里相关的架构参数也要对得上,否则解析会失败。
误区三:直接解析加壳文件。加壳是商业游戏最常见的保护手段,跳过脱壳直接解析,报错几乎是必然的。先确认文件是否干净,再动手。
写在最后:能力越大,责任越大
到这里,你已经具备了处理大多数IL2CPP逆向场景的完整能力:认文件、跑解析、看结果、排报错、上脚本。如果哪一步卡住了,优先回到项目的README.zh-CN.md、config.json说明和源码(尤其是Il2Cpp/Metadata.cs与Il2Cpp/MetadataClass.cs)里找答案,它们比任何教程都权威。
最后提醒一句:逆向分析工具本身是中性的,但使用场景必须合规。请确保你的分析行为符合软件的使用条款和相关法律法规,只对你有权分析的目标下手。技术是用来探索和学习的,别让它变成麻烦的源头。
【免费下载链接】Il2CppDumperUnity il2cpp reverse engineer项目地址: https://gitcode.com/gh_mirrors/il/Il2CppDumper
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考