ghidra-fleet
# ghidra-fleet
**一个 MCP 服务器,同时分析任意多个二进制文件,零端口占用。**
解决传统 GhidraMCP 的痛点:"1 个二进制 = 1 个 GUI 实例 = 1 个端口 = 1 份 MCP 配置"。
ghidra-fleet 完全无 GUI 运行(headless),AI 配置一次即可批量导入、并行分析、
跨样本交叉查询,分析结果落在标准 Ghidra 项目里,随时可以打开 GUI 人工复核。
```
MCP 客户端 ──stdio── ghidra-fleet (fastmcp)
├─ core/runtime.py PyGhidra 内嵌 JVM + 共享 .gpr 项目
│ + 程序句柄懒加载 / LRU 逐出(控内存)
├─ core/analyzer.py 批量分析:线程池并行、sha256 去重复用、
│ 后台作业 + 轮询(不受 MCP 30s 超时影响)
└─ core/queries.py 反编译/交叉引用/列表/重命名/跨样本搜索
```
## 安装
前置:已安装 Ghidra + Python 3.10+。
> 实测环境:Windows 11 + Ghidra 12.1 + Python 3.14。Linux/macOS 提供了对应的
> 安装脚本与跨平台测试(测试样本自动按平台选取),但未在 CI 上持续验证。
```bat
:: Windows
scripts\setup_env.bat <你的 Ghidra 安装目录>
```
```bash
# Linux / macOS
GHIDRA_INSTALL_DIR=/path/to/ghidra scripts/setup_env.sh
```
脚本会创建 `.venv` 并安装:fastmcp(PyPI)+ pyghidra(**Ghidra 安装目录自带的
wheel,版本严格匹配**)。若自带 jpype1 wheel 不覆盖你的 Python 版本,会自动
改用 PyPI 的兼容版 jpype1。
## 配置到 MCP 客户端
以 ZCode 为例,`~/.zcode/cli/config.json` 的 `mcp.servers` 里加(用户级),
路径换成你自己的:
```json
"ghidra-fleet": {
"type": "stdio",
"command": "<repo>\\.venv\\Scripts\\python.exe",
"args": ["-m", "ghidra_fleet"],
"cwd": "<repo>",
"env": {
"GHIDRA_INSTALL_DIR": "<你的 Ghidra 安装目录>"
},
"timeoutMs": 120000
}
```
Linux/macOS 下 `command` 用 `<repo>/.venv/bin/python`。
`timeoutMs` 建议保留:首次调用要启动 JVM + Ghidra(约 10~30 秒),之后都是毫秒级。
旧的单文件 GUI 版 MCP 无需删除,两者共存。
## 工具一览(23 个)
所有查询/改名工具的第一个参数都是 `binary`,接受:
完整 program_name(`ab12cd34__sample.exe`)/ 原始路径 / 唯一文件名 / sha256 前 8 位。
用 `list_binaries` 随时查看全部。
| 类别 | 工具 | 说明 |
|---|---|---|
| 舰队 | `analyze_binaries` | 批量导入+并行分析(目录也可,单批上限 1000 个文件),立即返回 job_id |
| | `analysis_status` | 轮询作业进度(含每个文件的分析百分比/阶段,已完成的可立刻查询) |
| | `list_binaries` | 所有二进制 + 架构/大小/哈希/状态(missing = 幽灵记录) |
| | `delete_binary` | 删除一个二进制(项目文件 + manifest;也能清理幽灵记录) |
| | `find_in_all_binaries` | **跨全部样本**搜同名函数/同字符串(找共享代码/家族特征,最多扫 200 个) |
| 查询 | `list_functions` / `list_methods` / `search_functions_by_name` | 函数列表/搜索 |
| | `decompile_function` / `decompile_functions` | 反编译 C(单个 / 批量最多 50 个,错误内联) |
| | `disassemble_function` | 反汇编 |
| | `function_info` | 签名、参数、调用约定等 |
| | `get_xrefs_to` / `get_xrefs_from` / `get_function_xrefs` | 交叉引用 |
| | `list_imports` / `list_exports` / `list_segments` / `list_strings` | 导入导出/内存段/字符串 |
| 修改 | `rename_function` / `rename_data` / `rename_variable` | 重命名(即时保存) |
| | `set_function_prototype` / `set_local_variable_type` | 签名/变量类型 |
| | `set_comment` | 注释(plate/pre/eol/post/repeatable) |
## 典型工作流
```
用户: 把 C:\samples\ 下的 20 个样本都分析了,找出它们的共同特征
AI: 1. analyze_binaries(["C:\\samples"], recursive=true) → job_id
2. analysis_status(job_id) → 轮询到完成(旧样本秒级跳过)
3. list_binaries() → 拿到全部 program_name
4. find_in_all_binaries("string", "http://") → 跨样本特征
find_in_all_binaries("function", "encrypt") → 共享函数
5. decompile_function("ab12cd34__x.exe", "FUN_00401000")
rename_function("ab12cd34__x.exe", "FUN_00401000", "c2_beacon_decode")
```
改名/注释/类型修改即时保存进项目;用 Ghidra GUI 打开
`<项目目录>/fleet.gpr`(File → Open Project)即可看到 AI 的全部标注。
## 环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
| `GHIDRA_INSTALL_DIR` | (必填) | Ghidra 安装目录 |
| `GHIDRA_FLEET_PROJECT_DIR` | `~/.ghidra_fleet/projects` | Ghidra 项目目录 |
| `GHIDRA_FLEET_PROJECT_NAME` | `fleet` | 项目名 |
| `GHIDRA_FLEET_MAX_WORKERS` | `min(4, CPU)` | 并行分析线程数;遇到分析器并发问题时设 `1` |
| `GHIDRA_FLEET_MAX_OPEN` | `6` | 同时保持打开的程序数(LRU 逐出) |
| `GHIDRA_FLEET_XMX` | `4G` | JVM 堆上限;设空串用 Ghidra 默认 |
| `GHIDRA_FLEET_LOG` | `INFO` | 日志级别 |
## 测试
```bash
GHIDRA_INSTALL_DIR=<Ghidra 安装目录> .venv/bin/python tests/smoke_test.py [样本1 样本2 ...]
GHIDRA_INSTALL_DIR=<Ghidra 安装目录> .venv/bin/python tests/stdio_test.py
```
不传样本时自动挑选 PATH 上的系统小工具(Windows 用 where/robocopy 等,
Linux/macOS 用 ls/true 等)。覆盖:并行分析、二次提交缓存跳过、重复内容去重、
各类查询、改名/签名/类型后逐出重开的持久性、跨样本搜索、stdio 协议层。
## 已知边界
- **同一项目目录同一时间只允许一个 server 实例**(Ghidra 项目锁):开多个 MCP 会话时,
第一个实例占用项目,其余实例会收到明确的锁冲突提示。多会话请错开使用,
或给不同会话配置不同的 `GHIDRA_FLEET_PROJECT_DIR`。关闭占用方后即可恢复。
- **不要把 server 的启动脚本放在名为 `ghidra` 的目录下运行**(也不要让 sys.path[0]
指向这种目录):Python 会把它当成 `ghidra` 命名空间包,与 pyghidra 的 Java 包
导入钩子冲突(递归爆栈)。用 `python -m ghidra_fleet` 从任意 cwd 启动是安全的。
- 进程内并行分析在极少数格式上可能触发 Ghidra 分析器并发问题:把
`GHIDRA_FLEET_MAX_WORKERS` 设为 `1` 即退化为顺序分析,接口不变。
- 分析进度按文件粒度上报百分比;部分 Ghidra 分析阶段本身不提供总量,
此时只显示阶段名(progress_pct 为 null)。
TDQS
Scored across 23 tools
Several tools overlap: list_methods is an explicit alias of list_functions, search_functions_by_name overlaps with filtered list_functions, and get_function_xrefs overlaps with get_xrefs_to on function entries. find_in_all_binaries is also adjacent to single-binary search tools. Descriptions help clarify intent, but an agent may still hesitate between similar query paths.
Most names follow a consistent snake_case verb_noun style such as analyze_binaries, list_functions, decompile_function, and rename_variable. Minor deviations like analysis_status and function_info are noun-first, and list_methods introduces an alternate noun for the same concept, but the overall convention is predictable.
At 23 tools, the surface is at the heavy end for a single MCP server, though the Ghidra reverse-engineering domain is broad. The explicit list_methods alias adds redundancy, and some list/search/xref tools could potentially be consolidated. It is usable but borderline heavy.
The surface covers batch analysis, status polling, binary listing, cross-binary search, function listing/search, decompilation, disassembly, xrefs, imports/exports, segments, strings, and several mutation operations. Minor gaps remain around deletion/project lifecycle and listing variables or data beyond rename operations, but core workflows are well covered.