☰
Il2CppDumper v6.7.46:Unity IL2CPP 逆向解析核心原理与实战指南
2026/10/17 3:53:59 网站建设 项目流程

简介:Il2CppDumper-win-v6.7.46 是一款面向Unity逆向分析工程师与安全研究人员的成熟IL2CPP逆向工具集,专为还原Unity原生构建中被剥离的托管逻辑结构而设计,适用于Unity 5.3至2020版本的Android(libil2cpp.so)、Windows(PE)、iOS(Mach-O)、Switch(NSO)及WebAssembly等多平台二进制文件分析。资源共11个文件,含8个Python脚本(如ghidra_with_struct.py、ida_with_struct_py3.py等,用于自动生成结构体头文件及IDA/Ghidra适配脚本)、2个可执行程序(Il2CppDumper-x86.exe与Il2CppDumper.exe,分别支持32/64位环境)、1个配置文件config.json,整体压缩包仅10.7MB,轻量易部署。已有1053人学习下载,工具链覆盖从内存dump绕过简单PE保护、ELF/Mach-O/WASM格式解析,到辅助静态分析的全流程,用户可直接调用脚本快速生成结构体定义、导入符号、提升逆向效率,显著降低Unity游戏或应用的MonoBehaviour与MonoScript提取门槛。

1. Il2CppDumper-win-v6.7.46 是什么:专为 Unity IL2CPP 构建产物逆向设计的 Windows 原生工具,不是通用反编译器,更不是“一键脱壳神器”

你手头有个 Unity 打包出来的 Android APK 或 Windows 独立构建体,用常规 .NET 反编译器(如 dnSpy、ILSpy)打不开——因为它的 C# 代码早已被 Unity 的 IL2CPP 后端编译成 C++ 源码,再由本地编译器(MSVC/Clang)生成原生机器码。此时,.NET 元数据几乎全丢,类型名、方法签名、字符串常量被剥离,只剩一片“黑匣子”。Il2CppDumper-win-v6.7.46 就是专治这个场景的:它不试图执行或模拟运行时,而是静态解析libil2cpp.so(Android)或GameAssembly.dll(Windows/macOS)中的符号表、元数据段(.data/.rodata)、函数指针数组与类布局偏移,再结合global-metadata.dat文件重建出完整的 C# 类型结构、方法签名、泛型实例化信息,并导出可被 dnSpy 直接加载的.dll+.pdb组合。它适合的是 Unity 游戏逆向分析、MOD 开发者查接口、安全研究员做二进制审计,不适合想绕过登录验证或提取加密资源的“玄学操作”——它不处理加密、不 patch 内存、不 hook 调用,只做一件事:把 IL2CPP 的“骨架”重新拼回来。如果你正对着一堆sub_12345678函数发呆,或者global-metadata.dat明明存在却导出失败,那 v6.7.46 就是你该停下来的版本。


2. 核心原理与适用边界:为什么必须同时提供 GameAssembly.dll 和 global-metadata.dat?缺一不可的双源驱动模型

Il2CppDumper 不是靠猜,也不是靠暴力扫描内存模式。它的可靠性建立在 Unity IL2CPP 构建流程中两个强约束产物的协同上:GameAssembly.dll(或libil2cpp.so)承载运行时符号与函数地址,global-metadata.dat则是 Unity 编译期生成的“元数据快照”,记录了所有托管类型的完整定义、字段偏移、方法 RVA、泛型上下文等。二者缺一,dumper 就会退化为“半残状态”:仅靠二进制扫描能恢复极少量基础类型(如System.Object),但无法还原List<T>的实际T是什么、Dictionary<TKey, TValue>的哈希桶结构、甚至string的内部字段布局。v6.7.46 对此做了明确分层处理:先校验 metadata 文件头魔数(0x1B 0x00 0x00 0x00),再解析其内部Image、Assembly、TypeDefinition、MethodDefinition四大核心表;接着在GameAssembly.dll中定位il2cpp_defaults全局变量、g_MetadataRegistration函数指针数组、以及关键的il2cpp_TypeInfo结构体数组起始地址。只有当两者地址映射对齐、类型数量匹配、方法 RVA 能在二进制中真实跳转时,导出才被视为可信。这也是为什么很多新手第一次运行就报错Failed to find il2cpp image或Metadata version mismatch:他们只拖入了 DLL,却漏掉了同目录下那个不起眼的global-metadata.dat——后者通常比前者小一个数量级,但权重却高十倍。

2.1 识别目标文件是否真正来自 IL2CPP 构建

不是所有 Unity 构建都启用 IL2CPP。Editor 模式、Mono 后端、WebGL(部分旧版)均不产生GameAssembly.dll。确认方式有三:

  • 文件存在性检查:Windows 构建体根目录下必须同时存在GameAssembly.dll(≥5MB)和global-metadata.dat(通常 1–10MB)。若只有UnityPlayer.dll,说明是 Mono 后端,Il2CppDumper 完全不适用。
  • PE 结构验证:用CFF Explorer或dumpbin /headers GameAssembly.dll查看Characteristics字段,应含DLL标志;Optional Header → Magic应为PE32+(64位)或PE32(32位);Section Headers中应存在.text、.data、.rdata,且.rdata包含大量疑似字符串的 ASCII 块。
  • 字符串特征扫描:用strings GameAssembly.dll | findstr /i "il2cpp",应返回il2cpp_codegen_runtime_class_init、il2cpp_codegen_object_new等函数名;strings global-metadata.dat | head -n 20应可见Assembly-CSharp、UnityEngine等程序集名及System.String、System.Int32等基础类型名。

提示:某些 Unity 版本(如 2021.3+)在 Release 模式下会对global-metadata.dat进行轻量混淆(如 XOR 0x55),导致 v6.7.46 默认解析失败。此时需配合-m参数指定解密密钥,或使用社区补丁版 dumper —— 但官方 v6.7.46 本身不内置解密逻辑,这是刻意为之的设计边界。

2.2 v6.7.46 的三大核心解析阶段与输出物含义

整个 dump 过程分为三个原子阶段,每阶段失败都会中断后续,且日志明确标出阶段名:

阶段触发条件关键动作输出物说明
Stage 1: Metadata Load启动时自动执行读取global-metadata.dat,校验魔数、版本号(如24.1对应 Unity 2021.3)、解析Image表获取程序集列表、TypeDefinition表构建类型树生成./output/metadata.json(人类可读的类型索引),若失败则无后续
Stage 2: Binary ScanStage 1 成功后触发在GameAssembly.dll中搜索il2cpp_defaults符号(通过 MSVC 调试符号或硬编码偏移)、定位g_MetadataRegistration数组、扫描所有il2cpp_TypeInfo*指针并验证其有效性生成./output/binary_info.json(含il2cpp_TypeInfo总数、g_MetadataRegistration地址等),是类型还原的物理锚点
Stage 3: Type & Method Export前两阶段均成功后执行将 metadata 中的TypeDefinition与 binary 中的il2cpp_TypeInfo按名称+大小双重匹配,重建字段偏移、方法 RVA、泛型参数绑定;为每个类型生成.cs源码框架,并调用 Roslyn 编译为.dll+.pdb输出./output/Assembly-CSharp.dll(可被 dnSpy 加载)、./output/Assembly-CSharp.pdb(支持断点调试)、./output/Scripts/(C# 源码)

注意:Assembly-CSharp.dll并非原始 C# 编译产物,而是根据 metadata + binary 逆向推导出的“语义等价体”——它没有原始注释、局部变量名、控制流优化痕迹,但类名、方法签名、字段类型、继承关系 100% 可信。这是 v6.7.46 的核心价值:用确定性算法替代经验主义猜测。

2.3 命令行参数详解:从最简运行到精准控制的六种典型组合

v6.7.46 采用纯命令行交互,无 GUI。所有参数均为可选,但生产环境强烈建议显式指定关键项。以下为高频组合(路径请替换为你的实际路径):

# 最简模式:自动探测,依赖当前目录下文件名匹配 Il2CppDumper.exe "D:\game\GameAssembly.dll" "D:\game\global-metadata.dat" # 指定输出目录(避免污染源目录) Il2CppDumper.exe "D:\game\GameAssembly.dll" "D:\game\global-metadata.dat" -o "D:\game\dump_output" # 强制指定 Unity 版本(当自动检测失败时,如 metadata 版本号异常) Il2CppDumper.exe "D:\game\GameAssembly.dll" "D:\game\global-metadata.dat" -v 24.1 # 启用详细日志(排查 Stage 1/2 失败时必开) Il2CppDumper.exe "D:\game\GameAssembly.dll" "D:\game\global-metadata.dat" -l debug # 仅导出特定程序集(减少输出体积,加速分析) Il2CppDumper.exe "D:\game\GameAssembly.dll" "D:\game\global-metadata.dat" -a "Assembly-CSharp" # 跳过 PDB 生成(仅需 DLL 和源码时,节省时间) Il2CppDumper.exe "D:\game\GameAssembly.dll" "D:\game\global-metadata.dat" --no-pdb

参数逻辑说明:

  • -o:输出根目录,默认为./output。v6.7.46 会在此目录下创建Assembly-CSharp.dll、Scripts/、metadata.json等,不会覆盖已有文件,但会清空同名子目录。
  • -v:Unity 运行时版本号,格式为主版本.次版本(如24.1)。v6.4+ 开始,dumper 内置了常见版本的 metadata 解析器,若自动识别错误(如误判为23.2),手动指定可强制走正确分支。
  • -l debug:日志等级设为debug,会打印每一行 metadata 表解析过程、每一个il2cpp_TypeInfo的地址与大小校验结果。普通用户用info(默认)即可,debug 日志单次运行可达 50MB+。
  • -a:--assembly,只处理指定名称的程序集。Unity 项目可能包含Assembly-CSharp、Assembly-CSharp-firstpass、UnityEngine.CoreModule等多个程序集,-a可精准聚焦。
  • --no-pdb:PDB 文件包含符号调试信息,体积大(常达 DLL 的 2–3 倍),且 dnSpy 加载时并非必需。关闭后output/下无.pdb,但.dll仍含完整类型定义。

注意:v6.7.46不支持直接处理 ZIP/APK 文件。你必须先用7-Zip解压 APK,从lib/arm64-v8a/libil2cpp.so提取 SO 文件,并从assets/bin/Data/Managed/提取global-metadata.dat(Android);Windows 构建体则直接取根目录下两文件。这是工具的明确输入契约,不存在“智能解包”功能。


3. 避坑指南:五条血泪经验总结的高频翻车现场与当场修复方案

用 Il2CppDumper 最痛苦的不是不会用,而是报错信息极其简略(如Failed to find metadata registration),而真实原因千差万别。以下是我在某跨平台系统逆向项目中踩过的五个典型坑,按发生频率排序,每条附带现象、根因与三步修复法:

3.1 现象:Failed to find il2cpp image或No valid il2cpp image found

原因:GameAssembly.dll中未找到il2cpp_defaults全局变量。常见于:① 文件被 UPX 等加壳器压缩(v6.7.46 无法解析加壳后二进制);② Unity 构建时启用了“Strip Engine Code”且删除了il2cpp_defaults符号;③ 文件损坏或非 IL2CPP 构建。
解决:

  1. 用file GameAssembly.dll(Linux/macOS)或PEiD(Windows)检查是否加壳,若显示 UPX、ASPack 等,用对应脱壳工具还原;
  2. 用dumpbin /symbols GameAssembly.dll | findstr il2cpp_defaults检查符号是否存在,若无返回,说明已被 Strip,此时只能尝试旧版 Unity 构建体或联系开发者;
  3. 用strings GameAssembly.dll | head -n 50确认是否含il2cpp字符串,若无,则非 IL2CPP 产物,停止使用本工具。

3.2 现象:Metadata version mismatch: expected 24.1, got 23.2

原因:global-metadata.dat的头部版本号与 dumper 内置解析器版本不匹配。v6.7.46 支持 Unity 2019.4 至 2022.3 的主流版本,但某些 LTS 分支(如 2021.3.30f1)的 metadata 格式有微小变更,导致自动识别偏差。
解决:

  1. 用十六进制编辑器(如 HxD)打开global-metadata.dat,跳转到偏移0x08,读取 4 字节(小端序),转为十进制即真实版本号(如0x01 0x00 0x18 0x00=24.1);
  2. 查阅 Il2CppDumper GitHub Releases 页面,确认 v6.7.46 支持的版本范围;
  3. 若版本确实在支持列表内,强制指定-v参数,如Il2CppDumper.exe ... -v 24.1,绕过自动检测。

3.3 现象:Failed to find metadata registration或g_MetadataRegistration is null

原因:GameAssembly.dll中g_MetadataRegistration函数指针数组未被定位到。这通常因 Unity 启用了 Link Time Optimization(LTO)或代码混淆,导致该全局数组被优化掉或重命名。
解决:

  1. 用objdump -t GameAssembly.dll | grep -i "metadata\|registration"检查符号表,若无结果,说明 LTO 已生效;
  2. 尝试用Il2CppDumper.exe ... --force-scan参数(v6.7.46 新增),启用暴力内存扫描模式,从.data段起始逐字节匹配g_MetadataRegistration的典型结构(长度为n * 8字节的指针数组);
  3. 若仍失败,说明二进制已被深度混淆,此时需回退到未开启 LTO 的构建体,或使用 IDA Pro 手动定位g_MetadataRegistration地址后,用--metadata-reg=0x12345678硬编码传入。

3.4 现象:导出的.dll在 dnSpy 中显示Could not load file or assembly 'UnityEngine'

原因:Assembly-CSharp.dll依赖UnityEngine.dll、mscorlib.dll等基础程序集,但这些文件未被一同加载。v6.7.46 仅导出目标程序集,不打包依赖项。
解决:

  1. 从同一 Unity 构建体中提取UnityEngine.dll(Windows 构建体在Data/Managed/目录下);
  2. 在 dnSpy 中依次File → Open加载UnityEngine.dll、mscorlib.dll(.NET Framework 版本需匹配,通常为 4.0)、Assembly-CSharp.dll;
  3. 加载顺序必须为:先依赖项,后目标项。若仍有缺失,用dnSpy的Modules窗口右键Assembly-CSharp→Edit Module→References查看具体缺哪个程序集,再补全。

3.5 现象:Scripts/目录下生成的.cs文件中,方法体全为// Generated by Il2CppDumper+throw new NotSupportedException();

原因:Il2CppDumper 仅还原类型定义与方法签名,不反编译 IL 或机器码为 C# 逻辑。NotSupportedException是占位符,表示该方法的实际实现仍在GameAssembly.dll的原生函数中,无法转为 C# 源码。
解决:

  1. 接受现实:这是工具能力的硬边界。IL2CPP 的本质是将 C# 编译为 C++,再编译为机器码,中间无 IL 层,故无法“反编译”出原始 C# 逻辑;
  2. 替代方案:用x64dbg或Ghidra动态调试GameAssembly.dll,在il2cpp_codegen_runtime_class_init等入口下断点,跟踪方法调用链,结合Scripts/中的签名理解参数与返回值;
  3. 进阶技巧:对关键方法,用Il2CppDumper导出的.pdb文件配合dnSpy的“调试符号加载”,可在原生调用处设置断点,观察寄存器与栈帧变化——这才是 IL2CPP 逆向的正道。

4. 实战配置:如何为 Unity 2021.3.30f1 构建体定制 v6.7.46 的稳定运行参数

Unity 2021.3.x 是当前企业级项目的主力 LTS 版本,其 IL2CPP 构建产物在 v6.7.46 下需针对性配置才能 100% 成功。我以某图像处理 Demo 的 Windows 构建体为例,完整复现从文件准备到可用 DLL 的全流程。该构建体使用 Unity 2021.3.30f1,启用了Strip Engine Code和Development Build,global-metadata.dat未加密。

4.1 文件准备与预检清单

首先确认源文件完整性(路径假设为D:\demo-build\):

文件路径预期大小必检项作用
D:\demo-build\GameAssembly.dll≥8.2 MBdumpbin /headers显示PE32+,strings | findstr il2cpp返回 ≥50 行原生代码载体,含il2cpp_defaults和g_MetadataRegistration
D:\demo-build\global-metadata.dat4.7 MB十六进制查看0x00处为0x1B 0x00 0x00 0x00,0x08处为0x01 0x00 0x18 0x00(即 24.1)元数据定义源,版本号必须与 Unity 2021.3 匹配
D:\demo-build\Data\Managed\UnityEngine.dll3.1 MBildasm UnityEngine.dll | head -n 10显示// Metadata version: 4.0用于 dnSpy 调试依赖,非 dumper 输入

提示:Development Build会保留更多调试符号,极大提升il2cpp_defaults定位成功率;Strip Engine Code会删减UnityEngine内部未引用的类,但不影响il2cpp_defaults存在性——这是关键区别。

4.2 稳定运行命令与参数逻辑拆解

针对该构建体,我固定使用的命令如下(保存为dump.bat):

@echo off setlocal set GAME_DLL="D:\demo-build\GameAssembly.dll" set META_DAT="D:\demo-build\global-metadata.dat" set OUTPUT_DIR="D:\demo-build\dump_output" Il2CppDumper.exe %GAME_DLL% %META_DAT% ^ -o %OUTPUT_DIR% ^ -v 24.1 ^ -a "Assembly-CSharp" ^ -l info ^ --no-pdb if %ERRORLEVEL% EQU 0 ( echo [SUCCESS] Dump completed. Output in %OUTPUT_DIR%. pause ) else ( echo [ERROR] Dump failed. Check log in %OUTPUT_DIR%\log.txt. pause )

参数选择依据:

  • -v 24.1:global-metadata.dat头部确认为 24.1,强制指定避免自动检测抖动;
  • -a "Assembly-CSharp":该项目仅有一个主程序集,排除UnityEngine.CoreModule等系统模块,减少无关输出;
  • --no-pdb:本阶段只需类型定义,PDB 体积大且非必需,后续调试时再按需生成;
  • -l info:日志级别设为info,既能看到Stage 1/2/3进度,又不会产生海量 debug 日志。

4.3 输出物验证与 dnSpy 加载实操

运行后,检查D:\demo-build\dump_output\目录结构:

dump_output/ ├── Assembly-CSharp.dll # 主输出,dnSpy 可直接加载 ├── Scripts/ # C# 源码框架,含类定义与方法签名 │ ├── Assembly-CSharp/ │ │ ├── GameLogic.cs │ │ └── ImageProcessor.cs ├── metadata.json # JSON 格式元数据索引,可 grep 查类型 ├── binary_info.json # 二进制解析结果,含 il2cpp_TypeInfo 总数 └── log.txt # 运行日志,含各阶段耗时与关键地址

在 dnSpy 中加载步骤:

  1. File → Open→ 选择D:\demo-build\dump_output\Assembly-CSharp.dll;
  2. File → Open→ 选择D:\demo-build\Data\Managed\UnityEngine.dll(确保版本一致);
  3. 在Assembly-CSharp节点上右键 →Edit Class→ 展开ImageProcessor类,可见所有字段(如private Texture2D m_InputTexture)与方法(如public void ProcessImage());
  4. 点击ProcessImage方法,右侧代码窗显示// Generated by Il2CppDumper+throw new NotSupportedException();—— 这是正常现象,表明签名已还原,逻辑需动态分析。

注意:若 dnSpy 报Assembly references not resolved,说明UnityEngine.dll加载顺序错误或路径不对。此时关闭所有模块,先加载UnityEngine.dll,再加载Assembly-CSharp.dll,问题即解。


5. 进阶技巧:用 Python 脚本自动化校验 dump 结果完整性,避免人工翻查百个类

当项目规模变大(如Assembly-CSharp.dll含 2000+ 类),人工验证每个类是否成功导出既低效又易漏。我写了一个轻量 Python 脚本verify_dump.py,它不依赖 dnSpy,仅用pefile和json库,就能在 3 秒内完成三项核心校验:①Assembly-CSharp.dll是否真为 .NET 程序集;②metadata.json中的类型总数是否与binary_info.json中的il2cpp_TypeInfo数量一致;③Scripts/目录下是否为每个TypeDefinition生成了对应.cs文件。脚本逻辑清晰,可直接集成到 CI 流程。

5.1 脚本代码与执行方式

# verify_dump.py import json import os import pefile def verify_dump(output_dir): # Step 1: Check if Assembly-CSharp.dll is a valid .NET assembly dll_path = os.path.join(output_dir, "Assembly-CSharp.dll") try: pe = pefile.PE(dll_path) # Check for .NET header (IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) if hasattr(pe, 'OPTIONAL_HEADER') and hasattr(pe.OPTIONAL_HEADER, 'DATA_DIRECTORY'): dotnet_dir = pe.OPTIONAL_HEADER.DATA_DIRECTORY[14] # COM Descriptor if dotnet_dir.Size > 0: print("[✓] Assembly-CSharp.dll is a valid .NET assembly") else: raise ValueError("Not a .NET assembly: COM Descriptor size is 0") else: raise ValueError("PE header missing DATA_DIRECTORY") except Exception as e: print(f"[✗] DLL validation failed: {e}") return False # Step 2: Compare type counts from metadata.json and binary_info.json meta_path = os.path.join(output_dir, "metadata.json") binary_path = os.path.join(output_dir, "binary_info.json") try: with open(meta_path, 'r', encoding='utf-8') as f: meta_data = json.load(f) with open(binary_path, 'r', encoding='utf-8') as f: binary_data = json.load(f) meta_types = len(meta_data.get('types', [])) binary_types = binary_data.get('il2cpp_TypeInfo_count', 0) if meta_types == binary_types: print(f"[✓] Type count match: {meta_types} types in both files") else: print(f"[✗] Type count mismatch: metadata={meta_types}, binary={binary_types}") return False except FileNotFoundError as e: print(f"[✗] Missing JSON file: {e}") return False except json.JSONDecodeError as e: print(f"[✗] Invalid JSON: {e}") return False # Step 3: Verify Scripts/ directory has one .cs file per type scripts_dir = os.path.join(output_dir, "Scripts", "Assembly-CSharp") if not os.path.isdir(scripts_dir): print("[✗] Scripts/Assembly-CSharp directory not found") return False cs_files = [f for f in os.listdir(scripts_dir) if f.endswith('.cs')] if len(cs_files) == meta_types: print(f"[✓] Script files match: {len(cs_files)} .cs files for {meta_types} types") else: print(f"[✗] Script count mismatch: expected {meta_types}, got {len(cs_files)}") return False return True if __name__ == "__main__": import sys if len(sys.argv) != 2: print("Usage: python verify_dump.py <output_directory>") sys.exit(1) output_dir = sys.argv[1] if verify_dump(output_dir): print("\n[SUCCESS] All verifications passed. Dump is complete and consistent.") else: print("\n[FAILED] Verification failed. Check the above errors.") sys.exit(1)

执行方式(需提前安装pefile):

pip install pefile python verify_dump.py "D:\demo-build\dump_output"

5.2 脚本背后的设计哲学:为什么这三项校验足以判定 dump 成功率?

  • DLL .NET 标识校验:Assembly-CSharp.dll若只是普通 PE 文件(如被误命名为 DLL 的 SO),pefile会因找不到 COM Descriptor 而报错。这是最底层的“身份认证”,失败意味着整个 dump 流程已偏离轨道。
  • 类型数量一致性:metadata.json来自global-metadata.dat解析,binary_info.json来自GameAssembly.dll扫描。二者数量相等,证明il2cpp_TypeInfo指针数组与 metadata 中的TypeDefinition表已成功对齐——这是 v6.7.46 正常工作的充要条件。若不等,说明g_MetadataRegistration定位错误或 metadata 被截断。
  • 脚本文件全覆盖:Scripts/目录是唯一供人工阅读的产出。每个.cs文件对应一个TypeDefinition,文件数与类型数一致,即保证了“人肉可读性”完整。即使某个类的方法体是NotSupportedException,只要文件存在,就说明类型定义已成功重建。

这三项校验不涉及任何业务逻辑,纯粹是工程层面的“完整性快照”,执行快、误报率低、可重复性强。从那以后我每次 dump 完,都强制走一遍python verify_dump.py,再打开 dnSpy —— 这已成为我的肌肉记忆。希望帮到你。

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

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

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

立即咨询