关于 Ghidra BizHawk MCP
Ghidra BizHawk MCP 将 Ghidra 二进制分析与 BizHawk 实时模拟整合到一个 MCP 服务中,面向处理复古游戏主机 ROM 和二进制文件的逆向工程人员。它将 ROM 初步识别、反编译、P-code 模拟和分析工具放在共享会话中。
主要功能
- 01识别并加载复古 ROM
- 02Ghidra 反编译与交叉引用
- 03支持污点跟踪的 P-code 模拟
- 04基于断点的模拟
- 05并行二进制分析会话
- 06二进制比较与字节搜索
适用场景
- 01识别并加载陌生的复古 ROM
- 02反编译主机二进制文件中的函数
- 03跟踪模拟循环中的寄存器变化
- 04比较两个二进制文件中的函数
MCP 相关
该服务通过 stdin/stdout 向 MCP 客户端提供二进制分析、Ghidra 和模拟工具。BizHawk 实时模拟工具为可选功能,并使用仅限本机回环的连接。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx ghidra-bizhawk-mcpGHIDRA_INSTALL_DIRAbsolute path to the Ghidra installation directoryBIZHAWK_EXE_PATHOptional path to EmuHawk.exe for live emulation featuresMOCK_MODESet to 1 for zero-dependency CI simulation本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Ghidra BizHawk MCP
一个统一的 MCP(模型上下文协议)服务,将 Ghidra 的无头静态分析与 BizHawk 的实时模拟连接起来 — 在同一会话中即可在反编译 ROM 和在真实硬件上运行 ROM 之间切换。
GBA ROM:如果要分析 Game Boy Advance ROM,请在 Ghidra 安装目录中安装 pudii/gba-ghidra-loader,以正确解析 ROM 头、镜像内存区域和 I/O 寄存器映射。该加载器仓库提供适用于 Ghidra 11.x 的预构建
.gpa文件。
先决条件
| 依赖项 | 版本 | 必需 | 说明 |
|---|---|---|---|
| Python | >= 3.10 | 是 | MCP 服务的运行时 |
| Ghidra | 11.x 或 12.x | 是 | 无头或 GUI 安装;GHIDRA_INSTALL_DIR 必须指向此处 |
| Java(JDK) | >= 17 | 是 | 随 Ghidra 捆绑;JVM 桥接所需 |
| pyghidra | >= 3.0 | 是 | Python 到 Ghidra 的桥接;自动安装 |
| BizHawk(EmuHawk) | 最新稳定版 | 否 | 仅实时模拟工具需要;BIZHAWK_EXE_PATH 可选 |
| Docker | 最新版 | 否 | 仅容器化部署需要 |
架构
┌─────────────────────────────────────────────────────────────────┐
│ MCP Client (Claude / Cursor) │
│ sends JSON-RPC over stdin/stdout │
└─────────────────────────────┬───────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ ghidra-bizhawk-mcp │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ MCP Server (server.py) — tool registry, stdio dispatch ││
│ └──────────────────────────┬──────────────────────────────────┘│
│ │ │
│ ┌──────────────┴──────────────┐ │
│ ▼ ▼ │
│ ┌────────────────────┐ ┌──────────────────────────────┐ │
│ │ GhidraSession │ │ BizhawkBridge │ │
│ │ pyghidra → JVM │ │ TCP client → localhost:8766│ │
│ │ decompile, etc. │ └──────────────┬───────────────┘ │
│ └────────────────────┘ │ │
└───────────────────────────────────────────┼─────────────────────┘
│ TCP (newline-delimited JSON)
▼
┌──────────────────────────────┐
│ BizHawk (EmuHawk.exe) │
│ built-in socket server │
│ ┌────────────────────────┐ │
│ │ bridge.lua │ │
│ │ memory read/write │ │
│ │ joypad, savestate │ │
│ │ frame advance │ │
│ └────────────────────────┘ │
└──────────────────────────────┘
安全模型
MCP 服务仅通过 stdin/stdout与 MCP 客户端通信 — 不监听 HTTP 或网络端口。唯一的本地 TCP 套接字是服务与 BizHawk 内置 Lua 套接字服务端之间的仅限环回地址连接(127.0.0.1:8766)。它仅用于实时模拟功能,不会暴露到网络。
硬件与复古游戏平台生态集成
ghidra-bizhawk-mcp 通过 Ghidra 静态分析,为复古游戏逆向自动化工作流提供开箱即用的原生支持;同时还通过 BizHawk 多系统模拟器支持实时模拟。该服务捆绑了:
- Nintendo Entertainment System(NES),通过
GhidraNes - Super Nintendo Entertainment System(SNES),通过原生 65816 内存映射
- Game Boy Advance(GBA),通过
gba-ghidra-loader - Nintendo DS(NDS),通过
NTRGhidra - Nintendo Switch,通过
ghidra-switch-loader - PlayStation 1(PSX),通过
ghidra_psx_ldr - Sega Genesis / Mega Drive,通过原生 68000 内存映射
- Sega Master System / Game Gear,通过
Ghidra-SegaMasterSystem-Loader - Sega Dreamcast,通过原生 SuperH4 内存映射
零输入分诊 — 示例(GBA)
主要入口点是 triage_and_load_retro_rom。调用时传入任意 ROM 路径,其余工作由服务处理:
# Auto-detect platform, map language, provision session
triage_and_load_retro_rom(rom_path="/data/game.gba")
# → platform: "Game Boy Advance (GBA)"
# → loader: "GBA ROM Loader"
# → arch: "ARM:LE:32:v4t"
# Decompile the main entry point on the same session
decompile_function(address="0x00001c2c")
# → decompiled C code for the GBA ROM entry routine
# Search for a known pattern (e.g. 32-bit ARM store-multiple)
search_bytes(pattern="09 08 00 01")
# → matching addresses labelled "gba_ram_start"
执行链式流程
无需让 AI Agent 花费时间手动识别架构映射、寄存器布局或内存段,可直接串联自动摄取工作流:
- 使用目标文件路径调用
triage_and_load_retro_rom。 - 服务以无头模式解析二进制文件结构(
NES\x1a、NTR、NSO0、GBA、SNES 标题向量、PS-X EXE、SEGA、TMR SEGA、SEGA ENTERPRISES),绑定匹配的 Ghidra 语言模块(6502:LE:16、ARM:LE:32:v4t、AARCH64:LE:64、65816:LE:24、MIPS:LE:32、68000:BE:32、Z80:16、SuperH4:LE:32),加载标准地址内存块,并关联自动签名缓存数组。 - 使用集成的
emulate_slice或emulate_slice_with_taint工具分析局部主机循环 — 无需实体主机硬件,也无需开放 GDB 网络端口。
分诊工具
| 工具 | 描述 |
|---|---|
triage_and_load_retro_rom | 读取原始文件的 magic 字节,以检测 NES、SNES、GBA、NDS、Switch、PSX、Genesis、SMS 或 Dreamcast ROM。配置语言映射正确的 Ghidra 会话,并自动恢复缓存的函数签名。返回平台、加载器、架构标记和映射后的内存块。 |
快速开始
1. 安装
pip install ghidra-bizhawk-mcp
或从源代码安装:
git clone https://github.com/getanirao/ghidra-bizhawk-mcp.git
cd ghidra-bizhawk-mcp
pip install -e .
2. 设置环境
# Required: point to your Ghidra installation
export GHIDRA_INSTALL_DIR=/opt/ghidra_11.2 # Linux / macOS
set GHIDRA_INSTALL_DIR=C:\Program Files\ghidra_11.2 # Windows
# Optional: enable live BizHawk emulation
export BIZHAWK_EXE_PATH=/path/to/EmuHawk.exe
# Optional: run in mock mode (no Ghidra/BizHawk needed)
export MOCK_MODE=1
3. 运行
ghidra-bizhawk-mcp
服务监听 stdin/stdout — 可将其管道连接到任何兼容 MCP 的客户端。
Docker
docker build -t ghidra-bizhawk-mcp .
docker run -i --rm -v /path/to/binaries:/data ghidra-bizhawk-mcp
容器捆绑了 JDK 17、Ghidra 11.2 和服务 — 除 Docker 外无需主机依赖。
配置
环境变量
| 变量 | 必填 | 默认值 | 描述 |
|---|---|---|---|
GHIDRA_INSTALL_DIR | 是 | — | Ghidra 安装路径(例如 /opt/ghidra_11.2) |
BIZHAWK_EXE_PATH | 否 | — | EmuHawk.exe 的路径,用于实时模拟功能 |
MOCK_MODE | 否 | 0 | 设为 1,即可在不使用 Ghidra/BizHawk 的情况下运行(用于测试/CI) |
Claude Desktop
将以下内容添加到你的 claude_desktop_config.json 中:
{
"mcpServers": {
"ghidra-bizhawk": {
"command": "ghidra-bizhawk-mcp",
"env": {
"GHIDRA_INSTALL_DIR": "/opt/ghidra_11.2"
}
}
}
}
Cursor
将以下内容添加到 Cursor MCP 配置中:
{
"mcpServers": {
"ghidra-bizhawk": {
"command": "ghidra-bizhawk-mcp",
"env": {
"GHIDRA_INSTALL_DIR": "/opt/ghidra_11.2"
}
}
}
}
工具
会话管理
| 工具 | 描述 |
|---|---|
analyze_binary | 导入并分析二进制文件,返回一个 session_id。如果提供了 ID,则复用该 ID;否则自动生成。 |
list_sessions | 列出所有活动工作区及其会话 ID、二进制文件路径和加载时间。 |
close_session | 关闭会话并释放其 Ghidra 项目资源。 |
大多数工具都接受可选的 session_id 参数——省略该参数即可使用最近加载的会话。
读取 / 分析
| 工具 | 描述 |
|---|---|
decompile_function | 按名称或地址反编译函数。 |
decompile_function_paginated | 使用 line_start、line_end、max_tokens(按令牌预算截断)和 summarize(去除样板局部变量并折叠空行)进行分页反编译,避免耗尽上下文窗口。 |
get_data_types | 列出程序中定义的所有数据类型。 |
get_cross_references | 获取指向某个地址或从该地址出发的交叉引用。 |
get_call_graph | 获取函数的递归调用图和调用方。 |
analyze_and_decompile_entrypoints | 组合工具——一次调用即可批量反编译所有入口点(程序入口、导出项、main、_start 等)。 |
generate_workspace_report | 生成活动工作区的 Markdown 摘要,包括入口点、函数数量、自定义符号、恢复的结构体、重命名的函数和注释。可替代 GUI CodeBrowser 窗口。 |
写入 / 修改
| 工具 | 描述 |
|---|---|
rename_symbol | 重命名函数或标签。更改保存在 Ghidra 项目数据库中。 |
add_comment | 添加注释(plate、pre、post、eol、repeatable)。 |
create_struct | 根据 JSON 成员布局 [{offset, name, type}, ...] 创建自定义结构化数据类型。偏移量为可选项。 |
retype_variable | 重新指定局部变量或函数参数的类型(例如 undefined4* → MyStruct*)。 |
汇编级别
| 工具 | 描述 |
|---|---|
disassemble_range | 反汇编某个地址处的 N 条原始指令,返回助记符、操作数、十六进制字节和长度,便于精确检查底层内容。 |
get_listing_range | 返回指定字节范围的原始十六进制和 ASCII 转储,相当于 Ghidra 的 Listing 面板。可与 disassemble_range 配合使用,以检查数据区域。 |
字节序列搜索
| 工具 | 描述 |
|---|---|
search_bytes | 在整个二进制文件中搜索十六进制字节模式(例如 09 08 00 01 或 F86D0003)。返回匹配地址、上下文字节以及命中位置的任何字符串标签。 |
二进制差异比较
| 工具 | 描述 |
|---|---|
diff_binaries | 按函数名称和函数体大小比较两个已加载的会话。返回每一侧独有的函数和发生变化的函数。 |
工作区会话
每次调用 analyze_binary 都会创建一个具名会话。每个会话都会独立保持其 Ghidra 项目处于打开状态,因此可以同时加载多个二进制文件:
# Load two binaries into separate sessions
s1 = analyze_binary(binary_path="/bin/a.out") # auto session_id
s2 = analyze_binary(binary_path="/bin/b.out", session_id="my_session")
# Operate on a specific session
decompile_function(function_name="main", session_id=s1.session_id)
# Diff them
diff_binaries(session_a=s1.session_id, session_b="my_session")
部署
Docker(多用户 / CI)
docker build -t ghidra-bizhawk-mcp .
# Run as an MCP subprocess
docker run -i --rm \
-v /data/binaries:/data \
ghidra-bizhawk-mcp \
--ghidra-dir /opt/ghidra
Dockerfile 在精简的 Python 3.11 镜像中打包了 Ghidra 11.2 和 JDK 17。运行时请将二进制文件目录绑定挂载到容器中。
MCP Bundle(MCPB — Claude Desktop / Smithery)
打包为可移植的 .mcpb Bundle,以便在 Claude Desktop 中一键安装,或发布到 Smithery。
前置条件: 安装 MCPB CLI:
npm install -g @anthropic-ai/mcpb
构建 Bundle:
# From the repo root — also builds the Smithery publish variant
scripts/build-mcpb.ps1
也可以使用 mcpb 手动构建:
mcpb pack
输出文件 ghidra-bizhawk-mcp.mcpb 会将服务与 manifest.json 打包在一起。安装时,清单会提示填写 GHIDRA_INSTALL_DIR(必填)以及可选的 BIZHAWK_EXE_PATH,无需手动编辑 JSON。
发布到 Smithery:
Smithery 的发布 API 要求使用 MCP 风格的工具架构(inputSchema)和对象形式的提示词参数,而 MCPB 架构不允许在 manifest.json 中使用这些内容。因此,构建脚本会从 mcpb/tool-schemas.json 修补清单,并生成第二个 Bundle:
python scripts/build_smithery_bundle.py
smithery mcp publish ./dist/ghidra-bizhawk-mcp.smithery.mcpb -n getanirao/ghidra-bizhawk-mcp
P-code 微型仿真
| 工具 | 描述 |
|---|---|
emulate_slice | 无头执行 N 条指令。设定寄存器状态并获取寄存器变更的逐步跟踪记录。 |
emulate_slice_with_taint | 与 emulate_slice 相同,但会自动进行污点跟踪——指定一个污点寄存器(例如 r0),工具会准确标记其值何时被修改或传播到其他寄存器。 |
emulate_slice_with_breakpoints | 执行指令,直到满足条件或达到计数上限。条件语法:R0==0、R1>0xFF、R2!=R3、PC==0x1234。在匹配指令之前或之后停止。 |
所有操作都在 pyhidra 进程中通过 Ghidra 的 EmulatorHelper 执行——无需 GDB/LLDB、网络端口或调试器存根。支持 ARM、x86、MIPS 以及 Ghidra 支持的任何架构。
示例 — 在满足寄存器条件时中断
假设你正在逆向一个 GBA ROM,并想找到 0x08000100 处的循环中 r0 第一次变为零的时刻:
# Step until r0 == 0, stop before the matching instruction
result = emulate_slice_with_breakpoints(
session_id="gba_v1",
start_address="0x08000100",
max_instructions=5000,
stop_condition="R0==0",
stop_mode="before"
)
# result.exit_reason → "R0==0"
# result.instructions_executed → 312
# result.trace → [step 311: r0 goes 4→2, step 312: r0 goes 2→0]
# Check if a specific address was reached after a branch
result = emulate_slice_with_breakpoints(
session_id="gba_v1",
start_address="0x08000100",
max_instructions=5000,
stop_condition="PC==0x08001234"
)
# result.exit_reason → "PC==0x08001234"
# Use inequalities to catch bounds checks
result = emulate_slice_with_breakpoints(
session_id="gba_v1",
start_address="0x08000100",
max_instructions=5000,
stop_condition="R1>0xFF"
)
# result.exit_reason → "R1>0xFF"
# result.last_step["r1"] → 0x100
这对于识别复制循环边界(R3 >= R4)、空指针路径(R0==0)或跳转表目标(PC==0x)尤其有用。
函数指纹 / 签名迁移
| 工具 | 描述 |
|---|---|
calculate_function_fingerprint | 为函数生成结构哈希(变量、参数、主体大小、分支、被调用函数、嵌入字符串、数值常量)。即使编译器重新排序,也能保持稳定。 |
export_signature_map | 为当前二进制文件中的每个函数构建完整的 {hash → name} 映射。将此 JSON 保存下来,以便在不同版本间复用。 |
apply_signature_map | 传入之前导出的签名映射;服务会扫描整个二进制文件,并自动重命名所有匹配的函数。 |
持久化签名缓存(服务端缓存)
| 工具 | 描述 |
|---|---|
save_active_binary_signature | 为所有函数生成指纹,并将映射存储在 lineage_group_id 下(例如 "my_firmware_v1")。存储在 ~/.ghidra_bizhawk_mcp/signatures/ 中——无需管理 JSON 文件。 |
auto_restore_signatures_from_stash | 按 lineage_group_id 加载缓存的映射,并自动重命名所有匹配的函数。 |
auto_stash_current_binary | 零输入自动缓存——对二进制文件的前 4 KB 进行哈希,并将映射保存在该哈希下。只需分析后调用即可。 |
auto_restore_current_binary | 零输入自动恢复——对二进制文件进行哈希,查找之前的缓存并重命名匹配项。无需组 ID。 |
list_stashed_signature_groups | 列出本地缓存中当前所有已缓存的组。 |
工作流 — 全自动持久化:
# Analyze v1 — stashes automatically under binary content hash
s1 = analyze_binary(binary_path="/bin/v1.bin")
auto_stash_current_binary(session_id=s1.session_id)
# Later, analyze v2 — restores automatically
s2 = analyze_binary(binary_path="/bin/v2.bin")
auto_restore_current_binary(session_id=s2.session_id)
# → 142 functions renamed, zero manual JSON handling
试试这些提示词
配置好 MCP 客户端后(参见配置),向 AI Agent 提问:
- “加载这个 GBA ROM 并反编译入口点。”
- “这个 NDS 二进制文件中有哪些函数会调用 0x8001234?”
- “对这个 PSX EXE 进行初步分析,并跟踪前 20 条指令中的 r0。”
- “对比我打开的两个会话,并显示发生变化的函数。”
项目结构
ghidra-bizhawk-mcp/
├── Dockerfile
├── pyproject.toml
├── README.md
└── src/ghidra_bizhawk_mcp/
├── __init__.py
├── server.py # MCP server, tool registry, stdio transport
├── ghidra_bridge.py # GhidraSession — pyghidra wrapper, all Ghidra logic
├── lua/
│ └── bridge.lua # BizHawk-side Lua bridge for live emulation
└── tools/
├── __init__.py
├── bizhawk_bridge.py # TCP client connecting MCP ↔ BizHawk
└── ...
工作原理
pyhidra.start()在服务启动时启动 Ghidra 的 JVM,且只启动一次- 每次调用
analyze_binary都会在其独立命名的会话中打开一个新的 Ghidra 项目 - 读写工具通过
session_id(或当前默认会话)路由到指定会话 - 写入工具会直接将更改应用到 Ghidra 程序数据库
- 会话会一直保留,直到显式关闭,从而支持多二进制文件工作流和差异对比
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。