告别手动定义:Il2CppDumper与IDA无缝共享Unity类型信息
你是否还在为Unity逆向分析中手动定义成百上千个类结构而头疼?是否经历过修改一处类型定义就要全局替换的重复劳动?本文将展示如何通过Il2CppDumper与IDA类型库的协作,实现Unity类型定义的自动化共享,将逆向效率提升至少300%。读完你将掌握:
- 类型信息自动提取的完整流程
- 生成IDA可用的C头文件与JSON元数据
- 一键导入类型定义的实用脚本使用
- 泛型类与复杂类型的自动处理方案
类型信息共享的核心价值
在Unity的IL2CPP逆向工程中,类型定义(如类结构、方法签名、字符串常量)是连接二进制分析与源代码逻辑的关键桥梁。传统手工定义方式存在三大痛点:
| 痛点 | 手动处理耗时 | 自动化处理 |
|---|---|---|
| 单个类结构定义 | 15-30分钟 | 3秒 |
| 泛型类实例化 | 无法手动完成 | 自动生成 |
| 类型引用更新 | 全局搜索替换2小时 | 一键同步 |
Il2CppDumper通过Outputs/StructGenerator.cs实现类型信息的自动化提取,其核心原理是解析IL2CPP二进制文件中的元数据段(Metadata)和代码段,重建C#类型系统的内存布局。
工作流程:从二进制到IDA类型库
数据提取阶段
Il2CppDumper的类型提取流程始于对两种核心文件的解析:
- global-metadata.dat:存储所有类型定义、方法签名和字符串常量
- libil2cpp.so/GameAssembly.dll:包含编译后的机器码和类型内存布局
在StructGenerator.cs的WriteScript方法中(第42行),程序会遍历metadata.imageDefs中的所有程序集,为每个类型定义生成唯一的结构名称(第46-57行)。关键代码片段:
for (var imageIndex = 0; imageIndex < metadata.imageDefs.Length; imageIndex++)
{
var imageDef = metadata.imageDefs[imageIndex];
var imageName = metadata.GetStringFromIndex(imageDef.nameIndex);
var typeEnd = imageDef.typeStart + imageDef.typeCount;
for (int typeIndex = imageDef.typeStart; typeIndex < typeEnd; typeIndex++)
{
var typeDef = metadata.typeDefs[typeIndex];
typeDefImageNames.Add(typeDef, imageName);
CreateStructNameDic(typeDef);
}
}
中间文件生成
处理完成后,会在输出目录生成两类关键文件:
- il2cpp.h:包含所有类结构定义的C头文件
- script.json:包含方法地址、签名和字符串常量的JSON元数据
StructGenerator.cs的第431行负责将这些信息写入文件:
File.WriteAllText(outputDir + "il2cpp.h", sb.ToString());
File.WriteAllText(outputDir + "script.json", JsonSerializer.Serialize(json, jsonOptions));
这些文件包含了逆向分析所需的全部类型信息,包括:
- 类的内存布局(字段偏移、大小)
- 方法的地址和参数签名
- 字符串常量的地址和值
- 泛型类的实例化信息
IDA类型导入实战
准备工作
确保已完成以下准备:
- 使用Il2CppDumper处理目标文件,获得il2cpp.h和script.json
- 启动IDA并加载Unity游戏主二进制文件(如libil2cpp.so)
- 将生成的两个文件复制到IDA脚本目录
一键导入脚本使用
Il2CppDumper提供了专为IDA设计的ida_with_struct.py脚本,其工作流程如下:
脚本核心功能在第33-85行实现,主要处理五种类型的元数据:
- 函数地址范围(第36-41行):自动创建函数段并设置边界
- 方法签名(第43-51行):应用函数原型到对应地址
- 字符串常量(第53-62行):标记字符串地址并添加注释
- 元数据引用(第64-74行):处理类型信息与属性
- 泛型方法(第76-85行):解析泛型实例并生成对应签名
关键代码示例(方法签名应用):
signature = scriptMethod["Signature"].encode("utf-8")
if apply_type(addr, parse_decl(signature, 0), 1) == False:
print "apply_type failed:", hex(addr), signature
验证导入结果
成功导入后,可以通过以下方式验证:
- 在IDA Structures窗口查看已导入的类型(如
UnityEngine_Transform_o) - 导航到已知函数地址(如
0x123456),确认已自动命名并应用签名 - 查看字符串常量地址(如
0x7890AB),确认已添加注释
高级应用:泛型类与复杂类型处理
泛型类(如List<T>)的实例化是类型处理的难点。Il2CppDumper通过Outputs/StructGenerator.cs的59-73行代码,为每个泛型实例生成唯一的结构名称:
var typeBaseName = structNameDic[typeDef];
var typeToReplaceName = FixName(executor.GetTypeDefName(typeDef, true, true));
var typeReplaceName = FixName(executor.GetTypeName(il2CppType, true, false));
var typeStructName = typeBaseName.Replace(typeToReplaceName, typeReplaceName);
nameGenericClassDic[typeStructName] = il2CppType;
genericClassStructNameDic[il2CppType.data.generic_class] = typeStructName;
例如,List<int>会被处理为List_int_o,而Dictionary<string, UnityEngine.Object>则变为Dictionary_string_UnityEngine_Object_o_o,确保每个泛型实例都有唯一的类型定义。
常见问题解决
导入失败的排查步骤
- 版本不匹配:确保Il2CppDumper版本支持目标IL2CPP版本(查看StructGenerator.cs第425行的版本检查)
- 头文件错误:删除IDA的类型缓存(
idc.ResetTypeCache())后重试 - 泛型处理失败:确认使用最新版本的ida_with_struct.py脚本
性能优化建议
对于大型项目(超过1000个类),建议:
- 分模块导入类型(修改ida_with_struct.py的processFields变量)
- 先导入核心类型(如UnityEngine命名空间)
- 使用IDA的类型库合并功能创建项目专属类型库
总结与展望
通过Il2CppDumper的Outputs/StructGenerator.cs与ida_with_struct.py的协同工作,我们实现了Unity类型定义的自动化提取与导入。这种方法不仅消除了手动定义的繁琐工作,还确保了类型信息的准确性和一致性。
未来版本将进一步优化:
- 类型继承关系的自动构建
- 与Ghidra等其他逆向工具的集成
- 动态类型更新机制
立即尝试这种自动化工作流,让你的Unity逆向分析效率实现质的飞跃!完整工具链可通过以下资源获取:
- 项目源码:Il2CppDumper/
- 使用文档:README.md
- 脚本工具:Il2CppDumper/ida_with_struct.py
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



