banteg/bn
GitHub: banteg/bn
面向 AI 编码智能体的 Binary Ninja CLI 工具,通过桥接运行中的 GUI 实例实现自动化逆向分析,支持结构化输出、变更预览和批量操作。
Stars: 32 | Forks: 1
# bn
`bn` 是一个面向编码智能体(coding agent-first)的 Binary Ninja CLI 工具。它为 shell 会话或工具调用智能体提供稳定的命令、结构化输出,并访问你已在 GUI 中打开的同一个实时 Binary Ninja 数据库。
## 核心功能
- 从 shell 查询实时 Binary Ninja 状态:目标、函数、反编译文本、IL、反汇编、交叉引用 (xrefs)、类型、字符串、导入以及可复用的 bundle。
- 在 Binary Ninja 进程内执行 Python,无需维护独立的 headless 工作流。
- 使用 `--preview` 应用变更,捕获反编译差异,并在报告成功前验证实时后置状态。
- 输出结构化的 `json` 或 `ndjson`,大数据集自动溢出到文件,并返回 token 计数以便智能体合理规划上下文。
## 安装
推荐设置:安装 CLI、Binary Ninja 伴侣插件以及捆绑的 Codex skill。
在 PATH 中安装 CLI:
```
uv tool install -e .
```
安装 Binary Ninja 伴侣插件:
```
bn plugin install
```
这会将 [`plugin/bn_agent_bridge`](/Users/banteg/dev/banteg/bn/plugin/bn_agent_bridge) 链接到你的 Binary Ninja 插件目录。
安装捆绑的 Codex skill:
```
bn skill install
```
这默认会将 [`skills/bn`](/Users/banteg/dev/banteg/bn/skills/bn) 符号链接到 `$CODEX_HOME/skills/bn`。如果你想要一个独立副本,请使用 `--mode copy`。重启 Codex 以加载新增或重命名的 skill。
如果插件代码发生更改,请重新加载 Binary Ninja Python 插件或重启 Binary Ninja。
## 工作原理
- `bn` 由两部分组成:
- 一个普通的 Python CLI,可从 shell 或智能体工具框架运行
- 一个 Binary Ninja GUI 插件,拥有所有 Binary Ninja API 访问权限
- 该插件创建一个固定的 bridge socket 和一个固定的注册表文件。
- CLI 发现该 bridge,连接到它,并将命令转发到实时 GUI 会话中。
- 因为 Binary Ninja 端作为 GUI 插件运行,所以它可以使用个人许可证,无需商业 headless 许可证。
## 快速入门
在 Binary Ninja 中打开一个二进制文件或 `.bndb`,然后运行:
```
bn doctor
bn target list
bn refresh
bn function list
bn decompile sub_401000
```
如果恰好打开了一个 BinaryView,特定于目标的命令可以完全省略 `--target`。如果打开了多个目标,请从 `bn target list` 中传递 `--target `。
## 目标选择
使用 `bn target list` 查看可用目标:
```
bn target list
```
可以通过以下方式选择目标:
- `active`
- `bn target list` 中的 `selector` 字段
- 完整的 `target_id`
- BinaryView 基名
- 完整文件名
- view id
在常规使用中,建议使用 `selector` 字段。对于单个打开的数据库,这通常就是 `.bndb` 基名:
```
bn decompile update_player_movement_flags --target SnailMail_unwrapped.exe.bndb
```
## 输出行为
每个命令都支持:
- `--format json`
- `--format text`
- `--format ndjson`
- `--out `
交互式读取命令默认为 `text`。变更、设置和导出命令默认为 `json`。
当你需要稳定的字段用于自动化或管道传输到结构化工具时,请添加 `--format json`。
示例:
```
bn function list --format ndjson
bn function list --min-address 0x401000 --max-address 0x40ffff
bn function search --regex 'attach|detach'
bn decompile sample_track_floor_height_at_position --out /tmp/floor.json
```
如果设置了 `--out`,命令会将渲染结果写入该路径,并打印一个紧凑的 JSON 封装,其中包含 artifact 路径、字节大小、token 计数、tokenizer、哈希和摘要。智能体可以使用该封装来决定是读取完整的 artifact、保留摘要,还是推迟将其加载到上下文中。
唯一的例外是 `bn bundle function`,它从 bridge 内部写入 bundle artifact 并将封装打印回 CLI。
`bn function list` 和 `bn function search` 返回所选目标或地址范围的完整匹配集。大型结果会自动溢出到 artifact,而不是强制手动分页。溢出是基于 token 的,当前在超过 20,000 个 token 时触发,CLI 还会发出 stderr 警告,其中包含 artifact 路径和有用的大小计数。
## 提取命令
常见的只读命令:
```
bn target list
bn target info
bn function list
bn function list --min-address 0x401000 --max-address 0x40ffff
bn function search attachment
bn function search --regex 'attach|detach|follow'
bn function info end_track_attachment_follow_state
bn proto get end_track_attachment_follow_state
bn local list end_track_attachment_follow_state
bn refresh
bn decompile end_track_attachment_follow_state
bn il end_track_attachment_follow_state
bn disasm end_track_attachment_follow_state
bn xrefs end_track_attachment_follow_state
bn xrefs field TrackRowCell.tile_type
bn comment get --address 0x401000
bn types --query Player
bn types show Player
bn struct show Player
bn types declare --file /path/to/win32_min.h --preview
bn strings --query follow
bn imports
```
`bn function search` 默认保持不区分大小写的子字符串匹配。当你需要正则表达式时,请添加 `--regex`。`bn function list` 和 `bn function search` 都接受 `--min-address` 和 `--max-address` 来按函数起始地址过滤。
## Bundle 与 Python
`bn decompile` 是 HLIL 文本的便捷通道。它对于快速读取函数很有用,但类型布局仍以 `bn types show` 和 `bn struct show` 为准。
导出可复用的函数 bundle:
```
bn bundle function end_track_attachment_follow_state --out /tmp/end_track_attachment_follow_state.json
```
在 Binary Ninja 进程内运行 Python。这是一流的一次性检查和 BN 原生脚本工作流,而不仅仅是后备方案:
```
bn py exec --code "print(hex(bv.entry_point)); result = {'functions': len(list(bv.functions))}"
bn py exec --stdin <<'PY'
print(hex(bv.entry_point))
result = {"functions": len(list(bv.functions))}
PY
```
对于多行代码片段,建议使用 `--stdin` 或 `--script`。`--code` 接收一个 shell 参数,因此普通双引号内的 `"\n"` 保持为字面量反斜杠-`n` 对,而不会变成换行符。
```
bn py exec --stdin <<'PY'
out = []
for f in bv.functions:
if 0x416000 <= f.start < 0x41C000:
out.append((f.start, f.symbol.short_name))
out.sort()
print("\n".join(f"{addr:#x} {name}" for addr, name in out))
PY
bn py exec --code $'print(hex(bv.entry_point))\nresult = {"functions": len(list(bv.functions))}'
```
`py exec` 环境包括:
- `bn`
- `binaryninja`
- `bv`
- `result`
Stdout 和 `result` 都会被返回。如果 `result` 不可 JSON 序列化,`bn` 会返回 `repr(result)` 并包含警告,而不是静默地将整个响应字符串化。
## 变更命令
变更遵循与其他特定目标命令相同的目标选择规则。
示例:
```
bn symbol rename sub_401000 player_update --preview
bn comment set --address 0x401000 "interesting branch" --preview
bn comment get --address 0x401000
bn proto get sub_401000
bn proto set sub_401000 "int __cdecl player_update(Player* self)" --preview
bn local list sub_401000
bn local rename sub_401000 0x401000:local:StackVariableSourceType:-20:2:12345 speed --preview
bn local retype sub_401000 0x401000:local:StackVariableSourceType:-20:2:12345 float --preview
bn types declare "typedef struct Player { int hp; } Player;" --preview
bn struct field set Player 0x308 movement_flag_selector uint32_t --preview
```
预览模式会应用更改、刷新分析、捕获受影响的反编译差异,然后回滚变更。
非预览写入仅在读回实时 BN 会话并验证请求的后置状态实际生效后才报告成功。如果验证失败,CLI 会返回非零退出代码并回滚整个变更或批次。
对于声明和结构变更,预览结果还包括带有前后布局和统一差异的 `affected_types`。如果字段编辑已完全相同,结果将标记为 `changed: false` 和 `No effective change detected` 消息。
对于前几个更改的函数,`affected_functions` 还包含简短的 `before_excerpt` 和 `after_excerpt` 代码片段,位于第一个更改的 HLIL 行附近。
变更结果现在区分:
- `verified`
- `noop`
- `unsupported`
- `verification_failed`
当验证失败时,JSON 输出还包括失败操作的 `requested` 和 `observed` 状态。
`bn types declare` 现在在可用时使用 Binary Ninja 的源解析器。当你传递 `--file` 时,CLI 还会转发源路径,以便相对包含的解析方式与 GUI 中导入头文件时相同。
如果声明仅解析函数或外部变量且未引入任何要持久化的命名类型,`types declare` 将返回已验证的 no-op,而不是因 `No named types found in declaration` 而失败。
`bn local list` 和 `bn local info` 为参数和局部变量返回稳定的 `local_id` 值。建议在 `bn local rename`、`bn local retype` 和批次清单中使用这些 ID;旧式的基于名称的定位仍可兼容使用。
## 批次清单
`bn batch apply` 接受 JSON 清单:
```
{
"target": "SnailMail_unwrapped.exe.bndb",
"preview": true,
"ops": [
{
"op": "rename_symbol",
"kind": "function",
"identifier": "sub_401000",
"new_name": "player_update"
},
{
"op": "set_prototype",
"identifier": "player_update",
"prototype": "int __cdecl player_update(Player* self)"
}
]
}
```
使用以下命令应用:
```
bn batch apply manifest.json
```
批次应用默认验证实时会话。如果任何操作应用失败或后置状态验证失败,整个批次将被回滚。
## 故障排除
检查 bridge 状态:
```
bn doctor
```
如果 `bn target list` 为空:
- 确保 Binary Ninja 已打开
- 确保二进制文件或 `.bndb` 已打开
- 确保已使用 `bn plugin install` 安装插件
- 在插件更改后重新加载 Binary Ninja 插件或重启 Binary Ninja
如果 `active` 有歧义,请从 `bn target list` 传递 `--target `。
如果类型更改后反编译文本看起来仍然陈旧,请运行:
```
bn refresh
```
这会强制分析刷新,但在某些情况下可能仍无法完全消除 Binary Ninja 陈旧的 `__offset(...)` 呈现。
## 开发
使用以下命令运行测试:
```
uv run pytest
```
从仓库运行 CLI 而不全局安装:
```
uv run bn --help
```
标签:Binary Ninja, CLI 工具, DevSecOps, DLL 劫持, Headless, Homebrew安装, LLM 工具链, Python 插件, Software Security, URL提取, Wayback Machine, 上游代理, 二进制分析, 二进制逆向, 云安全运维, 云资产清单, 交互式安全, 反汇编, 反编译, 大语言模型, 情报收集, 插件开发, 漏洞研究, 结构化输出, 自动化分析, 跨站脚本, 跨进程通信, 逆向工具, 逆向工程