ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

REA 逆向工程:拆解它把 IDA、Ghidra 变成 AI 工具的核心机制

REA 逆向工程:拆解它把 IDA、Ghidra 变成 AI 工具的核心机制

逆向工程一直是个高度依赖人的手艺活:打开 IDA 或 Ghidra,对着反编译窗口一点点抠。morluto 开源的 REA(Reverse Engineer Anything)想做的是把这件事交给 AI 代理来干,而且不是泛泛地"让大模型看代码",而是给代理一套能可靠调用的逆向工具面。

看懂 REA 的关键,不在于它"能不能逆向",而在于它怎么把散落、笨重、各说各话的逆向工具,整理成 Agent 可以稳定驱动的东西,还顺手解决了"本地、只读、有证据"这几个硬约束。下面拆的,是它最底层的五套机制。

机制一:MCP 原生,不是脚本封装

REA 本质上是一个 MCP Server,而不是一个命令行包装器。这是理解它全部设计的第一块基石。

传统思路是写个脚本,让 AI 去 shell 里跑命令、读 stdout。REA 走的是另一条路:它把逆向能力注册成 MCP 的标准工具(tools),Agent 通过tools/call去调用,拿回结构化结果。代理和工具之间隔了一层标准协议,而不是一段拼接的命令行。

这层协议带来的不是"花活",而是几个实打实的能力。

  • 工具发现代理启动时不靠猜,而是向catalog询问"你现在有哪些工具、各自要什么参数"。
  • 入参契约每个工具的参数都有 JSON Schema,调用前就被校验,坏入参不会进到引擎里。
  • 结构化返回结果同时给机器(structuredContent)和人(text 渲染),下游代理能直接消费。
  • 进度与取消协议内建 progress token 和取消信号,长任务不会被卡死。

我的判断是:REA 把"逆向"从"人操作软件"变成了"代理调用工具",这一步才是它和一堆 prompt 技巧的根本区别。

机制二:依赖向内,契约居中

再往下看一层,REA 的代码是依赖向内(dependency-inward)分层的,这是它最容易被忽略、却最决定可维护性的设计。

从内到外四层:最中心是领域语义与 MCP 契约(domain / contracts),往外是Provider 适配器(对接 Ghidra、Hopper、IDA、JS、.NET、Android),再往外是CLI 与 MCP 共享的分析工作流,最外层才是CLI / MCP 入口。

依赖方向永远指向内:外层可以调用内层,内层绝不反向依赖某个具体引擎。这条铁律的直接后果是——引擎相关的脏活被死死关在第二层,契约层保持稳定,替换或新增一个逆向后端不会动摇上层。你今天接 Ghidra,明天接别的分析器,对 Agent 暴露的工具面几乎不变。

机制三:证据是一等公民

逆向最怕的不是"答错",是"答得理直气壮但没凭据"。REA 的解法是把证据(Evidence)做成一等公民,让每一次分析的结论都带着来源和不确定性。

具体做法是把结果拆成四类,且显式分离。

  • Observations(观察)直接可见的东西,反编译伪代码、字符串、符号表,来自 provider 的原始输出。
  • Derivations(推导)由观察得出的,调用约定、控制流、调用图,且能回溯到证据。
  • Inferences(推断)带置信度的猜测,“疑似处理密钥”“可能做网络回传”,明确标注要人复核。
  • Unknowns(未知)符号缺失、混淆后的逻辑,直接说"不知道",而不是编。

每条证据都绑一个evidence_id,挂在**当前连接的账本(ledger)**上;调用close_binary时一并清空。大证据还能用inspect_analysis_view(offset)分页取,导出是原子 JSON。

REA 给的不是"答案",是带证据和明确未知的结论。这一点决定了它在安全、审计场景里可用,而不只是一个 demo。

机制四:本地、只读、声明作用域

信任从哪来?REA 的答案不是"我承诺安全",而是在结构上让你无法越界。

三条硬约束。

  • 本地执行所有分析在你的机器上跑,不向任何服务器上传你的二进制或结果。
  • 二进制不可变Ghidra 用临时数据库、IDA 严格只读,永不改写原始字节;静态分析(JS/.NET)只读文件不执行,运行时捕获才走你的权限。
  • 声明式作用域每次调用必须声明它要动的目标(target)和生命周期(lifecycle),server 只执行被声明的那一块。

标注(readOnly / destructive)只是说明,不是访问控制——真正兜底的是那条"只跑声明范围"的规则。destructive 标注覆盖数据丢弃、外部代码执行、设备变更这些危险动作。它不是靠信任,是靠把越界变成不可能。

机制五:Provider 桥接,最难的那块工程

前四点是架构哲学,第五点是把它落地的工程硬骨头:怎么把 Ghidra、Hopper、IDA 这种重型原生引擎,稳稳地包进 MCP。

一次tools/call的真实路径是:Agent 发调用 → REA 校验 Schema、解析声明作用域 → 下沉到 provider。难在 provider 不是温顺的 HTTP 服务。

  • 冷启动很慢Ghidra 拉起可能数十秒,REA 用REA_GHIDRA_STARTUP_TIMEOUT_MS控制,客户端 deadline 还能拉到 240s;等待期间每 10s 发一次通知,但故意不报分析百分比——因为原生引擎根本给不出真实进度。
  • 取消不等于超时取消信号会真正传播到 provider 的工作里,超时只是放弃等待,两回事。
  • 入参字节预算有的 provider(如 Moonshot)拒绝超大 payload,REA 用REA_MCP_INPUT_SCHEMA_PROFILE=compact把每个入参压到 13,312 字节以内。
  • 大输出分页超界结果标resource_constraint并附 inspection 引用,客户端再按需取;REA_MCP_MAX_RESPONSE_BYTES最小 10MB。

桥接层的存在,正是 REA 能把"专家手里的 GUI 工具"翻译成"代理手里的标准工具"的关键。没有这层,Agent 面对的就是一堆各自为政、动不动卡死的引擎。

把这五套机制串起来

MCP 原生是它的接口形态,依赖向内是它抵御复杂度的骨架,证据优先是它对"可信"的定义,本地只读是它赢得信任的方式,Provider 桥接是它真正干苦活的地方。

REA 真正有意思的,不是"AI 会逆向了",而是它把逆向这件事里那些最反人性的部分——零散的工具、不可信的结论、跑不完的长任务——用一套干净的分层和协议重新接了一遍。代理只是最后那个操作者,底座才是真功夫。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进