wowemulation-dev/binanana

GitHub: wowemulation-dev/binanana

面向魔兽世界经典版客户端的 Ghidra 自动化分析工具与符号数据库,支持跨版本符号传播和 Arxan 保护绕过。

Stars: 4 | Forks: 0

# binanana WoW Classic 客户端二进制文件的符号数据库和分析工具。 基于 [binana](https://github.com/thunderbrewhq/binana) 项目 (涵盖 WoW 3.3.5a),binanana 将该方法扩展到了 Classic 客户端家族:Classic (1.13.x)、Classic Era (1.14.x, 1.15.x)、TBC Classic (2.5.x) 和 Wrath Classic (3.4.x)。 所有 Classic 客户端均为 64 位 x86-64 Windows PE 二进制文件,具有以下特征: - 混淆的导入表(所有 API 调用均在运行时解析) - Control Flow Guard (CFG) - TLS 回调 - MSVC RTTI,包含 2,000-3,400 个 type_info 条目 - 700-900 个嵌入式源文件路径 - TACT/CASC 内容分发(静态链接) ## 目录 - [概述](#overview) - [依赖项](#dependencies) - [项目结构](#project-structure) - [符号文件](#symbol-files) - [头文件](#header-files) - [Ghidra](#ghidra) - [设置](#setup) - [无头分析](#headless-analysis) - [GUI 模式](#gui-mode) - [脚本兼容性](#script-compatibility) - [导入符号](#importing-symbols) - [导入 C 头文件](#importing-c-headers) - [Ghidra 服务器](#ghidra-server) - [Ghidra 扩展](#ghidra-extension) - [Binary Ninja](#binary-ninja) - [跨版本传播](#cross-version-propagation) - [可用配置文件](#available-profiles) ## 概述 该项目分为三层: 1. **Profiles** —— 每个构建的符号文件(`.sym`)、C 头文件和元数据(`info.json`)。这是受版本控制的知识库。 2. **Ghidra 脚本** —— 用于自动化分析的 Python 脚本:RTTI 链遍历、Lua API 字符串解析、符号导出/导入、跨版本函数匹配。 3. **工具** —— 用于编译符号、验证配置文件以及从内存中转储 Arxan 保护的二进制文件的 CLI 实用程序。 ## 依赖项 - Python 3.13(PyGhidra 需要 JPype1,该库没有 3.14+ 的 wheels) - Ghidra >= 12.0(用于 PyGhidra CPython 3 脚本支持) - JDK 21+(由 setup-ghidra 安装) - Gradle 8.5+(用于构建 Ghidra 扩展) - Make - Bash shell 对于 Binary Ninja 工作流: - Binary Ninja 及 binary_ninja_mcp 插件 对于内存转储器(`tools/wow-dumper`): - Rust 1.92+ 及 `x86_64-pc-windows-msvc` 目标 - cargo-xwin(从 Linux 交叉编译) - Wine 9+(推荐 wine-staging) ## 项目结构 ``` binanana/ profile/ {version}-{platform}-{arch}/ info.json # Binary metadata symbol/ {category}/ func.sym # Function symbols label.sym # Data label symbols main.sym # Compiled (all symbols merged) include/ main.h # Master header {subsystem}/*.h # Per-subsystem C headers ghidra/ analyze_rtti.py # Batch RTTI chain walker analyze_vtables.py # Heuristic vtable scanner analyze_lua_api.py # Lua API Usage: string resolver analyze_lua_tables.py # luaL_Reg registration table scanner analyze_lea_refs.py # LEA instruction reference scanner analyze_strings.py # Source path and debug string extractor export_symbols.py # Export named symbols from Ghidra import_symbols.py # Import symbols into Ghidra propagate_symbols.py # Cross-version function hash matching tools/ compile_symbols.py # Merge category .sym files into main.sym validate_profile.py # Check symbol integrity wow-dumper/ # Rust tool: dump Arxan-protected binaries extension/ build.gradle # Gradle build for Ghidra extension settings.gradle # Project name (WowEmulation) extension.properties # Extension metadata Module.manifest # Empty (no special module requirements) src/main/java/wowemulation/ WowBinaryAnalyzer.java # WoW binary detection (auto-analysis) script/ analyze # Run Ghidra headless analysis pipeline build-extension # Build the Ghidra extension zip compile-symbols # Shell wrapper for symbol compilation dump-client # Dump Arxan-protected binary via Wine export-from-binja # Export symbols from Binary Ninja install-extension # Build and install extension to Ghidra setup-ghidra # Install Ghidra + PyGhidra + ghidra-mcp Makefile ``` ## 符号文件 符号文件将地址映射到函数和数据标签。该格式与 Ghidra 的 `ImportSymbolsScript.py` 兼容: ``` FunctionName 00000001400AD020 f end=00000001400AD0A3 DataLabel 0000000142B60E20 l FunctionName 00000001400B1470 f end=00000001400B1590 type="int64_t __fastcall func(void*)" SomeFunc 00000001400C0000 f ; demangled: SomeNamespace::SomeFunc(int, char const*) ``` 字段: - **Name**:符号名称(无空格) - **Address**:16 位十六进制地址(64 位) - **Kind**:`f` 表示函数,`l` 表示数据标签 - **end=ADDR**:结束地址(最后一条指令之后的一个地址) - **type="..."**:C 类型签名 - **; comment**:人类可读的注释(例如,还原后的名称) 符号按类别组织在 `symbol/{category}/func.sym` 和 `symbol/{category}/label.sym` 中。`script/compile-symbols` 脚本将所有类别文件合并到 `symbol/main.sym` 中。 ## 头文件 C 头文件描述了与二进制文件内存表示相匹配的结构布局。它们使用条件编译进行特定于工具的处理: ``` #ifdef GHIDRA // Ghidra-specific includes #endif ``` ## Ghidra ### 设置 安装 Ghidra 和 PyGhidra(Fedora): ``` # 完整安装 (Ghidra GUI + PyGhidra + ghidra-mcp) make setup-ghidra # 仅 Headless (Ghidra + PyGhidra,无 GUI 插件) make setup-ghidra-headless ``` 此操作将安装: - Ghidra 12.0.3 到 `/opt/ghidra` - JDK 25 - Python 3.13(PyGhidra 需要 JPype1;不支持 3.14+) - PyGhidra 3.0.2 + JPype1(来自 Ghidra 捆绑的 wheels) - ghidra-mcp 2.0.2(仅限完整模式) 安装后,加载环境: ``` source /etc/profile.d/ghidra.sh ``` ### 无头分析 Ghidra 有两个无头启动器: | 启动器 | 脚本 | 用例 | |----------|---------|----------| | `analyzeHeadless` | 仅限 Java 和 Jython (Python 2.7) | 旧版脚本 | | PyGhidra headless | CPython 3.13 | binanana 脚本 | binanana 脚本使用 Python 3,必须通过 PyGhidra 运行。 运行完整的分析流水线: ``` ./script/analyze ``` 示例: ``` ./script/analyze ~/Downloads/wow_classic/Wow.exe \ profile/classic-1.13.2-31650-windows-win64 ``` 该脚本会创建一个临时的 Ghidra 项目目录,退出时会自动清理。 这将执行七个后处理脚本: 1. `analyze_rtti.py` —— 遍历 RTTI type_info -> COL -> vtable 链 2. `analyze_vtables.py` —— 用于数据段的启发式 vtable 扫描器 3. `analyze_lua_api.py` —— 将 Lua API Usage: 字符串解析为原生函数 4. `analyze_lua_tables.py` —— 查找 luaL_Reg 注册表 5. `analyze_lea_refs.py` —— 扫描 LEA 指令以查找字符串引用 6. `analyze_strings.py` —— 提取源路径和调试字符串 7. `export_symbols.py` —— 将所有命名符号导出为 .sym 格式 运行单个脚本: ``` python3.13 -m pyghidra.ghidra_launch \ --install-dir /opt/ghidra \ ghidra.app.util.headless.AnalyzeHeadless \ /tmp/ghidra_project project_name \ -import /path/to/binary \ -postScript ghidra/analyze_rtti.py "/path/to/output.txt" \ -overwrite -deleteProject ``` 脚本参数在脚本路径后传递。每个脚本接受一个可选的输出文件路径作为其第一个参数。如果没有参数,结果仅打印到 stdout。 ### GUI 模式 启动 Ghidra: ``` ghidraRun ``` binanana 脚本位于 `ghidra/` 目录中。使用方法: 1. Window -> Script Manager 2. Script Directories -> Add: `/ghidra/` 3. 按 "binanana" 类别筛选 4. 运行任意脚本(它们会在 GUI 模式下提示输入文件路径) 所有脚本均可在 GUI 和无头模式下工作。在 GUI 模式下,它们使用 `askFile()` 提示;在无头模式下,它们接受 `getScriptArgs()`。 ### 脚本兼容性 Ghidra 脚本使用 PyGhidra 兼容的导入: ``` # 正确 (在 PyGhidra 和 Jython 中可用): from ghidra.program.model.symbol import SourceType # 在 PyGhidra 中失效 (JPype enum wildcard import 问题): from ghidra.program.model.symbol.SourceType import * ``` JPype 不支持从 Java 枚举类型进行通配符导入。请使用直接导入(`import SourceType`)并将常量限定为 `SourceType.DEFAULT`、`SourceType.ANALYSIS` 等。 ### 导入符号 1. 打开 Ghidra -> Window -> Script Manager 2. 从 binanana 类别运行 `import_symbols.py` 3. 选择 `profile//symbol/main.sym` 或在无头模式下: ``` python3.13 -m pyghidra.ghidra_launch \ --install-dir /opt/ghidra \ ghidra.app.util.headless.AnalyzeHeadless \ /tmp/project project_name \ -process binary.exe \ -postScript ghidra/import_symbols.py "profile/version/symbol/main.sym" \ -noanalysis ``` ### 导入 C 头文件 1. 打开 Ghidra -> File -> Parse C Source... 2. 选择 `clib.prf` 作为解析配置 3. 将 `profile//include/main.h` 添加到源文件 4. 将 `profile//include` 添加到包含路径 5. 将 `-DGHIDRA` 添加到解析选项 6. 按 Parse to Program ### Ghidra 服务器 Ghidra 归档文件包含一个服务器(`/opt/ghidra/server/`),用于协作式多用户仓库共享。binanana 的无头分析工作流不需要此服务。如果多名分析师需要共享 Ghidra 项目数据库,它会很有用。 有关服务器设置,请参阅 `/opt/ghidra/server/svrREADME.md`。 ## Ghidra 扩展 `extension/` 目录包含一个可安装的 Ghidra 扩展,它将 Java 二进制检测器和 Python 分析脚本捆绑到一个包中。 ### 提供的功能 安装后,该扩展将添加: 1. **WoW Binary Detector** —— 一个在 Ghidra 自动分析期间运行的 Java 分析器。它扫描 `.rdata` 以查找 `CObject` RTTI 签名,从而识别 WoW 二进制文件,并使用 RTTI 条目计数设置程序属性。 2. **Script Manager 集成** —— 来自 `ghidra/` 的所有 Python 脚本会自动出现在 Script Manager 中,无需手动配置目录。 Java 代码仅限于二进制检测(约 100 行)。所有分析逻辑(RTTI 链遍历、Lua API 解析、符号管理)均保留在 Python 中。 ### 构建和安装 要求:Gradle 8.5+、JDK 21+、设置 `GHIDRA_INSTALL_DIR` 环境变量。 ``` # 构建 extension zip make build-extension # 构建并安装到系统 Ghidra 安装目录 make install-extension ``` 构建好的 zip 文件位于 `extension/dist/`。也可以通过 Ghidra 的 `File -> Install Extensions` 对话框(绿色 + 按钮)进行安装。 ### 架构说明 Ghidra 的自动分析扩展点(`AbstractAnalyzer`、`AbstractProgramWrapperLoader`、`ProgramPlugin`)需要 Java。Ghidra 的 `ClassSearcher` 扫描 classpath 上的已编译 `.class` 文件;通过 JPype 创建的 Python 类对其不可见。 这就是二进制检测使用 Java 而分析逻辑保留在 Python 中的原因。 ## Binary Ninja 对于通过 binary_ninja_mcp 插件加载到 Binary Ninja 中的二进制文件: ``` # 从 BN 导出用户命名符号为 binanana 格式 ./script/export-from-binja profile/classic-1.13.2-31650-windows-win64 # 或通过 Make make export-from-binja PROFILE=profile/classic-1.13.2-31650-windows-win64 ``` 这将连接到位于 `localhost:9009` 的 BN HTTP API,导出用户命名的函数和数据标签,并写入 `symbol/export/func.sym` 和 `symbol/export/label.sym`。 ## 跨版本传播 `propagate_symbols.py` 脚本使用指令级哈希匹配跨二进制版本的函数。工作流程: 1. 彻底分析一个版本(例如 1.13.2) 2. 在 Ghidra 中打开分析后的二进制文件,运行 `propagate_symbols.py` 并使用模式 "export" 以保存函数哈希 3. 打开目标二进制文件,运行 `propagate_symbols.py` 并使用模式 "import" 以及第 2 步中的哈希文件 4. 检查匹配的符号并提交到目标配置文件 在无头模式下: ``` # 从源二进制文件导出 hashes python3.13 -m pyghidra.ghidra_launch --install-dir /opt/ghidra \ ghidra.app.util.headless.AnalyzeHeadless /tmp/project src \ -process Wow_1.13.2.exe -noanalysis \ -postScript ghidra/propagate_symbols.py "export" "/tmp/hashes.txt" # 导入并匹配目标二进制文件 python3.13 -m pyghidra.ghidra_launch --install-dir /opt/ghidra \ ghidra.app.util.headless.AnalyzeHeadless /tmp/project tgt \ -process Wow_1.14.0.exe -noanalysis \ -postScript ghidra/propagate_symbols.py "import" "/tmp/hashes.txt" ``` ## 可用配置文件 | 版本 | 构建 | 产品 | 平台 | 二进制文件 | |---------|-------|---------|----------|--------| | 3.13.3 | 9370 | Agent | windows-i386 | Agent.exe | | 1.13.2 | 31650 | Classic | windows-win64 | Wow.exe | | 1.14.0 | 40618 | Classic Era | windows-win64 | WowClassic.exe | | 1.14.1 | 41794 | Classic Era | windows-win64 | WowClassic.exe | | 1.14.2 | 42597 | Classic Era | windows-win64 | WowClassic.exe | | 1.15.2 | 55140 | Classic Era | windows-win64 | WowClassic.exe | | 1.15.2 | 55140 | Classic Era | macos-arm64 | World of Warcraft Classic | | 1.15.8 | 64272 | Classic Era | windows-win64 | WowClassic.exe | | 2.5.3 | 42328 | TBC Classic | windows-win64 | WowClassic.exe | | 3.4.3 | 53788 | Wrath Classic | windows-win64 | WowClassic.exe |
标签:Arxan, Binary Ninja, CASC, CFG, Ghidra, JS文件枚举, Lua API, Python, RTTI, Ruby on Rails, TACT, UML, Windows PE, World of Warcraft, WoW, x86-64, 二进制分析, 云安全监控, 云安全运维, 云资产清单, 内存转储, 反混淆, 可视化界面, 后台面板检测, 应用安全, 怀旧服, 控制流保护, 无后门, 游戏安全, 符号表, 类型库, 脚本开发, 逆向工具, 逆向工程, 静态分析