Unity IL2CPP逆向实战:用Il2CppDumper还原dump.cs与桩DLL
2026/9/8 14:28:10 网站建设 项目流程

简介:Il2CppDumper-win-v6.7.46 是一款面向 Unity 逆向工程与游戏安全分析场景的元数据还原工具,核心目标是帮助分析人员从 il2cpp 二进制中还原动态链接库结构信息(不包含代码),进而定位 MonoBehaviour 与 MonoScript 类,为后续静态分析打下基础。工具覆盖范围广,支持 ELF、Mach-O、PE、NSO 和 WASM 等主流可执行格式,兼容 Unity 5.3 至 2020 版本,还可读取内存转储得到的 libil2cpp.so 文件来绕过保护,并能处理带简单保护壳的 PE 文件。压缩包共 11 个文件、约 10.7 兆字节,由两个 Windows 可执行程序、八个 Python 脚本以及一个 JSON 配置组成;脚本主要用于生成带结构体信息的 IDA/Ghidra 助手脚本、导出结构体头文件以及补充 wasm 分析能力,可以显著减少人工逆向的重复操作。目前已有 1022 人学习下载,适合逆向工程师、CTF 选手及游戏安全研究者用于 Unity 游戏逻辑还原与工具链整合。 拿到一个Unity游戏包,本想着跟以前一样把Assembly-CSharp.dll丢进dnSpy里慢慢看逻辑,结果解包出来的却是一个几百MB的native二进制文件和一个叫global-metadata.dat的东西,没有以往那些热乎的托管DLL。相信不少刚接触Unity逆向的朋友都在这一步卡过。没错,这就是IL2CPP打包方式的典型特征。而这次要聊的 Il2CppDumper-win-v6.7.46,就是绕开这个坎的关键工具,它的作用是在没有托管DLL的情况下,把GameAssembly.dll(Windows平台)或libil2cpp.so(Android平台)配合global-metadata.dat,重新还原出结构清晰的dump.cs和一堆可浏览的桩DLL文件。

这篇文章会把这套东西掰开揉碎:从为什么Unity会产出这种"二进制+元数据"的组合讲起,再带你把原理、实操、踩坑、进阶使用整个流程走一遍。适合正在做Unity游戏功能分析、安全研究、Mod开发,或者单纯被IL2CPP搞得头大的同学参考。

1. 为什么Unity游戏会变成"二进制+元数据"两个文件

1.1 Mono时代:托管DLL随处可见的日子

早年的Unity默认走Mono虚拟机,C#代码编译成IL中间语言,打包后就是一个一个的托管DLL,其中游戏主逻辑通常叫Assembly-CSharp.dll。这种DLL是标准.NET程序集,直接用dnSpy、ILSpy这些工具就能打开,类名、方法名、甚至整个反编译源码都能看。对逆向来说,那几乎是"开卷考试"。

也正是因为太开卷,游戏厂商越来越不爽——你辛辛苦苦写的算法、客户端校验逻辑、资源加密规则,全被人一把梭翻个底朝天。再加上Mono的GC和JIT在某些平台确实有性能瓶颈,IL2CPP就这么变成了大厂和加密需求强的游戏的主流选择。

1.2 IL2CPP的编译链路:C#到C++再到机器码

IL2CPP的字面意思就是"IL to C++"。Unity在打包时先把C#源码编译成标准IL,然后IL2CPP把IL转成C++源码,最后再由各平台的C++编译器把这一大坨C++编成原生机器码。

这就导致一个结果:最终产物里根本没有托管DLL,你拿到的是一个纯native二进制——Windows上是GameAssembly.dll,Android上是libil2cpp.so。里面是真实的机器指令,想看逻辑可以,但直接想还原出类结构、方法名,难如登天。

1.3 元数据的意义:没有姓名的代码等于一堆乱码

仅仅有native代码还不够,游戏运行的时候总要知道"有哪些类、类的字段怎么排、每个方法什么签名"。这部分信息被单独抽出来,放在了global-metadata.dat里。它保存了类型定义、方法签名、字段偏移、字符串字面量等"元数据",相当于整份代码的目录和索引。

于是出现了这个现象:Unity IL2CPP游戏的关键信息被拆分成了两份——

文件内容能否直接看出逻辑
GameAssembly.dll / libil2cpp.soIL2CPP生成的C++再编译出的native指令看不出类和方法名,只有一堆地址
global-metadata.dat类型、方法、字段、字符串等元信息结构齐全,但没有代码实现
Assembly-CSharp.dll(如有)残留的托管程序集有些游戏没清干净,但通常不再包含核心逻辑

这两者必须配合使用:二进制提供代码实现,metadata提供代码的身份信息。Il2CppDumper做的就是把这个配合关系重新建立起来,让你能对着地址谈方法名,而不是面对一堵二进制墙。

2. 它的工作原理解析:metadata到底是"字典"还是"正文"

2.1 一个不太恰当但很好懂的类比

你可以把GameAssembly.dll想象成一本只有正文、没有目录、而且所有词句都涂掉了姓氏的书,global-metadata.dat则是这本书的目录和索引手册。运行的时候,游戏靠索引去正文里找到对应的实现;Il2CppDumper拿到这两样东西之后,做的事情就是:解析索引手册,把每一个词条和正文里的具体位置对应起来,然后生成一份新的、部件齐全的档案——dump.cs。

所以有件事要提前搞清楚:dump.cs不是反编译器吐出来的C#源码,它是一份完整的结构声明文件,包含命名空间、类、字段(带偏移量)、方法声明(带地址或偏移),但方法体仍然是native机器码,不会自动变回C#逻辑。想继续分析逻辑,得拿着这份dump.cs去IDA或者Ghidra里对着找。

2.2 Il2CppDumper具体做了什么

IL2CPP运行时在启动时需要通过一些关键符号来初始化元数据,比如Il2CppCodeRegistration、Il2CppMetadataRegistration这类结构体指针。这些符号在导出的二进制里往往有迹可循,哪怕被strip过符号,某些字符串引用或者初始化函数的特征仍然能暴露出来。

Il2CppDumper的工作流程大致是:

  1. 读取global-metadata.dat,按版本解析出类型定义、字段、方法、字符串池等数据块;
  2. 扫描目标二进制(so或GameAssembly.dll),定位IL2CPP运行时的关键注册结构,从中拿到方法指针表、虚方法表等运行时信息;
  3. 把metadata里的方法索引和二进制里的方法地址一一对应,生成包含地址与签名的映射表;
  4. 最后输出:dump.cs(完整结构声明)、script.json(结构化数据)、DLL文件夹(一堆用于静态分析的桩DLL)。

2.3 为什么生成的是"桩DLL"而不是直接还原逻辑

很多人第一次看到输出目录里的DLL,以为直接拖进dnSpy就能看代码了,结果打开发现只有类声明、空方法体,大呼"就这?"。对,就这。这些DLL本质上是补全了签名信息的空壳程序集,作用不是反编译,而是让dnSpy、ILSpy这类工具能正常浏览类和成员的声明结构,方便你快速定位目标字段和方法,真正实现的分析还是要回到native二进制上。

这一步有一点特别值得说明:由于Il2CppDumper生成方法签名时需要从二进制中读取虚表和方法指针信息,能不能成功生成完整的DLL,很大程度上取决于游戏是否对IL2CPP的注册结构做了手脚。这也是后面踩坑章节的核心。

3. 完整实操流程:从拿到目标文件夹到还原出可读结构

3.1 环境准备

我使用的版本是Il2CppDumper-win-v6.7.46,Windows平台直接解压就能用,不需要安装额外运行时。这款工具同时提供GUI和命令行模式,日常分析用GUI足够,如果要批量处理多个目标,建议用命令行。

解压后目录大概长这样:

Il2CppDumper-win-v6.7.46/ ├── Il2CppDumper.exe ├── Il2CppDumper.pdb ├── config.json └── ...

config.json里可以配置一些解析选项,比如是否输出DLL,默认情况下只要解析成功,dump.cs、script.json和DLL文件夹都会生成。

3.2 获取并识别目标文件

先去游戏安装目录或APK里把关键文件捞出来。Windows游戏找GameAssembly.dll和global-metadata.dat,全球定位一般就在游戏根目录或Data目录下;Android游戏通常从APK的lib/ /libil2cpp.so里拿二进制,而global-metadata.dat在assets/bin/Data/Managed/Metadata或者assets/Data/Managed/Metadata下,具体路径依Unity版本和打包配置略有差别。

拿到的文件名不一定就叫global-metadata.dat,有些魔改版会改成别的后缀甚至无后缀,判断依据是文件头的magic。global-metadata.dat的前四个字节通常是AF 1B B1 FA(不同Unity大版本可能略有改动)。这个特征值得记一下,很多时候拿到的文件没名字,用Hex编辑器看一眼就清楚了。

3.3 执行解析

命令行模式直接一条指令:

Il2CppDumper.exe GameAssembly.dll global-metadata.dat output_dir

参数顺序是二进制文件在前、metadata在后。如果直接双击exe进入GUI模式,则按提示依次选择二进制文件、metadata文件、输出目录,界面会显示解析日志。

解析过程中日志会打印读取到的metadata版本号、类型数量、方法数量等关键信息。看到类似"Gathered info"和"Done!"的提示基本就成功了。如果报错,可以参考后面踩坑部分的处理思路。

3.4 检查输出结果

解析成功后输出目录里会有三类核心产物:

  • dump.cs:所有类、结构体、枚举、字段偏移、方法声明的全文,这是后续查找目标的主要依据;
  • script.json:结构化数据,方便用脚本程序化地提取信息,适合做批处理分析;
  • DLL文件夹:桩DLL,导入dnSpy等.NET工具中浏览结构用。

拿实际项目来说,我要找一个跟玩家属性相关的类,直接在dump.cs里搜关键词就能定位到类名和字段偏移。字段偏移这个信息非常值钱,做内存修改、注入工具或者外挂辅助开发时,字段偏移+虚表偏移就是整个技术方案的地基。Il2CppDumper把这些都给你整理好了,省去了一大段手动dump内存的时间。

4. 实际踩坑:版本匹配、报错与防Dump机制

4.1 metadata版本不匹配是最高频的报错

Il2CppDumper对global-metadata.dat的版本有明确的兼容范围。Unity每次大版本升级,metadata格式都可能调整,如果手里游戏的metadata格式比工具支持的版本新,解析阶段就会直接报版本不支持的错误。

遇到这种情况,优先检查工具是否有更新——IL2CPP新版本出来后,Il2CppDumper社区跟进得很快,升级工具版本是首选方案。如果游戏用的Unity版本很新、对应Dumper版本还没发布,也可以试试Il2CppInspector作为备选工具,它走的是另一套解析思路,在某些新格式上能跟上。还有一个不得已的土办法:把metadata文件头里的版本号改成低版本骗过程序,但不保证后面数据区能正常解析,只在个别小版本变动的时候碰巧能成。

4.2 二进制被strip符号之后还能不能解析

很多正式商用的IL2CPP游戏在编译native层时会开启strip符号选项,把导出表里那些Il2Cpp开头的符号全部抹掉,目的是增加逆向难度。Il2CppDumper面对这种目标时,不再依赖导出符号,而是尝试通过特征码在二进制里搜索关键数据结构,比如虚表和元数据注册表。大部分情况下仍然能解析成功,只是速度会慢一些,而且偶尔会需要你从弹出的候选基地址里人工确认。

如果你的目标在这一步卡住了,在GUI界面里通常会有提示或者需要你选择多个候选地址。这时候建议拉出IDA,看看候选地址附近是否存在指向字符串池的引用,行为特征像不像IL2CPP初始化代码,再决定选哪一个。

4.3 metadata被加密或魔改怎么办

有一部分游戏上了更强的保护,对global-metadata.dat整体做了加密,有些干脆在运行时动态解密到内存里,落盘的metadata文件是密文,直接用Il2CppDumper读出来的全是乱码。这种情况工具本身无解,得先走一步脱壳或解密流程:静态上找解密的XOR逻辑、AES Key,动态上直接在运行中的进程内存里dump解密后的metadata。

就我的经验来说,在Windows平台用调试器在UnityPlayer.dll加载完成后对内存做扫描、拿到解密后的元数据,是最快的路子。拿到干净的metadata之后再丢回Il2CppDumper,配合原始的GameAssembly.dll,后续流程就畅通了。

4.4 路径和命令行小坑

Win版本在命令行模式下,路径里有中文或空格时偶尔会解析异常,建议解析前先把目标文件放到一个纯英文路径下。GUI模式下这个问题基本不存在,但命令行批处理时确实容易踩,属于小概率但很烦的坑。

另外,如果命令行执行后窗口一闪而过,多半是参数顺序错了或文件路径写错。可以先不加任何参数直接运行exe,GUI模式下确认能正常打开,再回命令行操作。

5. dump.cs的正确打开方式:从结构声明到动态分析

5.1 读dump.cs时应该看什么

dump.cs里的信息密度非常高,但大多数时候你不用从头读。以查找玩家角色位置相关逻辑为例,我一般这么用:

  1. 先用关键词定位类,比如Player、Role、Character;
  2. 看字段声明里的偏移量注释,找到位置字段(Vector3类型通常是Position、LocalPosition之类)对应的偏移;
  3. 顺着方法列表找到移动、同步、状态切换相关的方法名;
  4. 记住方法名和偏移,回native二进制里定位。

这里特别提一下文件中每个方法后面的注释里那个地址,是方法在native二进制中的相对偏移(RVA)。在IDA里加载GameAssembly.dll时,用这个RVA加上ImageBase就能直接跳到对应方法所在的代码段。

5.2 配合IDA/Ghidra做代码级分析

恢复了方法名和地址之后,整个native二进制的可读性会发生质变。在IDA里把每个方法的地址标记好、重命名成dump.cs里的名字,然后对关键方法逐个看反汇编伪代码。IL2CPP生成的C++代码可读性比纯手写C++好不少,因为Unity在生成C++源码时保留了非常多原始C#的结构痕迹——类名、方法名会出现在字符串池里,常量、字段访问方式也能隐约对应回高级语言的表达。

我在分析某个游戏的技能冷却逻辑时,就是先在dump.cs里找到了技能数据类,发现冷却时间字段的偏移,再在IDA里找到修改该字段的函数,最后通过交叉引用一路找到上层调用——整个过程比对着纯汇编大海捞针直观得多。

5.3 script.json和脚本化批处理

如果目标是批量分析多个游戏,或者要从海量类里抽出特定规则的结构信息(比如找出所有带"Encrypt"字样的方法),手翻dump.cs太累了。script.json把这些数据都结构化存储了,写几行脚本就能做筛选。我对这种方式的使用频率很高,尤其要整理某类游戏通用结构的时候,一条Python正则或JSON查询下去,所有相关类一次性捞出来。

举一个最简单场景:你想知道游戏里哪些类跟网络协议相关,直接把script.json里所有含Network、Packet、Proto关键字的类型列出来,然后按需回到dump.cs查看字段偏移。整个过程不到一分钟完成。

5.4 方向与合规提醒

有一点大家心里要有数。Il2CppDumper本身是个中性的分析工具,在漏洞研究、安全测试、技术学习、正版游戏Mod开发这些方向上非常有用。但拿它去拆商业游戏的联网验证、提取资源后二次分发,或者做外挂,既违背了工具的正当用途,也容易给自己惹上实际的法律麻烦。我的原则很简单:自己的学习目标、公开的样例程序、明确获得授权的项目怎么折腾都行,别把手伸向没有授权的商业作品。

回到工具本身。Il2CppDumper-win-v6.7.46这个版本在我近期处理过的Unity目标里,解析成功率和生成的dump.cs完整度都很能打。如果你也卡在IL2CPP魔咒里,照着上面的流程走一遍,基本能把"只见二进制不闻DLL"的问题解决掉。真遇到版本不兼容或者metadata加密的硬茬,不要只盯着一个工具——升级版本、上Il2CppInspector、动态dump内存三板斧下来,多数防线都能绕过去。

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

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

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

立即咨询