mcpField
R
reversing-unity-il2cpp

reversing-unity-il2cpp

github.com/trilwu开发17762 次安装12 周前更新
代码仓库

关于 reversing-unity-il2cpp

面向移动应用安全评估者的 Unity IL2CPP 逆向分析技能,讲解从识别构建类型、恢复符号到运行时检查的流程,并涵盖常见安全问题。

主要功能

  1. 01识别 Mono 与 IL2CPP 构建
  2. 02组合元数据与原生二进制
  3. 03使用 Il2CppDumper 和 Il2CppInspector
  4. 04借助 Frida 进行运行时分析
  5. 05检查凭据、网络与本地存储问题

适用场景

  1. 01分析 Unity APK 或 IPA 中的应用逻辑
  2. 02定位客户端中的 API、认证或购买流程
  3. 03检查受保护构建的内存元数据
  4. 04评估客户端权威逻辑及证书固定

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trilwu/secskills --skill reversing-unity-il2cpp

安装后在 Claude Code 中输入/reversing-unity-il2cpp确认已加载。

详细介绍

逆向分析 Unity IL2CPP

Unity 有两种截然不同的构建形式,确定你手头的是哪一种是整个流程的首要决策。Mono 构建会提供可反编译的 .NET 程序集。IL2CPP 构建会将 C# 编译为 C++,再编译成本机代码;C# 元数据存放在单独的文件中,在任何内容可读之前,必须将它与二进制文件重新组合。

适用场景

  • APK 中包含 assets/bin/Data/Managed/Metadata/global-metadata.dat 和 lib/arm64-v8a/libil2cpp.so
  • APK 中包含 assets/bin/Data/Managed/Assembly-CSharp.dll(Mono 构建)
  • IPA 中包含 Frameworks/UnityFramework.framework
  • jadx 只显示 UnityPlayerActivity 和 Unity 相关内容
  • 你需要还原游戏或应用逻辑、反作弊行为或 API 层

不适用场景

  • Flutter 或 React Native——使用 reversing-flutter-apps 或 reversing-react-native-apps
  • 普通本机应用——使用 testing-mobile-applications
  • 没有 Unity 标记的桌面游戏二进制文件——使用 analyzing-binaries
  • 为在线多人服务制作作弊工具或绕过反作弊机制——不在范围内;这是滥用服务,而非安全评估

识别构建类型

unzip -l target.apk | rg 'global-metadata|libil2cpp|Assembly-CSharp|libmono'
存在的文件构建类型难度
Assembly-CSharp.dll、libmono*.soMono简单 — 直接反编译 DLL
global-metadata.dat + libil2cpp.soIL2CPP下文的主要流程
两者都没有,但有 UnityFrameworkiOS IL2CPP与 IL2CPP 相同;从解密后的 IPA 中提取

Mono 构建很快就能处理完。 提取程序集并打开:

unzip -j target.apk 'assets/bin/Data/Managed/Assembly-CSharp.dll' -d ./out
# dnSpy / dnSpyEx / ILSpy / dotPeek — full C# source recovery, and dnSpy can edit
ilspycmd ./out/Assembly-CSharp.dll -o ./decompiled

以下内容均针对 IL2CPP。

将元数据与二进制文件重新组合

IL2CPP 将信息拆分存储:libil2cpp.so 保存编译后的代码,global-metadata.dat 保存 C# 类型系统——类名、方法名、字段名、字符串字面量。单独使用其中任何一个都没有用。工具会将两者匹配起来并生成符号。

unzip -j target.apk 'lib/arm64-v8a/libil2cpp.so' \
                    'assets/bin/Data/Managed/Metadata/global-metadata.dat' -d ./in

# Il2CppDumper: the standard first attempt
Il2CppDumper ./in/libil2cpp.so ./in/global-metadata.dat ./out

典型输出及其用途:

产物用途
dump.cs列出所有类、方法和字段及其地址——先看这个
DummyDll/.NET 程序集存根;可在 dnSpy/ILSpy 中打开,以便轻松浏览类型系统
script.json用于 IDA/Ghidra 的符号导入文件——将名称应用到 libil2cpp.so
stringliteral.json字符串常量:URL、密钥、消息

如果 Il2CppDumper 失败,可以改用 Il2CppInspector;它支持不同范围的 Unity 版本,并会生成 Ghidra 和 IDA 脚本,以及内容更丰富的 C++ 头文件。在认定某个构建不受支持之前,两种工具都试试。

版本不匹配是最常见的失败原因。 元数据格式会随 Unity 版本变化;工具会询问或推断版本。先读取 Unity 版本并显式传入:

strings ./in/libil2cpp.so | rg -m3 '20[0-9]{2}\.[0-9]+\.[0-9]+' 
strings ./in/global-metadata.dat | head -5

受保护的构建会加密或混淆 global-metadata.dat——文件头魔数会不正确,转储工具也会拒绝处理。迹象包括:文件开头不是预期的元数据魔数,或熵值普遍偏高。实用的做法是动态处理:让应用自行解密元数据,然后在加载后从内存中转储。

# Dump the decrypted metadata from a running process
frida -U -f com.target.app -l dump-metadata.js
# Then feed the dumped file to Il2CppDumper as normal

这种“让程序自行解包,再从内存转储”的方法与处理加壳恶意软件时使用的方法相同,而且几乎总是比静态破解保护更省力。参见 analyzing-binaries。

分析还原出的代码

  1. 阅读 dump.cs,了解类型映射。 搜索相关类:名称包含 *Manager、*Service、*Api、*Network、*Auth、*Purchase、*Config 的类。
  2. 将 script.json 导入 IDA 或 Ghidra,让 libil2cpp.so 显示 C# 方法名,而不是 sub_1A2B3C。没有这一步,反汇编内容将难以阅读;完成后,读起来就像反编译后的 C#。
  3. 检查 stringliteral.json,查找端点和密钥。 理由与其他框架相同——字符串常量在各种处理后仍会保留。
  4. 使用 Frida 在运行时挂钩,并使用 dump.cs 中的地址。方法地址相对于 libil2cpp.so 基址,因此需要解析模块基址并加上偏移量。
// Pattern: resolve base, add the RVA from dump.cs, intercept
const base = Module.findBaseAddress('libil2cpp.so');
Interceptor.attach(base.add(0x1A2B3C), {
  onEnter(args) { console.log('called with', args[1]); },
  onLeave(ret)  { console.log('->', ret); }
});

与安全相关的发现

进行评估而非满足好奇心时,常见问题包括:

  • 硬编码的凭据和端点,位于 stringliteral.json 中——后端密钥、 分析令牌、云存储凭据。
  • 由客户端主导的逻辑。 货币、权益和验证在 C# 中完成,且服务器信任这些结果。直接调用 API 进行验证。
  • 证书固定薄弱或缺失。 Unity 的网络层通常配置得较为宽松;检查 UnityWebRequest 的用法。
  • 本地存档和配置篡改。 PlayerPrefs 和本地存档文件中存储着服务器信任的值。
  • 应用内购买的收据验证在客户端完成。

应拒绝的合理化说辞

  • “jadx 什么也没显示,所以它受到了保护。” Unity 应用按设计在 dex 中几乎不包含任何内容。
  • “转储器失败了,所以无法分析这个构建。” 尝试另一个转储器,明确提供 Unity 版本;如果元数据已加密,则从内存中转储。
  • “IL2CPP 是编译后的,所以逻辑是安全的。” 元数据会随它一同发布。这正是这种格式的意义所在。
  • “客户端会验证购买。” 那么这笔购买就没有经过验证。
  • “我会直接读取原始 arm64。” 先应用 script.json。在应用之前,同一个函数难以读懂;应用之后则一目了然。

参考资料

  • testing-mobile-applications — 平台存储、权限和原生层
  • testing-apis — 后端;客户端主导的逻辑问题会在此成为发现项
  • analyzing-binaries — 受保护构建的内存转储和反分析
  • Il2CppDumper、Il2CppInspector、dnSpy/ILSpy、Frida、IDA/Ghidra

评论

支持 Markdown