DavidClawson/ripcord
GitHub: DavidClawson/ripcord
ripcord 是一个固件逆向工程流水线,将不透明的嵌入式二进制文件通过确定性分析、执行验证和 LLM 驱动转化为可查询的结构化事实数据库。
Stars: 2 | Forks: 0
# ripcord
**输入不透明的固件二进制文件,输出可查询的事实数据库 —— 只需一条命令。**
ripcord 是一个用于逆向工程嵌入式固件的研究 pipeline。
它接收一个没有符号、没有源代码且带有未记录硬件外设的二进制文件,并将其扩展为一个结构化的事实仓库 —— 包括函数、调用图、MMIO 访问模式、反编译的 C 代码、行为 trace —— 确定性分析器、形式化方法和 LLM agent 都可以对其进行查询,而无需重新读取原始字节。
其主要目标是 **FNIRSI 2C53T 示波器**(AT32F403A MCU + 不透明的 Gowin FPGA)。该固件中最困难、最有价值的部分是 FPGA 采集路径 —— 即与*没有公开文档和源代码*的芯片进行通信的时序关键代码。了解 FPGA 工作原理的唯一方法是观察 MCU 与它的交互。ripcord 旨在捕获该对话,并将其转换为经过执行验证的协议 spec。
## 一图胜千言的理念
```
firmware.bin
│
▼
┌───────────────────┐ deterministic, runs in minutes, no human judgment
│ IDENTIFY │ ISA · load address · chip family (scripts/identify.py)
├───────────────────┤
│ EXTRACT (Ghidra) │ functions · calls · blocks · xrefs · strings
│ │ pcode · decompiled C (PyGhidra headless)
├───────────────────┤
│ RECOVER │ vector tables, func-ptr dispatch, veneers, registrars
│ │ → closes the call-graph reachability gap
├───────────────────┤
│ CLASSIFY │ SVD-resolved peripheral register access · fingerprint
│ │ match library code across compilers
├───────────────────┤
│ TRACE (Renode) │ boot the binary, capture MMIO transcript = ground truth
└─────────┬─────────┘
▼
┌─────────────────────────────────────────┐
│ THE WAREHOUSE │ per-target Parquet tables,
│ build//tables/*.parquet │ queried with DuckDB.
│ (no database file — Parquet is truth) │ THIS is the artifact.
└─────────┬───────────────────────────────┘
│
┌───────┴────────┬─────────────────┬──────────────────┐
▼ ▼ ▼ ▼
scripts/query LLM agent swarm Unicorn / Renode Claude Code
(SQL / DuckDB) (bulk labeling) (VERIFY by (skills + CLI:
execution) drives it all)
```
两大原则承担了主要工作:
1. **执行是验证预言机 —— 而非编译器。** 关于函数功能的断言需要通过*运行* (Unicorn) 或 *追踪* (Renode) 并将 register/memory/MMIO 的差分与原始状态进行比对来确认。编译器捕获类型错误;执行捕获逻辑错误。任何断言在得到执行支持之前都不会成为规范。这是大多数 RE 工具会跳过的部分(参见[相关工作](#related-work))。
2. **数据库才是产出物 —— 而不是干净的源代码。** 交付成果是关于二进制文件的一组可查询的事实。渲染出的 C 代码(如果存在的话)只是对数据库的后期*视图*,绝不是最终目标。(原因:[`notes/goal-and-approach.md`](./notes/goal-and-approach.md)。)
LLM 的预算仅花费在确定性工具无法解析的*残留部分*。所有机械性的工作 —— Ghidra 提取、库识别、调用恢复、trace 捕获 —— 都在几分钟内无人值守地运行。
## 快速开始
```
# 在进行完整运行前识别 ISA / load address / chip
scripts/identify.py firmware.bin
# 一条命令:识别 → 提取 → 摄取 → 恢复调用 → 分类 → 汇总
scripts/ripcord.py firmware.elf # ELF: flags inferred
scripts/ripcord.py firmware.bin --chip AT32F403A --base-addr 0x08004000 # raw binary
# 基于 warehouse + 反编译的 C 代码 + LLM 提问
scripts/analyze --target stock_v120 "what writes to USART2_DR?"
# 全面的自底向上理解:对每个函数进行 smoke-test,为它们命名,
# 分解庞大函数,综合子系统 → 架构叙述
uv run python scripts/agents/deep_analysis.py --target stock_v120
# 生成独立的 HTML 报告
scripts/render/report.py stock_v120
# (可选)通过 MCP 为没有 shell 访问权限的客户端公开 warehouse。
# 主要路径是使用 Claude Code 直接运行上述工具 + 技能。
uv run python scripts/mcp_server.py --build-dir ./build
```
有关工具链的前置条件(带有 PyGhidra 的 Ghidra 11.2+、Python 3.11+、`uv`、Snakemake、DuckDB;以及可选的 Renode 和用于构建测试语料库的交叉工具链),请参见 [`SETUP.md`](./SETUP.md)。
## 为什么 harness 才是核心
大多数“LLM + Ghidra”工具会将单个反编译的函数提供给模型,然后询问“它是做什么的?” —— 这是一个没有任何周围上下文的片段。这恰恰在嵌入式 RE 最困难的地方让模型陷入了信息匮乏。
ripcord 颠覆了这一点。确定性 pipeline 首先构建丰富、*可查询*的上下文;然后由 **Claude Code 驱动** —— 直接运行 CLI 工具和技能 (`.claude/skills/`),以迭代地精确提取所需的表、反编译主体、外设映射和执行 trace,同时将二进制文件作为一个整体进行推理,并在任务需要时针对特定目标*在执行中途构建新工具*。可重用的过程固化为技能(`firmware-bringup`、`execution-verify`);经过执行验证的结论会存入合约账本(`scripts/contracts/ledger.py`)中,这是持久的产物。单次执行的 API 路径(`scripts/analyze`、agent 群)保留用于低成本的、限定范围的、*可衡量的*子任务 —— 例如指纹匹配、批量函数标注 —— 在这些任务中,单一的片段确实足够了。[MCP server](./scripts/mcp_server.py) 作为可选的互操作方式保留,适用于无法运行 shell 的客户端;它不是主要的操作界面,因为 ripcord 的数据是本地 Parquet,驱动程序已经可以直接读取。理解能力存在于 harness 中,而不是访问协议中。
## 仓库里有什么
在 `build//tables/` 下,执行一次 `snakemake --cores 4 --resources ghidra=1` 会为每个目标生成带类型的 Parquet 表。agent 和验证阶段会增加更多内容。亮点:
| 表 | 粒度 |
|------------------------|--------------------------------------------------------------|
| `functions` | Ghidra 发现的每个函数占一行(包含 `body_hash`) |
| `calls` / `xrefs` | 调用点;非调用引用(读取、写入、跳转、数据) |
| `basic_blocks` | 每个 CodeBlock 占一行,带有包含它的函数 |
| `strings` | 已加载内存中定义的字符串 |
| `decompiled` | Ghidra 反编译的伪 C 代码,每个函数占一行 |
| `pcode_features` | 每个函数的 P-Code 操作码直方图 + 序列哈希 |
| `recovered_calls` | 恢复的间接调用边(向量表、函数指针等) |
| `peripheral_xrefs` | SVD 解析的外设寄存器访问 |
| `mmio_events` | 来自 Renode trace 的 MemoryIORead/Write,可通过 PC 连接 |
| `unicorn_smoke` | 每个函数的可执行性(捕获代码与数据的错误解码) |
| `ground_truth_functions` | `nm -S` 符号,回归测试的信号 |
所有表都会被 `scripts/query` 自动发现为 DuckDB 视图。[`notes/queries/`](./notes/queries/) 目录保存了提交的 SQL,它们既是可执行的文档,也是回归测试。
## 当前状态 (2026-05)
阶段 0 已完成;阶段 1 库识别已端到端验证,包括在经过 strip 处理的二进制文件上的盲恢复;阶段 3 agent 群已端到端验证。Renode trace 捕获和 Datalog (Souffle) 推导已接入 Snakemake DAG。深度分层分析、上下文丰富化和 Unicorn 执行验证在此基础之上构建。
仓库中存在**跨越四个构建生态系统的 15 个目标**:5 个 Raspberry Pi Pico (Cortex-M0+)、2 个 Zephyr (Cortex-M3)、1 个经过 strip 处理的盲恢复目标、3 个 AT32F403A 参考构建(GCC + LLVM,交叉编译器语料库),以及 4 个原始的 FNIRSI 2C53T 固件版本 (V1.0.3–V1.2.0) —— 它们既是主要目标,*也是*其自身的差分 ground truth。
得出的一些实证结果(完整列表和来源见 [`CLAUDE.md`](./CLAUDE.md) → “Key empirical findings”):
- **经过 strip 处理的二进制文件的盲恢复:86.6% 召回率,94.9% 精确率** —— 在零符号的情况下重新识别了 171/197 个函数。
- **计算调用的恢复将不可达率的缺口从 70% 缩小到 12%**,通过五种恢复机制实现了约 95% 的混合精确率。
- **基于常量的指纹识别:跨编译器 100% 精确率。**
- **执行能捕获静态分析无法捕获的内容** —— Unicorn 冒烟测试标记了 Ghidra 将数据解码为代码的情况,这是原始导入的第一大失败模式。
- **FNIRSI V1.0.3→V1.0.7 的过渡是对 FPGA 采集路径的全面架构重写**(仅 USART2 → DMA/SPI3),这是通过与 GCC 参考构建的逐字节相同的 FreeRTOS 移植代码确认的。
## 相关工作
ripcord 的各个独立要素都已经存在;而它们的组合 —— 一个结构化的事实仓库**加上**以执行作为验证的预言机,**再加上**一个由技能驱动且带有来源追踪合约账本的 Claude Code harness,旨在*理解*不透明的二进制文件 —— 这是我目前在其他地方没有见到过的组合。客观的定位:
- **LLM + 反汇编工具**(Gepetto、G-3PO、aiDAPal、DeGPT)主要是将反编译的代码片段发送给模型,然后回写重命名/注释。ripcord *首先*构建可查询的上下文,因此模型永远不会在没有上下文的情况下进行推理。
- **持久化的结构化状态不再是一个差异化优势。**
[GhidrAssist](https://github.com/jtang613/GhidrAssist)(开源,具有 5 级层次结构的 SQLite+图知识数据库)和 **Binary Ninja**
Sidekick**(商业软件,带有出处追踪和后台验证 agent)都构建了它。ripcord 的区别在于 **它们的验证是静态的** —— 重新分析和交叉引用查询 —— 而 ripcord 对每个规范断言都通过*执行*来进行把关。
- **基于反汇编器的 MCP 只是基本要求 —— 而且这并不是 ripcord 的价值所在。**
[GhidraMCP](https://github.com/LaurieWired/GhidraMCP)(9k+ stars)和
[IDA Pro MCP](https://github.com/mrexodia/ida-pro-mcp) 很成熟;它们通过协议公开*实时的工具调用*。ripcord 仅将 MCP 界面作为可选的互操作方式保留 —— 驱动程序(Claude Code)通过 CLI 直接读取本地仓库,因此访问协议是附带的。界面背后那些东西 —— *包含经过执行验证事实的仓库*以及生成它的技能 —— 才是有趣的部分。
- **将二进制分析视为数据库的做法早于 ripcord** ——
[ddisasm/GTIRB](https://github.com/GrammaTech/ddisasm)(它与 ripcord 共享 Souffle/Datalog 层)和 CodeQL。ripcord *使用*了该技术;它并没有发明它。
- **固件重新托管**(PRETENDER、P2IM、DICE、Fuzzware)已经从 trace 中推断出了 MMIO 外设模型 —— 但其交付成果是“足以进行 fuzzing 的模型”,而**不是**一个清晰、可证伪的 MCU↔外设协议 spec。
输入类别相同,输出不同。ripcord 旨在得到那些工具所遗漏的、清晰易读的边界合约。
- **匹配源代码的反编译**(decomp.me、N64/PSX 项目)通过逐字节相同的重新编译进行验证 —— 这是比 ripcord 的行为执行差异*更严格*的预言机,但其目标是完美的源代码恢复,而 ripcord 明确**不**打算产生这种结果。
- **与核心论点最接近的先例:** Patrick Hulin 的
[SimTower 重新实现](https://phulin.me/blog/simtower) 将 LLM 置于一个以 Unicorn 模拟器作为 ground truth 的闭环中 —— 与执行作为预言机的理念相同,但这是一个一次性项目,而不是通用的 pipeline。
## 深入了解
- [`CLAUDE.md`](./CLAUDE.md) — 密集且权威的项目导向:包含每个脚本、每个表、每个提交的查询以及当前发现。
- [`notes/`](./notes/) — 设计日志和 FNIRSI 目标档案。从
[`notes/README.md`](./notes/README.md) 开始。关键文件:
[`design-decisions.md`](./notes/design-decisions.md)(做出每个选择的原因),
[`pipeline-architecture.md`](./notes/pipeline-architecture.md),
[`scope_acquisition_spec.md`](./notes/scope_acquisition_spec.md)(MCU↔FPGA 协议),和
[`renode-at32-bringup.md`](./notes/renode-at32-bringup.md)(实际运行中的 FPGA 模拟预言机)。
## 范围、客观性与 FPGA 注意事项
ripcord 有意保持**通用性**。范围固件是试验场,而不是将 2C53T 的特性硬编码到核心 pipeline 中的借口 —— 目标知识存在于 `notes/` 和查询中,而绝不存在于提取器中。FPGA 的时序代码*没有外部的 ground truth*。ripcord 会为每个断言标记来源级别,并且绝不将推断出的 FPGA 行为呈现为既定事实:内部的调度/选择器代码并不是 wire 级别的硬件事务,而且观察到的是固件*写入*的值,而 stub *虚构*的回复在得到硬件 trace 确认之前都是未经验证的。这种原则正是执行预言机存在的全部理由。
## License
[MIT](./LICENSE)。本仓库**不**包含 pipeline 分析的固件二进制文件;其版权属于原作者。测试语料库基于开源 SDK(Pico SDK、Zephyr、AT32 SDK)构建,或由用户提供。
标签:Ghidra, 云安全监控, 云资产清单, 固件分析, 嵌入式系统, 逆向工具, 逆向工程, 静态分析