Unity游戏逆向进阶 - IL2CPP逆向技术详解
字数 3767
更新时间 2026-02-06 04:38:50
Unity IL2CPP逆向技术详解教学文档
1. IL2CPP技术原理
1.1 编译流程
IL2CPP(Intermediate Language To C++)是Unity的一种脚本后端技术,其工作流程如下:
- C#代码编译:将C#源代码编译为IL(Intermediate Language)中间语言
- IL转C++:通过IL2CPP工具将IL代码转换为C++代码
- 原生编译:使用平台特定的C++编译器将C++代码编译为机器码
1.2 技术优势
- 性能提升:AOT(Ahead-Of-Time)编译,运行时无需JIT编译
- 安全性增强:代码编译为机器码,逆向难度显著增加
- 平台兼容性:支持多平台原生代码编译
1.3 核心文件结构
- GameAssembly.dll(Windows)或libil2cpp.so(Android/Linux):包含所有机器码
- global-metadata.dat:位于Data/il2cpp_data/Metadata目录,存储元数据信息
2. IL2CPP游戏识别方法
2.1 文件特征识别
-
IL2CPP特征:
- 根目录存在GameAssembly.dll文件(Windows)
- Data目录下包含il2cpp_data文件夹
- il2cpp_data/Metadata/global-metadata.dat文件存在
-
Mono特征:
- Data/Managed文件夹包含Assembly-CSharp.dll等完整DLL文件
2.2 文件大小特征
GameAssembly.dll文件体积通常为几十MB到几百MB,包含游戏全部代码和依赖库
3. Il2CppDumper工具详解
3.1 工具概述
- 项目地址:https://github.com/Perfare/Il2CppDumper
- 功能:从GameAssembly.dll和global-metadata.dat提取符号信息
- 支持平台:Windows、Linux、Android、iOS、macOS
- 支持架构:x86、x64、ARM、ARM64
3.2 使用模式
- 自动模式(Auto):自动识别平台和架构
- 手动模式(Manual):用户手动指定平台信息
- 自动加强模式(Auto(Advanced)):增强识别算法
3.3 命令格式
Il2CppDumper.exe <executable-file> <global-metadata> <output-directory>
示例:
Il2CppDumper.exe GameAssembly.dll global-metadata.dat output
3.4 输出文件详解
3.4.1 DummyDll文件夹
- 包含还原的DLL文件
- 可使用dnSpy、ILSpy等工具查看
- 保留完整的类结构和方法签名
- 方法体为空,但包含完整的元数据信息
3.4.2 dump.cs文件
- 纯文本格式的完整类定义
- 包含继承关系、字段、属性、方法等信息
- 支持文本搜索关键功能点
3.4.3 script.json文件
- JSON格式的函数地址-名称映射
- 用于IDA、Ghidra等反汇编工具
- 实现函数重命名功能
3.4.4 il2cpp.h文件
- IL2CPP运行时结构体定义
- 包含Il2CppObject、Il2CppString等关键结构
- 提升IDA反编译可读性
3.4.5 stringliteral.json文件
- 字符串常量地址映射
- 快速定位关键字符串引用
3.4.6 脚本文件
- ida.py/ida_with_struct.py:IDA脚本
- ghidra.py/ghidra_wasm.py:Ghidra脚本
4. IDA静态分析技术
4.1 分析流程
- 使用IDA打开GameAssembly.dll
- 等待自动分析完成
- 加载Il2CppDumper生成的脚本文件
- 导入符号信息和结构体定义
4.2 脚本加载方法
- File → Script file 选择ida.py或ida_with_struct.py
- 选择对应的script.json文件
- 如使用增强版,还需选择il2cpp.h文件
4.3 分析技巧
4.3.1 字符串搜索
- 利用stringliteral.json定位字符串地址
- 在IDA中查找字符串引用
- 快速定位关键功能函数
4.3.2 符号搜索
- 通过恢复的符号信息搜索特定类和方法
- 使用IDA的函数列表搜索功能
- 结合DummyDll理解程序结构
4.3.3 结构体应用
- 导入il2cpp.h增强反编译可读性
- 正确识别Il2CppString、Il2CppArray等类型
- 理解Unity特定的数据结构
5. Cheat Engine动态分析
5.1 内存搜索技术
- 精确值搜索:已知具体数值时使用
- 变化值搜索:通过数值变化规律定位地址
- 数据类型支持:整数、浮点数、字符串、字节数组
5.2 高级功能应用
5.2.1 地址访问追踪
- "Find out what accesses this address":追踪读取操作
- "Find out what writes to this address":追踪写入操作
- 定位修改关键变量的代码位置
5.2.2 函数调用
- 通过script.json获取函数地址
- 使用CE的"Call function"功能
- 需要正确设置参数和调用约定
5.2.3 脚本功能
- Lua脚本:自动化内存操作
- Auto Assembler脚本:代码注入和修改
- 实现复杂的内存操作逻辑
6. 实战案例:2024极客大挑战
6.1 游戏分析阶段
6.1.1 文件识别
- 确认GameAssembly.dll存在
- 定位global-metadata.dat文件
- 确定为IL2CPP打包方式
6.1.2 符号提取
Il2CppDumper.exe GameAssembly.dll global-metadata.dat output
6.1.3 DummyDll分析
- 使用dnSpy分析Assembly-CSharp.dll
- 发现hOOK类及其SYC方法
- 理解金钱触发机制
6.2 动态修改阶段
6.2.1 CE内存修改
- 附加CE到游戏进程
- 搜索当前金币数值
- 通过数值变化精确定位地址
- 修改金币值为1000000
- 触发SYC方法执行
6.2.2 文件生成
- SYC方法生成Data.txt文件
- 文件包含十六进制格式的PE文件
- 存储位置为游戏根目录
6.3 二进制分析阶段
6.3.1 文件转换
Python转换脚本:
with open('Data.txt', 'r') as f:
hex_data = f.read().strip()
with open('final.exe', 'wb') as f:
f.write(bytes.fromhex(hex_data))
6.3.2 IDA反编译分析
加密逻辑分析:
- 凯撒加密:20轮偏移,只影响字母字符
- 异或加密:使用"GEEK"密钥循环异或
- 十六进制转换:字节数组转十六进制字符串
6.4 解密算法实现
6.4.1 加密流程
明文 → 凯撒加密(偏移20) → 异或加密(密钥"GEEK") → 十六进制转换 → 密文
6.4.2 解密脚本
def decrypt_flag():
cipher_hex = "0A161230300C2D0A2B303D2428233005242C2D26182206233E097F133A"
cipher_bytes = bytes.fromhex(cipher_hex)
key = b"GEEK"
# 异或解密
xor_decrypted = bytes([cipher_bytes[i] ^ key[i % len(key)] for i in range(len(cipher_bytes))])
# 凯撒解密(反向偏移20)
plaintext = ""
for byte in xor_decrypted:
if 97 <= byte <= 122: # 小写字母
plaintext += chr((byte - 97 - 20) % 26 + 97)
elif 65 <= byte <= 90: # 大写字母
plaintext += chr((byte - 65 - 20) % 26 + 65)
else:
plaintext += chr(byte)
return plaintext
7. IL2CPP逆向难点与解决方案
7.1 技术难点
7.1.1 调用约定理解
- x64架构使用Microsoft x64调用约定
- 前4个参数通过RCX、RDX、R8、R9传递
- 成员方法的this指针通过RCX传递
7.1.2 字符串处理
- Il2CppString非标准C字符串
- 包含长度字段和字符数据
- 需要通过结构体偏移访问内容
7.1.3 类型信息丢失
- 局部变量类型信息不完整
- 需要通过上下文推断变量类型
- 结合DummyDll签名信息辅助分析
7.2 保护措施应对
7.2.1 代码混淆
- 控制流平坦化:转换为状态机结构
- 虚拟机保护:自定义指令集执行
- 应对策略:动态调试、符号执行
7.2.2 元数据保护
- global-metadata.dat文件加密
- 字符串常量加密存储
- 需要先解密再使用Il2CppDumper
7.3 分析策略建议
- 先高层后底层:先分析DummyDll了解整体结构
- 动静结合:静态分析配合动态调试
- 关键词搜索:利用字符串和符号信息快速定位
- 参考文档:查阅Unity官方源码和文档
8. IL2CPP与Mono技术对比
8.1 逆向难度对比
| 特性 | Mono | IL2CPP |
|---|---|---|
| 代码形式 | IL字节码 | 机器码 |
| 反编译工具 | dnSpy(源码级) | IDA(汇编级) |
| 符号信息 | 完整保留 | 需要工具恢复 |
| 修改难度 | 直接修改IL | 修改机器码或Hook |
8.2 开发选择考量
8.2.1 Mono优势
- 快速编译迭代
- 完整调试支持
- 热重载功能
8.2.2 IL2CPP优势
- 更好的运行性能
- 更高的代码安全性
- 更好的平台兼容性
8.3 混合开发策略
- 开发阶段使用Mono快速迭代
- 发布阶段切换为IL2CPP打包
- 注意反射等特性兼容性问题
9. 总结与最佳实践
9.1 技术掌握要点
- 熟练掌握Il2CppDumper工具链使用
- 具备IDA静态分析能力
- 掌握CE等动态分析工具
- 理解IL2CPP运行时特性
9.2 分析流程标准化
- 识别阶段:确认打包方式和文件结构
- 提取阶段:使用Il2CppDumper恢复符号
- 静态分析:结合DummyDll和IDA分析
- 动态验证:使用CE等工具验证分析结果
- 算法还原:理解并实现加解密逻辑
9.3 持续学习建议
- 关注Unity技术更新和变化
- 学习新的逆向技术和工具
- 参与安全社区交流分享
- 遵守法律法规和道德规范
本教学文档详细介绍了IL2CPP逆向的完整技术体系,从基础原理到实战应用,涵盖了工具使用、分析方法、难点解决等各个方面,为深入学习Unity游戏逆向技术提供了完整的学习路径。