wklwkl115/ida-pilot

GitHub: wklwkl115/ida-pilot

将 IDA Pro 的反编译与反汇编能力封装为 MCP 工具供 AI agent 调用的无头分析服务器,专为降低逆向分析中的 token 成本和交互轮次而设计。

Stars: 1 | Forks: 0

# IDA Pilot [![验证](https://github.com/wklwkl115/ida-pilot/actions/workflows/verify.yml/badge.svg)](https://github.com/wklwkl115/ida-pilot/actions/workflows/verify.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE) ![Go](https://img.shields.io/badge/Go-1.25%2B-00ADD8?logo=go&logoColor=white) ![Python](https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white) ![MCP](https://img.shields.io/badge/MCP-server-7c3aed) ![平台](https://img.shields.io/badge/platform-windows%20%7C%20linux%20%7C%20macos-lightgrey) ![IDA Pilot — 一场 MCP 会话:打开二进制文件,非阻塞地观看自动分析进度,一键进行全面勘察,随后反编译某个函数](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/db00805a55153945.gif) 无头 (Headless) IDA Pro 分析服务器,提供 MCP 工具(启用 `py_eval` 时为 28 个,未启用时为 27 个)。专为 AI agent 设计 —— 分层工具加载、多层缓存、批量操作以及紧凑的有效载荷 (payload),旨在最小化每轮对话的 token 成本。 由 Go 负责编排会话和缓存。Python worker 通过 idalib 运行 IDA。通信采用基于 TCP 的 Connect RPC。 ## 为什么选择 IDA Pilot? - **专为 agent 而非人类设计。** 每次响应都是紧凑的 —— 十六进制地址、稀疏字段、`[address, type]` 交叉引用 (xref) 元组、使用 `"ok"` 代替 `{"success": true}` —— 以实现每轮对话消耗最少的 token。 - **一次调用胜过十次。** 像 `survey_binary` 和 `analyze_function` 这样的复合工具能在一次往返中返回反编译代码 + 元数据 + 交叉引用 + 注释;`analyze_functions` 支持一次批量处理多达 10 个函数。 - **在处理庞大二进制文件时依然保持响应。** 加载和自动分析以独立进程运行,并带有实时进度心跳,因此即使是 200 MB 的二进制文件也不会卡死或导致你的 MCP 客户端超时 —— 你只需轮询直到 `ready=true` 即可继续工作。 - **分层工具呈现。** Agent 启动时仅有 3 个工具;随着工作流的推进,读取/分析和写入工具会逐步解锁,从而保持每轮对话的 schema 精简。 - **多二进制文件支持。** 可以同时打开多个数据库,并通过 `cross_reference` / `cross_search` 在它们之间进行交叉检索。 - **默认安全。** 仅绑定本地回环 (Loopback)、默认关闭 `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 worker 内部运行任意 Python 代码(拥有完整的主机文件系统和网络访问权限)。必须使用 `--enable-py-eval`(或 `IDA_PILOT_ENABLE_PY_EVAL=1`)显式开启,并将由此产生的 endpoint 视为一个 RCE 原语 —— 任何能访问该端口的人都可以执行代码。 - **文件系统白名单(可选开启)。** 默认情况下,客户端可以打开服务器用户有权限读取的任何文件(`open_binary`, `import_metadata`)。设置 `--allowed-roots`(或 `IDA_PILOT_ALLOWED_ROOTS`)可将这些路径限制在特定目录中 —— 只要暴露端口就强烈建议这样做。路径在进行检查前会进行符号链接解析,因此根目录内的链接无法逃逸出去。 截断输出的缓存(`get_cached_output`)在进程全局范围内共享,没有基于会话的 ACL —— 因为服务器没有可绑定条目的客户端身份 —— 所以其访问安全性依赖于不可预测的 128 位缓存 ID 以及上述的本地回环/Origin 防护,而不是基于会话所有权。 简而言之:**新启动的 `./bin/ida-pilot` 运行时保持默认配置是安全的;向网络开放端口或启用 `py_eval` 是你明确的选择,保护它是你的责任。** ## 架构 ``` MCP Client (Claude, Cursor, etc.) │ │ Streamable HTTP / SSE ▼ Go Server (:17300) │ session registry, tool tiers, caching, output pagination │ │ Connect RPC (TCP) ▼ Python Worker (one per binary) │ idalib + Hex-Rays decompiler ▼ IDA database (.i64) ``` ## 快速开始 ### 前置条件 - **IDA Pro 9.0+** 且已激活 idalib([文档](https://docs.hex-rays.com/user-guide/idalib)) - **Go 1.25+** - **Python 3.10+**(支持的最低版本;CI 和 `mise` 固定使用 3.12) ### 构建 ``` 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 ``` ### 运行 ``` ./bin/ida-pilot --debug ``` 服务器将监听 `http://localhost:17300/`(Streamable HTTP)和 `http://localhost:17300/sse`(SSE 备用)。 ### 连接 MCP 客户端 添加至你的 MCP 客户端配置中: ``` { "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` ## 针对 Agent 的优化设计 IDA Pilot 是为 agent 而非人类构建的。每一项设计决策都旨在降低 token 成本和减少往返次数。 ### 分层工具加载 Agent 启动时仅拥有 3 个工具。随着需求增加,会解锁更多工具 —— 从而保持每次对话的 schema 有效载荷精简。 | 层级 | 触发条件 | 工具数 | 用途 | |------|---------|-------|---------| | 0 | 服务器启动 | 3 | `open_binary`, `list_sessions`, `get_cached_output` | | 1 | 二进制文件已打开 | +19 = 22 | 读取、查询、复合、分析、上下文及跨会话工具 | | 2 | 首次分析 | +5 = 27 | 写入、注释及导入工具 | 当最后一个会话关闭时,工具会降级回 Tier 0。添加 `--enable-py-eval` 会额外注册一个 Tier-1 工具,使完整的工具集达到 28 个。 ### 复合工具 一次调用替代多次。这些是进行分析的主要入口: - **`survey_binary`** —— 区段、函数/导入/导出/字符串计数及其头部条目、入口点、反编译器状态。一次调用即可掌握全貌。 - **`analyze_function`** —— 获取单个函数的伪代码 + 元数据 + 交叉引用 + 注释。全部已被缓存。 - **`analyze_functions`** —— 并行批量分析最多 10 个函数。 - **`annotate_function`** —— 针对每个函数,在一次调用中批量进行重命名、重新定义类型和添加注释。 ### 多层缓存 | 缓存 | 作用域 | 容量 | 失效条件 | |-------|-------|----------|--------------| | 列表 (函数, 导入, 导出, 字符串) | 会话 | 无限制 | rename / make_function | | 反编译 (伪代码) | 单函数 | 200 条 | 定向失效:函数重命名仅使该函数失效;数据标签重命名会搜索并仅驱逐包含旧名称的条目;局部变量(lvar)/注释会使该函数失效 | | 交叉引用 (源 + 目标) | 单地址 | 无限制 | make_function | | 区段 | 会话 | 静态 | 永不失效 | | 输出 (被截断的响应) | 全局 | 200 条, 1小时 TTL | FIFO 驱逐 | | 分析上下文 (已访问 + 备注) | 会话 | 无限制 | 永不失效 | 当打开二进制文件时,后台缓存预热会自动开始 —— `survey_binary` 在首次调用时能瞬间返回。 ### 紧凑的有效载荷 - 输入和输出中的地址均为十六进制 (`0x...`),因此 agent 可以原样粘贴在反汇编/列表中看到的内容(输入时也接受十进制) - 稀疏字段:省略零值/假值/空值 - 交叉引用使用 `[address, type]` 元组而不是对象 - 写入操作返回 `"ok"` 而不是 `{"success": true}` - 超过 8KB 的响应会自动截断,并可通过 `get_cached_output` 进行分页处理 - 当仅有一个活动会话时,自动检测会话 ID ### 分析上下文 Agent 在长对话中容易丢失上下文。IDA Pilot 会在服务器端进行跟踪: - **`set_analysis_note`** —— 在分析过程中将备注附加到地址上 - **`get_analysis_context`** —— 检索所有已访问的函数和备注,以恢复状态 ## 工具参考 工具集设计得刻意精简:相关操作被整合在少数几个调度工具背后,这些工具通过一个区分字段(`category`, `mode`, `action`, `target`, `format`)来执行操作。跨越三个层级的 28 个工具。 ### 会话与生命周期 (Tier 0–1) | 工具 | 描述 | |------|-------------| | `open_binary` | 打开二进制文件。立即返回;加载和自动分析在后台运行 | | `close_binary` | 关闭会话并保存数据库 | | `save_database` | 保存但不关闭 | | `list_sessions` | 列出活动会话 | | `get_session_progress` | 加载/分析进度及就绪状态 —— 轮询直到 `ready=true` | | `get_cached_output` | 通过其 `_cache_id` 对截断的响应进行分页 | `open_binary` 不会阻塞:加载和自动分析在后台 worker 线程中运行,因此调用会立即返回(大型二进制文件分析可能需要几分钟)。在发出分析工具指令之前轮询 `get_session_progress` 直到 `ready=true` —— 在此之前它们会受到限制并返回 `not ready` 错误。状态 RPC 始终保持响应,因为 worker 会在单线程上串行化对 IDA 的访问,同时根据缓存状态响应进度查询。 ### 复合工具 (Tier 1) | 工具 | 描述 | |------|-------------| | `survey_binary` | 一次调用获取完整的二进制概览 | | `analyze_function` | 针对单个函数的反编译 + 元数据 + 交叉引用 + 注释 | | `analyze_functions` | 批量分析最多 10 个函数;包含单项错误反馈,因此一个错误的地址不会导致整个批次失败 | ### 读取与查询 (Tier 1) | 工具 | 描述 | |------|-------------| | `query` | 按 `category` 浏览:functions, imports, exports, strings, globals, segments, structs, enums, entry_point。支持正则表达式、分页和类别过滤器 (`named_only`, `module`, `name`) | | `get_references` | 交叉引用。`mode`=code (`direction`=to/from/both), data, 或 string | | `search` | `mode`=text (`needle`) 或 binary (IDA `pattern`),限定在 `start`/`end` 范围内 | | `inspect` | 获取地址上的名称 + 类型 + 注释 + 函数边界 + 指令长度 | | `get_disasm` | 获取地址处的反汇编,或整个函数的 | | `read_memory` | 原始内存:`format`=bytes/dword/qword/byte/string | ### 跨会话 (Tier 1) | 工具 | 描述 | |------|-------------| | `cross_reference` | 从一个二进制文件 (`source_session_id` + `address`) 中查找符号,并找出它在另一个文件 (`target_session_id`) 中出现的位置 —— 搜索导入、导出、函数名和字符串 | | `cross_search` | 一次跨多个会话进行搜索。`mode`=functions/imports/exports/strings,支持正则表达式或精确匹配。省略 `session_ids` 以搜索所有活动会话 | ### 分析控制与上下文 (Tier 1) | 工具 | 描述 | |------|-------------| | `run_auto_analysis` | 触发 IDA 自动分析(适用于使用 `skip_analysis` 打开的二进制文件)。在分析完成后返回,或者 如果分析时间超过调用时长 —— 迅速返回并带有 `status:"analyzing"`,同时继续在后台运行;轮询 `get_session_progress` 直到 `ready=true` | | `watch_auto_analysis` | 观察 (watch) 自动分析进度(不会驱动或取消它) | | `set_analysis_note` / `get_analysis_context` | 用于状态恢复的服务器端上下文跟踪 | | `prune_context` | 清除缓存的输出和已标记函数的缓存以释放内存 | | `py_eval` *(可选开启)* | 在 IDA 中执行 Python —— 仅在使用 `--enable-py-eval` 时注册。每次调用后会使缓存失效(使用 `read_only=true` 可保持缓存)。参见 [安全模型](#%EF%B8%8F-security-model--read-before-exposing-the-port)。 | ### 写入与导入 (Tier 2) | 工具 | 描述 | |------|-------------| | `annotate_function` | 针对函数批量重命名 + 重定义类型 + 加注释 → 返回更新后的伪代码 | | `set_metadata` | `action`=set_name, delete_name, 或 set_comment (`scope`=address/function/decompiler) | | `set_type` | `target`=function (prototype), global (C type), 或 lvar (C type + `function_address` + `lvar_name`) | | `make_function` | 在指定地址创建函数 | | `import_metadata` | `format`=il2cpp (script.json + il2cpp.h) 或 flutter (flutter_meta.json) | ## 配置 ### 命令行参数 ``` --bind Bind interface (default 127.0.0.1; use 0.0.0.0 only behind an auth proxy) --port HTTP port (default: from config.json) --config Config file path (default: config.json) --worker Python worker script path --max-sessions Max concurrent sessions --session-timeout Session idle timeout (e.g. 4h) --debug Verbose logging --enable-py-eval Register the py_eval tool (arbitrary Python in the IDA worker — RCE primitive) --allowed-roots Restrict agent-supplied paths to these dirs (OS-path-list separated; empty = unrestricted) ``` ### 环境变量 ``` 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-path-list separated; empty = unrestricted ``` ### config.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": [] } ``` ## 开发 ``` make build # Build server make test # Run tests make proto # Regenerate protobuf (requires protoc) make clean # Clean artifacts make inspector # Launch MCP Inspector at localhost:5173 ``` ### 项目结构 ``` ida-pilot/ ├── cmd/ida-pilot/ # Server entry point ├── internal/ │ ├── server/ # MCP tool handlers, caching, tiers │ ├── session/ # Session registry + persistence │ └── worker/ # Python worker process manager ├── proto/ # Protobuf service definitions └── python/worker/ # idalib wrapper + Connect RPC server ``` ## 贡献 欢迎提交贡献 —— 有关环境设置、本地测试门槛及规范,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。 如需私下报告安全问题,请参阅 [SECURITY.md](SECURITY.md)。 ## 许可证 MIT
标签:EVTX分析, Go, IDA Pro, MCP, Python, Ruby工具, 云资产清单, 无后门, 日志审计, 服务端, 逆向分析辅助, 逆向工具, 逆向工程