ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Unity IL2CPP逆向利器:Il2CppDumper实战详解

Unity IL2CPP逆向利器:Il2CppDumper实战详解 简介面向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: Cant 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 引擎自带代码除非研究引擎细节否则可以先忽略。这种抓重点的方式比对着几千个类发呆要高效得多。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进