概览
BinDetective 二进制侦探是面向 AI 时代的轻量化、高并发、多架构二进制反编译与识别引擎, 采用 C++ 开发。它原生支持多款处理器架构,兼容 PE、ELF、Mach-O 三大主流可执行文件格式, 可完成自动化反编译;同时兜底识别十余种常见非二进制文件,自动判别大小端与位数, 覆盖 x86、ARM、AArch64 等主流架构,对部分小众架构可完成名称识别,提升二进制样本的快速分析与适配能力。
Sleigh 指令集描述语言,
因此 Sleigh 规范覆盖的全部处理器架构均被支持——x86(16/32/64)、ARM / AArch64、MIPS、PowerPC、SPARC、
RISC-V、LoongArch、SuperH、68000、V850、TriCore、Xtensa、PA-RISC、PIC、AVR、MSP430、8051、6502、Z80、
JVM、Dalvik、eBPF 等处理器族均在其列,大小端与位数变体一并覆盖。
要确认当前部署实际可用的架构清单,请直接调用 ListLanguages(direct),
其返回的语言 ID 列表即为服务端真实支持的处理器定义。
引擎通过 HTTP POST 对 AI Agent 与后端服务暴露能力。 设计上刻意收敛了协议表面积:只有一个端点、一种方法、一种编码,所有差异都体现在请求体里。
这套结构的直接收益是:Agent 侧不需要为每个能力维护路由表或 SDK 版本,只需一份接口清单与一份参数顺序,即可在无 SDK 的情况下完成调用。
引擎内核与流水线
引擎共计实现 120 余项能力,依托并完整对接 Sleigh 指令集描述语言, 在其基础之上搭载全套自研核心算法,从文件装载到反编译后端的每一段都由自研模块承担。 分析结果逐级增强后送入反编译后端,所有环节可控、可观测、可逐层调参。
- 装载与前端:PE / ELF / Mach-O 文件加载、函数边界扫描、函数序言识别。
- 结构与控制流:控制流恢复、跳转表与间接跳转消解、栈帧与 ABI 分析。
- 类型与中间表示:类型管理与推导、p-code 构造、符号与调试信息注入。
- 运行支撑:任务调度、会话隔离、缓存、异常处理。
三类调用面
- 会话装载与管理(direct,4 项):
Open装载二进制并返回session_id,SessionCreate/SessionList/SessionClose负责空会话的创建、枚举与释放;它们本身不写会话状态,因此不要求携带session(Open成功后会由客户端自动绑定)。 - 会话接口(session,133 项):绑定到某个
session_id的分析能力,如下按功能分组全部列出(点击任意接口名查看签名、参数与调用示例)。 - 无状态分析(direct,11 项):字节流级别的即时分析,如
DisasmBytes、DecompileHex、IdentifyArchitecture、Crc32、AssembleRoundTrip。可任意水平扩展,不占用会话资源。 - 服务信息与控制面(direct,3 项):
ListLanguages、GenerateOpenAPI、HealthStats,用于能力枚举、契约导出与运行状态观测。
bin_detective_client.py 做静态解析(python extract_ifaces.py),
把 151 个接口逐一映射到真实方法,提取其完整签名、参数默认值、docstring 与所在行号,
同时读取源码里的 SUPPORTED_INTERFACES / INTERFACE_MODES / INTERFACE_CALL_INFO 三张注册表,
因此接口文档中看到的每一个参数名、默认值与 mode 标记,都能在源码里逐字对应。
快速开始
1. 准备环境
引擎默认监听 127.0.0.1:8000,鉴权头为 X-Auth-Token。客户端在未显式传入 token 时,按以下顺序取值:
- 环境变量
BINDETECTIVE_TOKEN - 内置默认 Key
DEFAULT_API_KEY
Open 接收的是服务端本地路径,样本文件需对引擎进程可见。2. 安装客户端库
客户端库通过 pip 安装,随库附带的 bin_detective_client.py 即本站接口文档的解析源头:
3. 建立客户端
4. 装载样本
调用 Open 装载二进制文件。引擎会自动判定格式(PE / ELF / Mach-O)、CPU 架构、字节序与位数,并在成功返回时把 session_id 自动绑定到当前客户端。
5. 得出第一份伪代码
取函数列表里的第一个地址,交给 Decompile 得到 C 代码:
session,引擎不提供隐式的“当前会话”回退。
直接调用底层 call() 而未传 session 时,服务端会返回 E_SESSION_REQUIRED。
传输层约定
以下三条约定不是建议,而是引擎稳定运行的前提,尤其在与 mongoose 类轻量 HTTP 服务端通信时。
请求格式
为什么必须使用 Connection: close
引擎对重接口(尤其是 Open 与首次 Decompile)在 keep-alive 长连接下可能出现不响应或挂起。
官方客户端因此改用 raw-socket + Connection: close 的直连方式,并在读取响应时按 Content-Length 读满 body 即返回,
不等 EOF —— 服务端对 close 未必立即断开,等待 EOF 会白白耗到超时。
Connection: close、读完 Content-Length 声明的长度即关闭。
这三步是稳定的关键,比复用连接池更重要。
响应信封
所有接口返回同一结构,便于统一处理:
status 仅取 success / error;code 在成功时为 null,失败时为字符串错误码;
业务数据一律放在 result 中,即使失败也可能带有部分上下文(如错误原因 result.error)。
参数规范
params 是一个按位置排列的字符串数组,而不是对象。这带来两个必须遵守的规则:
- 顺序即语义:不同接口同一位置的含义不同,调用前请核对接口详情页的参数表。
- 尾部空串自动裁剪:
None会被转为空串并从尾部裁掉,因此call("X", ["a", None])与call("X", ["a"])等价。但中间的空串不会被裁掉,需要占位时请显式传""。
地址的写法
地址类参数(address / func_addr / at / base)按字符串下发,int 与 "0x…" 两种写法服务端都能接受,客户端仅在 validate_hex_address() 中把它们规范化:
地址串中的空白字符与转义空白标记(\t、\r、\n、\v、\f)在 validate_hex_address() 与 _addr() 中会被自动移除,避免长地址在传输或复制过程中被截断;_addr() 遇到无法解析的地址会抛 ValueError,而各接口方法本身只做最小化的字符串转换(str(base) 等),不会主动校验地址。
语言 ID
形如 x86:LE:64:default:gcc,由「处理器 : 字节序 : 位数 : 变体 : 编译器」构成。Open 与字节流类接口的 language 参数可省略(自动识别)或显式指定(强制覆盖)。枚举全部可用 ID 请调用 ListLanguages。
返回模式:str 与 json
客户端 Config(response=…) 支持两种模式,避免调用方重复解析:
会话管理
会话是引擎的核心隔离单元:每个会话持有独立的镜像、分析结果、重命名、注释、补丁与覆写状态。多个会话可以并行存在,互不干扰。
生命周期
关闭会话时的陷阱
服务端解析“目标会话”的优先级为:请求 session 字段 > params[0] > 当前会话。若客户端已绑定了 config.session,直接把目标 ID 放进 params[0] 会被当前的 session 字段覆盖,从而误关其它会话。官方客户端为此把目标 ID 显式写进 session 字段:
状态持久化
SessionSave 可把种子、标号、equates、补丁等状态导出为 JSON(path 为空则内联返回),SessionLoad 从文件或内联 JSON 恢复,前提是已装载同一镜像。适合长任务断点续跑与结果归档。
direct 与 session 的区别
引擎的接口注册表对每个接口声明了 mode。这是调用前最需要确认的一件事:
call() 的 mode 参数可选,用于与服务端注册表做双重校验;
不传时服务端按注册表行为处理 —— 会话域缺 session 即返回 E_SESSION_REQUIRED。
在 接口文档 中,每个接口名前的 D / S 标记即对应上述两类。
推荐分析流水线
面向上千个样本批量处理时,建议按下面的顺序组织调用,兼顾质量与开销:
每一步都可以单独取用 —— 比如只做架构识别(IdentifyArchitecture,direct),无需装载完整镜像即可完成样本归类。
错误码
失败响应的 code 字段是唯一稳定的判定依据,请勿依赖 result.error 的文案内容。
| 错误码 | 层级 | 含义与处理建议 |
|---|---|---|
E_SERVER_UNAVAILABLE | 客户端 | TCP 探测失败,引擎进程未启动或端口不通。检查服务是否在 8000 端口监听。 |
E_CONN_REFUSED | 传输 | 连接被拒绝。目标地址 / 端口错误,或防火墙拦截。 |
E_TIMEOUT | 传输 | 请求超时。重接口(Open、AnalyzeAll、BatchDecompile)建议单独调大 timeout。 |
E_REQUEST_FAILED | 传输 | 其它传输层异常,result.error 含具体原因。 |
E_SESSION_REQUIRED | 业务 | 会话域接口未提供 session_id。先调用 Open 或 SessionCreate。 |
E_READONLY | 业务 | 只读模式下尝试写操作,如 PatchBytes 在只读会话中被拒。 |
check_server_available 装饰器,调用前做一次带 TTL 缓存的 TCP 探测(默认 probe_ttl=10s),
引擎宕机时快速失败而不阻塞 —— 这一点在 Agent 循环调用中尤其重要。
自描述与 OpenAPI
引擎可自我描述,无需手工维护契约文档:
GET /→ 返回plugin_info:版本、接口总数、会话 TTL、interface_modes与支持的语言列表。客户端对应server_info()(返回原始字符串)与server_info_json()(返回 dict)。GenerateOpenAPI(direct)→ 实时生成 OpenAPI 契约,可直接导入 Postman / Swagger UI。客户端generate_openapi()默认返回 JSON 字符串,落盘前无需再序列化。HealthStats(direct)→ 运行期统计:请求数、耗时、错误数,用于容量观测。
server_info_json() 外,其余方法在默认 response="str" 下都返回 JSON 字符串;要直接取字段请用 parse_response() 解析,或在构造客户端时传 Config(response="json")。最佳实践
1. 会话按任务而非按请求创建
分析一个样本的多个函数应当在同一个会话内完成 —— 反编译结果、类型推导与交叉引用是相互增强的。为每个函数新建会话会显著降低输出质量。
2. 批量场景用批量接口
需要多个函数的伪代码时,用 BatchDecompile / BatchSession 传入地址 JSON 数组,比逐条 Decompile 减少往返开销。
3. 先修正,再反编译
遇到间接跳转误判时,OverrideAdd、OverrideFlow、OverrideProto 能显著改善后续输出;符号缺失时,PdbLoad / DwarfLoad / FidbMatch 注入种子与签名会带来质量跃升。
4. 用仿真验证假设
Emulate / EmulateEx / EmulateWatch 可对函数做字节级仿真与单步观察,用于验证解密算法、解包逻辑等关键路径,而无需真正执行样本。
5. 始终处理空结果
剥离符号的样本上,类型表、导出表、字符串表可能为空。业务代码应把“空”与“失败”区分开:前者是 status=success 但 result 为空集合,后者才是 status=error。