Unity IL2CPP逆向利器:Il2CppDumper实战详解
2026/9/7 3:24:23 网站建设 项目流程

简介:面向Unity游戏逆向与安全分析者的专业工具包,适用于还原IL2CPP打包生成的DLL元数据,并提取MonoBehaviour与MonoScript组件信息。支持ELF、Mach-O、PE、NSO、WASM等多种执行格式,覆盖Unity 5.3至2020版本,同时可从内存转储的libil2cpp库中恢复数据,以绕过简单加固,是中高级逆向工程师处理混淆或加密方案的实用选择。压缩包内共11个文件,包括8个Python脚本、2个Windows可执行程序及1个JSON配置。脚本面向IDA与Ghidra联动场景,可自动生成结构体头文件;exe主程序则快速完成DLL还原,压缩后大小仅10.7MB。JSON配置文件支持自定义输出选项,便于批量处理或集成到工作流。目前已有1022人学习下载,社区接受度较好。借助该工具,可直接获得IDA与Ghidra调用的辅助脚本,避免手工分析元数据;输出结构体定义后,能更高效定位关键逻辑、序列化字段及MonoBehaviour挂载关系,显著减少Unity游戏逆向中的重复劳动,兼顾效率与便利,适合个人研究与团队自动化分析流程。

1. 项目概述:Il2CppDumper 解决的“黑盒”问题

玩 Unity 游戏逆向的朋友,对这个名字应该都不陌生。Il2CppDumper 是一个专门用于解析 Unity IL2CPP 运行时二进制文件的工具,它能从游戏包体里提取出类、方法、字段、属性、接口等完整的元数据,并输出成可读的 C# 结构定义文件。简单说,它就是一把钥匙,帮你打开 IL2CPP 这扇紧闭的大门。我这次用的是 win-v6.7.46 这个 Windows 版本,在 Windows 10/11 环境下开箱即用,不需要装额外的运行时环境。

想明白它为什么这么重要,得先知道 Unity IL2CPP 是什么。老一代 Unity 游戏走的是 Mono 虚拟机,脚本编译成 IL 中间语言,打包后很容易用 dnSpy 直接反编译成可读的 C# 源码。后来 Unity 官方为了性能和防破解,推出了 IL2CPP:把 C# 代码先编译成 IL,再转换成 C++ 源码,最后编译成原生机器码。这样一来,游戏运行时不依赖 Mono 虚拟机,执行效率大幅提升,反编译的难度也直线上升。但代价是,代码里的类型信息不再以明文形式躺在 DLL 里,而是被塞进了一个二进制元数据文件——global-metadata.dat。Il2CppDumper 干的事,就是把这个 dat 文件和对应的 native 库凑在一起,把散落的元数据重新拼装成完整结构。

我最早接触这个工具是在分析 App 逆向案例的时候,当时拿到的 APK 里全是 libil2cpp.so 和 global-metadata.dat,用传统反编译器打开,完全是一堆地址和无意义的指令。直到用了 Il2CppDumper,五分钟内就看到完整的类名、方法签名、字段偏移,那种从黑盒到透明的感觉,确实很提气。v6.7.46 这个版本算是比较新的稳定版,处理 Unity 2020~2023 的项目都没啥压力,特别是对高版本 Unity 的 metadata 版本支持比老版好了很多。如果你手里正好有需要分析的 IL2CPP 包,这篇文章可以帮你少踩不少坑。

2. 核心原理:它是怎么把数据“缝合”起来的

2.1 两份关键文件的分工

要理解 Il2CppDumper 的工作逻辑,必须搞清楚 IL2CPP 在打包后留下了哪两份关键文件。第一份是 native 库,在 Android 上是 libil2cpp.so,在 iOS 上是 libil2cpp.a 或拆出来的二进制,在 Windows 游戏里可能是 GameAssembly.dll。这份文件里包含了所有方法编译后的机器码、全局字符串、以及一些运行时需要的结构定义。第二份是 global-metadata.dat,它存了几乎全部的托管元数据——类型表、方法表、字段表、字符串表,以及它们之间的引用关系。但这份数据本身是加密或者混淆过的,没法直接读。

Il2CppDumper 的思路是:从 native 库中寻找 IL2CPP 运行时内部的结构特征,比如一些关键函数指针、全局变量的地址、以及某些固定字符串(比如 "Unity" 相关的运行时标记),通过这些“锚点”确定 metadata 在内存中的解析方式。然后再用 metadata 文件里的索引表和偏移表,把类型信息一条条还原出来。整个过程很像考古:你有一堆碎陶片(metadata),还有一本残缺的文献(native 库),工具根据文献里描述的器型,把陶片拼回原来的样子。

2.2 从二进制到 dump.cs 的转变

用工具跑完后,你会得到几个关键输出。最常见的是 dump.cs,里面是按命名空间组织的类定义,包含类继承关系、字段声明、方法签名、属性的 getter/setter,甚至还包括虚表偏移和字段内存偏移。还有 script.json,是把所有信息以 JSON 格式结构化输出,适合程序化处理。另外还会生成若干 .h 文件,用于在 C++ 侧直接定位某个类或方法的内存地址。这套输出组合基本覆盖了从静态分析到动态调试的全部需求。

需要注意的是,Il2CppDumper 不是万能的。它依赖 native 库中未加密的符号特征,如果开发者在打包时做了深度混淆,或者用了一些商业保护壳,工具可能只能还原出一部分类型,甚至完全失败。所以要理性看待它的输出。我在实际使用中,遇到过某些美团加固过的包,需要在内存中 dump 出解密后的 metadata 再喂给工具,才能成功。

3. 实操过程:win-v6.7.46 在 Windows 上的完整跑法

3.1 运行前的准备工作

在 Windows 上使用这个版本,你只需要准备三样东西:Il2CppDumper 解压后的文件夹、目标 APP 的 native 库文件、以及对应的 global-metadata.dat。native 库怎么拿?Android 的话,解包 APK 后在 lib/armeabi-v7a 或 lib/arm64-v8a 目录下能找到;iOS 的话,越狱机上可以从 App 沙盒里拷贝;Windows 游戏则是在游戏安装目录里找 GameAssembly.dll。metadata 文件通常在 APK 的 assets/bin/Data/Managed/Metadata 目录下,iOS 和 Windows 也类似,位置可能会有变化。

注意架构要匹配。如果 native 库是 32 位,metadata 一般对应一套数据;如果是 64 位,又是另一套。实际包体可能同时包含两种架构,最好选择你目标设备的架构,否则即使跑通了,后面动态调试时地址对不上,白忙一场。我一般用 ARM64 版本,因为现在主流设备都是 64 位。

3.2 命令行执行与模式选择

win-v6.7.46 启动后有两种玩法:图形界面和命令行。双击 Il2CppDumper.exe 会进入一个简单的 GUI,让你选择 libil2cpp.so 文件、global-metadata.dat 文件以及输出目录,点一下 Run 就完事。但更推荐命令行方式,因为可以嵌入到自动化流程里。在 CMD 或 PowerShell 中执行:

Il2CppDumper.exe <libil2cpp路径> <global-metadata路径> <输出目录>

注意路径不要有中文和空格,否则偶尔会出奇怪的解析问题。执行后工具会先尝试从 native 库中匹配特征,然后读取 metadata,在还原过程中会打印很多调试信息,包括检测到的 Unity 版本、metadata 版本等。如果一切顺利,最后会输出 "Done!" 字样,并在输出目录生成 dump.cs、script.json 和若干头文件。

这里有个小技巧:当我遇到某些加了变种保护的包,直接在命令行跑会失败。这时候可以用交互模式,在 GUI 里选择“手动模式”,工具会让你输入一些关键函数的偏移地址,这些地址要从另一个叫 Il2CppInspector 的工具辅助获取。不过手动模式对新手不太友好,建议先用默认自动模式,失败再上手动。

3.3 关键输出文件的阅读方法

拿到 dump.cs 后,第一件事不是从头到尾读,而是先搜索关键词。比如想知道某个类有哪些字段,直接在 dump.cs 里搜类名;想知道某个方法内部逻辑,先搜到方法名,拿到 offset,然后在 IDA/Ghidra 里跳转到对应地址。dump.cs 里的每个类型前面都带着一堆偏移信息,对动态调试非常有用。

举个例子,我之前分析一个 Unity 游戏的角色属性,dump.cs 里能看到 PlayerData 类有个字段 m_health,偏移是 0x24。然后在 Cheat Engine 里搜索角色血量值,找到地址后加上偏移,就能直接定位到金币、经验等其他属性。如果没有 Il2CppDumper,完全靠硬翻汇编找偏移,工作量至少翻五倍。

script.json 也值得好好利用。它把数据组织成树状结构,包含每个类的基类、接口、字段类型、方法参数和返回类型。写自动化脚本时,用 Python 的 json 模块解析它,可以批量生成结构体定义,或者批量查某个方法的地址。对比下来,dump.cs 适合人看,script.json 适合程序读。

3.4 与 IDA/Ghidra 联动的常规套路

拿到偏移后,最常用的操作就是把它喂给反编译器。比如在 IDA 里加载 libil2cpp.so,按 G 键输入 dump.cs 里某个方法的 Offset(注意加基址或按实际情况调整),就能直接跳转到这个方法对应的汇编代码处。配合 IDA 的 python 插件,还能把 Il2CppDumper 生成的 script.json 里的类型信息导入到 IDA 的本地类型窗口,变量名和结构体都会自动识别。

我自己习惯用 Ghidra,因为免费。流程是:用 Ghidra 的 Loader 加载 libil2cpp.so,等自动分析完,再把 Il2CppDumper 生成的头文件(.h)通过 File -> Parse C Source 导入,这样函数签名和结构体就能批量恢复。整个过程不需要手工整理,非常适合大项目。不过 Ghidra 分析速度比 IDA 慢,如果你的机器内存不够,建议用 IDA 64 位。

4. 常见问题与排查技巧实录

4.1 metadata 版本太新导致解析失败

这是最常遇到的情况。Unity 每个版本都可能调整 metadata 的格式,Il2CppDumper 的更新就是跟着新版本补特征库。如果你下载的是老版本,遇到新版的 global-metadata.dat,工具可能会提示 “ERROR: Can't find metadata header” 或者直接崩溃。解决办法很简单,下载最新的 Il2CppDumper 版本。像 v6.7.46 支持到 Unity 2023.2 附近,如果遇到 Unity 2024 的包,可能就要等更新了。

这背后的原理是,global-metadata.dat 的头部有一个 magic number 和版本号,Il2CppDumper 会先检查版本号并选择对应的解析结构体。当解析器不认识这个版本时,就只能放弃。所以你可以在报错信息里看到它读到的版本号,再去 GitHub 上核对是否有对应支持。我个人的经验是,不是在最新版的 Unity 上,提前用老工具也问题不大,但最稳妥的还是保持工具更新。

4.2 加密和加固后的 metadata 处理

很多商业应用会给 metadata 加密。典型表现是用工具打开时,dump.cs 里全是乱码或者只有空的类名,运行时才会在内存中解密出真正的数据。这时候离线文件是没法直接解析的。常用的思路是转储内存:先让 App 跑起来,等 metadata 被解密后,用 Frida 或 GameGuardian 从内存中把解密后的 global-metadata.dat 抠出来,再喂给 Il2CppDumper。

用 Frida 时,一般 hook 原生层中读取 metadata 的函数,把解析后的内存段抓下来。不过这个操作需要一点逆向基础,如果你暂时不会写 hook,可以先尝试用 Il2CppDumper 的 GUI 文件附带的 test 里有没有对应版本的解密脚本。我自己实操中,用 frida 脚本 dump 内存里的 metadata,再结合 Il2CppDumper 成功解析出不少加了壳的游戏。也有很多人把 dump 出的文件起名成 global-metadata.dat.bak,作为备份。

4.3 方法和字段缺失的原因与应对

就算工具跑通了,dump.cs 里也经常会出现缺失某几个方法的情况。原因多半是这些方法被编译成 internal 调用后,没有注册进 metadata,或者被裁剪掉了。遇到这种情况,不要急着怀疑工具坏了,先试试用 Il2CppInspector 交叉验证,它能通过更底层的方式扫描代码段,偶尔能补出 Il2CppDumper 漏掉的方法。

另外,现代 Unity 可能会启用“IL2CPP 裁剪”(Managed Stripping Level)。当裁剪级别设置为 High 时,未被引用的类和成员可能在编译期就被删除,最终不会出现在 metadata 里。这意味着你用 Il2CppDumper 看到的并不是完整的底层世界,而是裁剪后的“官方视角”。想验证是否有裁剪,可以看 App 包体的大小,如果比同类型游戏小很多,多半裁得厉害。

4.4 一个容易忽略的字节对齐问题

我在 64 位包上遇到过几次解析出来的偏移整体偏小几字节的情况。后来发现是 metadata 文件在打包时被做了特殊处理,去掉了对齐填充。Il2CppDumper 在解析时默认按照原始的字节对齐规则计算偏移,但实际文件的对齐方式已经被破坏,导致后续字段偏移全部错位。这个问题最典型的特征是 dump.cs 里的类名能对,但字段个数明显少于运行时实例中实际存在的字段。

解决方法是自己在解析前对文件做一次对齐修复。简单粗暴的做法是找一段已知的字符串引用,在 Hex 编辑器里对比,手动调整文件头部某些偏移字段,直到符合预期。如果不想这么折腾,可以试试新版工具提供的 “force alignment” 参数,有时能直接绕过。不过这属于比较进阶的场景,新手遇到了可以先放着,等熟悉文件结构后再深挖。

5. 工作流里最值得记住的几条经验

用 Il2CppDumper 多了之后,我总结了一套比较顺手的流程:先准备干净的包体,优先从 APK 里解出 ARM64 的 libil2cpp.so 和同名 metadata;然后命令行跑一遍,把 dump.cs 和 script.json 保存好;接着用 IDA 或 Ghidra 加载 binary,导入 script.json;最后结合运行时的内存验证偏移对不对。这套流程下来,绝大多数 Unity IL2CPP 项目的结构分析都能在两小时内完成。

工具本身很简单,但真正影响效率的是对 Unity 构建体系的理解。很多人卡住,不是因为工具不会用,而是不知道 metadata 在哪、架构选哪个、或者版本不匹配。遇到报错别慌,先看工具输出的日志,日志里通常写着版本号和失败原因,再对症下药。比起盲目换工具,理解它的工作原理才是解决问题的根本。

还有一个心得:任何时候都把原始文件备份好。Il2CppDumper 虽然设计得挺健壮,但在读取某些畸形文件时也可能崩溃。备份能让你在反复试验时快速复位。顺便说一句,跑完后的 dump.cs 如果太大(几十 MB),用 VS Code 打开比记事本流畅得多,搜索定位也方便。

6. 扩展:从 dump 到动态调试的衔接技巧

很多朋友拿到 dump.cs 之后,就不知道怎么继续了。其实这一步才是真正发挥价值的开始。以最常见的内存修改为例:你从 dump.cs 里看到某个类某个字段的偏移,接下来要做的是运行时拿到这个类实例的地址。方法不外乎两种,第一种是搜索特征值,比如角色的血量是 100,在 CE 里搜 100,过滤几次找到地址,然后用计算器把地址减去偏移,就能得到对象基址。第二种是 hook 某方法,在游戏调用这个方法时,从参数里直接拿到 this 指针。

hook 方法的方式有很多,老牌的 Frida 对 Android 很友好。比如这个类叫 PlayerData,方法叫 setHealth,它的偏移是 0x123456。在 Frida 里可以用 Interceptor.attach 到这个偏移加上基址,然后读取参数。这类操作在游戏“做 MOD”时特别常用。有些人喜欢用 Python 脚本半自动收集 dump.cs 里的方法地址,生成一个 JSON 映射,方便 Frida 直接读取。这个思路我一直在用,省事很多。

不过要强调的是,做这些事的目的是为了学习、安全研究或者给单机游戏做 MOD。对在线游戏或者他人开发的商业作品,一定要遵守当地法规和用户协议。技术本身没有对错,关键是怎么用,我自己只会在自己的测试设备上折腾,绝不去碰有违规风险的东西。

回到工具本身,Il2CppDumper 这个系列更新到现在,已经相当成熟。win-v6.7.46 这个版本无论是稳定性还是对主流 Unity 版本的支持都让人满意。如果你正打算入坑 Unity 逆向,建议从它开始,配合 IDA(或 Ghidra)练习,把整个流程跑通,再逐步深入。遇到问题多看看日志,多翻翻 GitHub 上的 issue,大部分答案都在那里。

最后分享一个我自己的小习惯:我不会一次性把整个 dump.cs 读完,而是先看命名空间列表,然后挑几个核心模块分析。游戏逻辑一般都在 Assembly-CSharp 对应的那一块,其他都是 Unity 引擎自带代码,除非研究引擎细节,否则可以先忽略。这种抓重点的方式,比对着几千个类发呆要高效得多。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询