内容
# IDA Pilot
[](https://github.com/wklwkl115/ida-pilot/actions/workflows/verify.yml)
[](LICENSE)




> 通过模型上下文协议(MCP)驱动 IDA Pro 的反编译器和反汇编器,实现无头、快速和节省令牌。

无头 IDA Pro 分析服务器,暴露 MCP 工具(启用 `py_eval` 时为 28 个工具,不启用时为 27 个工具)。专为 AI 代理设计,提供分层工具加载、多层缓存、批量操作和紧凑的负载,以最小化每次调用的令牌成本。
Go 负责协调会话和缓存。Python 工作线程通过 idalib 运行 IDA。通信使用 TCP 上的 Connect RPC。
## 为什么选择 IDA Pilot?
- **为代理而建,非为人类。** 每个响应都是紧凑的——十六进制地址、稀疏字段、`[address, type]` 交叉引用元组、 `"ok"` 而不是 `{"success": true}` —— 以花费最少的令牌。
- **一次调用,非十次。** 复合工具如 `survey_binary` 和 `analyze_function` 在单次往返中返回反编译 + 元数据 + 交叉引用 + 注释;`analyze_functions` 批量处理多达 10 个。
- **在大型二进制文件上保持响应。** 加载和自动分析在后台运行,带有实时的进度心跳,因此 200 MB 的二进制文件不会阻塞或超时您的 MCP 客户端——您轮询直到 `ready=true` 然后继续工作。
- **分层工具表面。** 代理启动时带有 3 个工具;读写和分析工具在工作流推进时动态添加,保持每次调用的模式 payload 较小。
- **多二进制文件。** 打开多个数据库并跨数据库进行 `cross_reference` / `cross_search`。
- **默认安全。** 环回绑定、`py_eval` 关闭、`Origin`/`Host` 保护,可选路径允许列表(详情见下)。
## ⚠️ 安全模型 — 请在公开端口前阅读
IDA Pilot **没有内置身份验证**。默认配置针对同一台机器上的单个受信任的 MCP 客户端:
- **默认绑定到 `127.0.0.1`。** 只有本地主机上的调用者可以访问。如需覆盖,请使用 `--bind 0.0.0.0` (或 `IDA_PILOT_BIND`),前提是您已配置了身份验证的反向代理。
- **每次请求的 `Origin` / `Host` 验证**,当绑定到环回地址时——阻止 DNS 重绑定和浏览器跨源攻击。
- **`py_eval` 默认关闭。** 它在 IDA 工作线程中运行任意 Python 代码(具有完整的主机文件系统和网络访问权限)。请显式启用 `--enable-py-eval` (或 `IDA_PILOT_ENABLE_PY_EVAL=1`),并将生成的端点视为 RCE 原语——任何可以访问端口的人都可以执行代码。
- **文件系统允许列表(可选)。** 默认情况下,客户端可以打开服务器用户可以读取的任何文件(`open_binary`、`import_metadata`)。设置 `--allowed-roots` (或 `IDA_PILOT_ALLOWED_ROOTS`)以将这些路径限制在特定目录内——建议在公开端口时使用。路径在检查前会解析符号链接,因此链接内的路径无法逃逸。
截断输出缓存(`get_cached_output`)是进程全局的,没有每会话的 ACL——服务器没有客户端身份来绑定条目,因此访问依赖于不可猜测的 128 位缓存 ID 和上述环回保护,而不是会话所有权。
简而言之:**全新 `./bin/ida-pilot` 运行是安全的,可以直接运行;公开端口或启用 `py_eval` 是明确的选择,需要您负责保护。**
## 架构
```
MCP 客户端(Claude、Cursor 等)
│
│ 流式 HTTP / SSE
▼
Go 服务器(:17300)
│ 会话注册、工具分层、缓存、输出分页
│
│ Connect RPC(TCP)
▼
Python 工作线程(每个二进制文件一个)
│ idalib + Hex-Rays 反编译器
▼
IDA 数据库(.i64)
```
## 快速入门
### 要求
- **IDA Pro 9.0+**,并启用 idalib([文档](https://docs.hex-rays.com/user-guide/idalib))
- **Go 1.25+**
- **Python 3.10+**(支持的最低版本;CI 和 `mise` 固定为 3.12)
### 构建
```bash
git clone https://github.com/wklwkl115/ida-pilot.git
cd ida-pilot
pip install -r python/requirements.txt
go build -o bin/ida-pilot ./cmd/ida-pilot
```
### 运行
```bash
./bin/ida-pilot --debug
```
服务器监听 `http://localhost:17300/`(流式 HTTP)和 `http://localhost:17300/sse`(SSE 回退)。
### 连接 MCP 客户端
将以下内容添加到您的 MCP 客户端配置中:
```json
{
"mcpServers": {
"ida-pilot": {
"type": "http",
"url": "http://127.0.0.1:17300/"
}
}
}
```
**Claude Desktop:** `~/Library/Application Support/Claude/claude_desktop_config.json`(macOS)或 `%APPDATA%\Claude\claude_desktop_config.json`(Windows)
**Claude Code:** `.mcp.json` 在项目根目录或 `~/.claude/settings.json`
**Cursor:** `.cursor/mcp.json` 在项目根目录
## 代理优化设计
IDA Pilot 专为代理而设计,非为人类。每个设计决策都针对降低令牌成本和减少往返次数。
### 分层工具加载
代理启动时带有 3 个工具。根据需要,会出现更多工具——每次调用的模式 payload 保持较小。
| 层级 | 触发器 | 工具 | 目的 |
|------|---------|-------|---------|
| 0 | 服务器启动 | 3 | `open_binary`、`list_sessions`、`get_cached_output` |
| 1 | 二进制文件打开 | +19 = 22 | 读取、查询、复合、分析、上下文和跨会话工具 |
| 2 | 首次分析 | +5 = 27 | 写入、注释和导入工具 |
当最后一个会话关闭时,工具会降级回第 0 层。添加 `--enable-py-eval` 会注册另一个第 1 层工具,使整个表面达到 28 个。
### 复合工具
一次调用取代多次调用。这些是分析的主要入口点:
- **`survey_binary`** — 单次调用获取二进制文件概览
- **`analyze_function`** — 反编译 + 元数据 + 交叉引用 + 注释,针对单个函数
- **`analyze_functions`** — 批量分析最多 10 个函数
- **`annotate_function`** — 批量重命名、重新类型和注释,针对单个函数
### 多层缓存
| 缓存 | 范围 | 容量 | 使无效 |
|-------|-------|----------|--------------|
| 列表(函数、导入、导出、字符串) | 会话 | 无限制 | 重命名 / make_function |
| 反编译(伪代码) | 按函数 | 200 条目 | 有针对性:函数重命名仅使该函数无效;数据标签重命名搜索并逐出仅包含旧名称的条目;lvar/注释使该函数无效 |
| 交叉引用(至 + 从) | 按地址 | 无限制 | make_function |
| 分段 | 会话 | 静态 | 永远不会 |
| 输出(截断的响应) | 全局 | 200 条目,1 小时 TTL | FIFO 逐出 |
| 分析上下文(已访问 + 注释) | 会话 | 无限制 | 永远不会 |
当打开二进制文件时,背景缓存预热会自动启动——`survey_binary` 在其首次调用时立即返回。
### 紧凑的负载
- 地址以十六进制(`0x...`)形式出现在输入和输出中,因此代理直接粘贴其在反汇编/列表中看到的内容(输入也接受十进制)
- 稀疏字段:省略零/假/空值
- 交叉引用为 `[address, type]` 元组,而不是对象
- 写操作返回 `"ok"` 而不是 `{"success": true}`
- 超过 8KB 的响应会自动截断,并通过 `get_cached_output` 分页
- 会话 ID 自动检测,当只有一个会话处于活动状态时
### 分析上下文
代理在长时间对话中会丢失上下文。IDA Pilot 在服务器端跟踪它:
- **`set_analysis_note`** — 在分析过程中将注释附加到地址
- **`get_analysis_context`** — 检索所有已访问的函数和注释,以恢复状态
## 工具参考
表面故意设计得较小:相关操作被合并在少数调度工具后面,这些工具带有鉴别器字段(`category`、`mode`、`action`、`target`、`format`)。3 个层级共 28 个工具。
### 会话和生命周期(第 0-1 层)
| 工具 | 描述 |
|------|-------------|
| `open_binary` | 打开二进制文件。立即返回;后台加载 + 自动分析 |
| `close_binary` | 关闭会话并保存数据库 |
| `save_database` | 保存而不关闭 |
| `list_sessions` | 列出活动会话 |
| `get_session_progress` | 加载/分析进度和就绪状态 — 轮询直到 `ready=true` |
| `get_cached_output` | 通过其 `_cache_id` 分页截断的响应 |
`open_binary` 不会阻塞:加载和自动分析在后台工作线程中运行,因此调用会立即返回(大型二进制文件可能需要几分钟才能分析)。在发出分析工具之前,请轮询 `get_session_progress` 直到 `ready=true` — 它们会被阻塞,并在未准备好时返回“未准备好”的错误。状态 RPC 在工作线程序列化 IDA 访问的单个线程上回答进度查询,同时从缓存状态中回答。
### 复合工具(第 1 层)
| 工具 | 描述 |
|------|-------------|
| `survey_binary` | 单次调用获取二进制文件概览 |
| `analyze_function` | 反编译 + 元数据 + 交叉引用 + 注释,针对单个函数 |
| `analyze_functions` | 批量分析最多 10 个函数;每个项目错误,以便单个错误地址不会导致批量失败 |
### 读取和查询(第 1 层)
| 工具 | 描述 |
|------|-------------|
| `query` | 按 `category` 浏览:函数、导入、导出、字符串、全局变量、段、结构体、枚举、入口点。正则表达式、分页和类别过滤器(`named_only`、`module`、`name`) |
| `get_references` | 交叉引用。`mode`=代码(`direction`=to/from/both)、数据或字符串 |
| `search` | `mode`=文本(`needle`)或二进制(IDA `pattern`),在 `start`/`end` 范围内 |
| `inspect` | 名称 + 类型 + 注释 + 函数边界 + 指令长度在某个地址 |
| `get_disasm` | 某个地址或整个函数的反汇编 |
| `read_memory` | 原始内存:`format`=字节/双字/四字/字节/字符串 |
### 跨会话(第 1 层)
| 工具 | 描述 |
|------|-------------|
| `cross_reference` | 查找一个二进制文件中的符号(`source_session_id` + `address`)并在另一个二进制文件(`target_session_id`)中找到其出现 — 搜索导入、导出、函数名称和字符串 |
| `cross_search` | 跨多个会话进行搜索。`mode`=函数/导入/导出/字符串,正则表达式或精确匹配。省略 `session_ids` 以搜索所有活动会话 |
### 分析控制和上下文(第 1 层)
| 工具 | 描述 |
|------|-------------|
| `run_auto_analysis` | 触发 IDA 自动分析(适用于以 `skip_analysis` 打开的二进制文件)。分析完成后返回,或 — 对于长时间分析 — 及时返回 `status:"analyzing"`,同时在后台继续;轮询 `get_session_progress` 直到 `ready=true` |
| `watch_auto_analysis` | 观察自动分析进度(不驱动或取消) |
| `set_analysis_note` / `get_analysis_context` | 服务器端上下文跟踪,用于状态恢复 |
| `prune_context` | 清除缓存输出 + 已记录函数缓存以释放内存 |
| `py_eval` *(可选)* | 在 IDA 中执行 Python — 仅在 `--enable-py-eval` 时注册。使每次调用后缓存无效(`read_only=true` 以保持缓存)。参见 [安全模型](#%EF%B8%8F-%E5%AE%89%E5%85%A8%E6%A8%A1%E5%9E%8B--%E8%AF%BB%E5%89%8B%E5%90%8E%E5%90%8A%E9%AA%8C%E6%9C%8D%E5%8A%A1%E7%9B%96%E5%99%A8) 。 |
### 写入和导入(第 2 层)
| 工具 | 描述 |
|------|-------------|
| `annotate_function` | 批量重命名 + 重新类型 + 注释函数 → 返回更新的伪代码 |
| `set_metadata` | `action`=set_name、delete_name 或 set_comment(`scope`=address/function/decompiler) |
| `set_type` | `target`=函数(原型)、全局变量(C 类型)或 lvar(C 类型 + `function_address` + `lvar_name`) |
| `make_function` | 在某个地址创建函数 |
| `import_metadata` | `format`=il2cpp(script.json + il2cpp.h)或 flutter(flutter_meta.json) |
## 配置
### 命令行标志
```
--bind 绑定接口(默认 127.0.0.1;仅在身份验证代理后面使用 0.0.0.0)
--port HTTP 端口(默认:来自 config.json)
--config 配置文件路径(默认:config.json)
--worker Python 工作线程脚本路径
--max-sessions 最大并发会话数
--session-timeout 会话空闲超时(例如 4h)
--debug 详细日志记录
--enable-py-eval 注册 py_eval 工具(IDA 工作线程中的任意 Python 代码 — RCE 原语)
--allowed-roots 限制代理提供的路径到这些目录(OS 路径列表分隔;空 = 无限制)
```
### 环境变量
```
IDA_PILOT_BIND=127.0.0.1
IDA_PILOT_PORT=17300
IDA_PILOT_SESSION_TIMEOUT_MIN=240
IDA_PILOT_MAX_SESSIONS=10
IDA_PILOT_WORKER=/path/to/worker.py
IDA_PILOT_DEBUG=1
IDA_PILOT_ENABLE_PY_EVAL=0
IDA_PILOT_ALLOWED_ROOTS=/srv/samples:/data/binaries # OS 路径列表分隔;空 = 无限制
```
### config.json
```json
{
"bind": "127.0.0.1",
"port": 17300,
"session_timeout_minutes": 240,
"max_concurrent_sessions": 4,
"database_directory": "./databases",
"python_worker_path": "python/worker/server.py",
"debug": false,
"enable_py_eval": false,
"allowed_roots": []
}
```
## 开发
```bash
make build # 构建服务器
make test # 运行测试
make proto # 重新生成 protobuf(需要 protoc)
make clean # 清理工件
make inspector # 在 localhost:5173 启动 MCP Inspector
```
### 项目结构
```
ida-pilot/
├── cmd/ida-pilot/ # 服务器入口点
├── internal/
│ ├── server/ # MCP 工具处理程序、缓存、分层
│ ├── session/ # 会话注册 + 持久性
│ └── worker/ # Python 工作线程进程管理器
├── proto/ # protobuf 服务定义
└── python/worker/ # idalib 包装器 + Connect RPC 服务器
```
## 贡献
欢迎贡献 — 请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 以了解设置、本地测试门控和约定。如需私下报告安全问题,请参阅 [SECURITY.md](SECURITY.md)。
## 许可证
MIT