Elytra
AI

REA:让 Agent 带着证据做逆向工程

从架构、Evidence 与调查工作流理解 REA,再用 DX-Ball 的小函数闭环和 Enshrouded 的大型体素调查,说明它能做什么、怎样判断成果是否可靠。

拿到一款没有源码的程序,想知道某个功能怎样实现,往往要不断切换视角:搜索字符串,检查交叉引用,读反编译结果,回到汇编确认类型,再找调用者和资源数据。真正困难的是,把这些零散观察组织成能够检验的解释。

REA(Reverse Engineer Anything)把这套调查过程接到了 Agent 的工具链上。Agent 可以通过统一接口检查程序、追踪局部代码,并把结果用于解释或重实现。它的价值值得从三个问题理解:谁负责分析,结论怎样保留依据,以及怎样完成验证闭环。

本文对应的版本与案例

本文于 2026 年 10 月 22 日整理。架构与接口说明主要核对 REA 源码提交 d0067ba;我们的 Enshrouded 调查使用 npm 包 rea-agents@6.7.0 与 Ghidra 12.1.4。文中的工具名以这次环境为参照,具体可用能力仍应读取所连接服务的工具清单。DX-Ball 部分引用项目方公开的调查与验证记录,本文没有重新运行其原始程序或编译器验证。

1先区分逆向工程、反汇编与反编译

正向开发从需求、设计与源代码出发,经过编译和构建得到可执行程序。**逆向工程(Reverse Engineering)则从已经存在的程序和它的行为出发,推断背后的数据结构、算法与设计决策。**它并不要求研究对象一定是机器码:网页脚本、Android 字节码、资源文件与网络协议同样可以作为观察对象。

概念要解决的问题结果的局限
反汇编(Disassembly)机器码对应哪些处理器指令?指令中的地址与寄存器不会自动变成有意义的业务概念
反编译(Decompilation)能否把低级指令恢复成更易读的伪代码?变量名、类型、签名和控制流可能是推断结果
逆向工程(Reverse Engineering)软件为什么呈现某种行为,内部如何协作?需要结合多处证据、运行观察与独立验证

比如看到 return __ftol(),只知道程序调用了浮点转整数例程,却还不知道浮点数来自哪里。要理解一个音频声像计算,就需要再追参数来源、运算指令、常量和使用结果的函数。后文的 DX-Ball 案例正好展示了这一过程。

逆向的终点不是一份看起来像源代码的文本

更有价值的成果是可以检验的解释:输入如何产生,处理规则是什么,输出流向哪里,以及一个独立实现能否在明确的测试条件下复现行为。

2REA 是什么?

REA 是一个采用 MIT 许可证的开源逆向工程工具项目,提供 MCP 服务、CLI 和配套工作流说明。它把不同分析工具的能力交给 Agent 调用,同时组织目标身份、分析结果、来源位置和限制条件。1

把一次原生程序调查拆开看,几个角色各有职责:

角色负责什么
人提出要理解的行为,决定研究范围和验收标准
Agent规划查询、阅读结果、提出假设、编写解释与测试
REA暴露工具接口,管理分析会话,组织查询和证据
分析引擎执行具体反汇编、反编译、引用与类型查询,例如 Ghidra
验证程序检查重建规则是否符合样本、原程序输出或其他独立依据

在我们的调查中,Ghidra 负责生成伪代码和汇编视图,REA 将这些能力变成可调用的操作;Agent 再根据结果决定下一步读哪个函数。这种分工解释了一个常见现象:**REA 返回了完整的反编译结果,调查却仍然可能只完成一小段。**理解变量含义、确认边界、连接上下游,以及验证重建,仍然需要后续工作。

REA 的范围也不限于原生 EXE。不同目标走不同路径:JavaScript/Electron 包可以进行静态文件与模块分析,.NET 程序可以读取托管元数据和 IL,浏览器相关调查可以结合运行时观察。依赖随目标改变;例如静态 JavaScript/ASAR 分析可以不启动原生反编译引擎。2

3它怎样工作?

从源码结构看,CLI 与 MCP 是两种入口,它们共享应用层工作流。应用层再连接 provider,也就是具体的分析能力提供者;Ghidra 路径还包含运行在其环境中的 Java bridge。下面是省略了许多适配器的结构示意:3

Loading diagram…

Mermaid 源代码

flowchart TD
    H[人提出具体问题] --> A[Agent 选择查询并解释结果]
    A --> M[MCP 工具入口]
    C[终端或脚本] --> L[CLI 入口]
    M --> W[REA 应用层工作流与会话]
    L --> W
    W --> P[Provider 适配层]
    P --> G[Ghidra / Hopper / IDA]
    P --> S[静态资源与其他专用分析路径]
    G --> E[结果、位置、覆盖范围与限制]
    S --> E
    E --> R[REA Evidence 记录]
    R --> A
    A --> T[解释、原创实现与验证]
    T --> A

可选择文字复制;按 Esc 或点击空白处关闭。

因此,终端用户也能直接使用 REA。Agent 的作用体现在连续调查:它可以从一个异常字符串出发,选择引用点,检查所在函数,发现参数含义不明,再追到调用者。下一次查询由前一次结果推动,而不是预先把所有函数全部反编译一遍。

配套工作流说明则指导 Agent 如何选择目标、处理不确定性和恢复错误。这里可以与Skill、CLI、MCP 的分工联系起来理解:流程说明影响调查方式,CLI 适合脚本与批处理,MCP 方便在持续会话里交互查询。仅仅获得工具列表,还不等于拥有一套可靠的调查方法。

3.1原始操作与组合工作流

REA 提供的工具有不同粒度。以下是本次原生调查实际涉及的几类:

问题工具例子
目标里有哪些字符串或函数?search_strings、list_procedures
谁引用这个地址,它属于哪个函数?xrefs、resolve_containing_procedure
这个函数做了什么?procedure_pseudo_code、procedure_assembly
需要函数的多个视角analyze_function
内存地址处实际保存什么?read_bytes
保留和结束调查export_evidence_bundle、close_binary

例如 analyze_function 可以提供包含伪代码、汇编、调用关系等面的函数档案;可用内容随 provider 和实际分析结果而异。组合查询也有自己的边界:源码中的 executeComposedWorkflow 会收集所用操作报告的限制,再随组合结果保留。上游某一环无法确认的事情,不应在汇总后变成确定事实。4

4Evidence:把“为什么这样判断”留下来

逆向中很容易出现这样的解释:“这个函数看起来像是在生成地形。”但以后再检查时,还需要知道它针对哪个版本、看过哪些指令、哪些部分来自推测。

REA 的 Evidence 把一次观察组织成结构化记录。几个值得阅读的字段是:5

字段回答的问题
subject分析的是哪个制品,内容 SHA-256 是什么?
provider、analysis_profile哪个工具及分析配置产生了观察?
operation、parameters当时执行了什么查询?
normalized_result操作结果是什么?
raw_result是否另有需要保留的原始表示?没有时可以为 null
locations对应哪个地址、文件偏移或制品路径?
limitations、relationship_coverage哪些能力、关系或覆盖范围受到限制?
evidence_links关联哪些其他证据记录?

confidence 使用 observed、derived、inferred 这样的分类,帮助区分观察、推导和推断。它不是一个经过校准的正确率。例如“观察到反编译器输出某段伪代码”,不能直接升级为“伪代码中的类型和签名一定正确”。

源码还会根据记录的语义内容计算 ev_... 标识,并在解析时检查它是否与内容一致。这个标识便于引用和检查记录一致性;它不证明分析引擎永远正确,也不证明记录中的推断已经经过运行验证。6

对调查者而言,最有用的习惯是维护一张很小的表:

当前判断支持依据还缺什么
这里生成一个单元顶点八角读取、跨零边插值、位置写入调用者如何连接相邻单元
这个字段参与材质打包整数读取与移位指令shader 如何解释权重
这个缓存保存碰撞网格命中复制,未命中现场构建地形修改时如何失效

这是我们整理调查结果的方法,并非要求每个条目都由 REA 自动生成。工具保留观察,研究者还需要明确自己正在主张什么。

5一次调查的工作流

5.1先把功能缩成可回答的问题

“逆向这个游戏”很难确定终点。更适合开始的问题是:

找到一个体素单元的顶点生成规则,确认它读哪些采样、怎样计算位置、怎样输出索引;保留证据,并写独立模型检查边界。

这段任务描述已经规定了输入、输出和交付物。即使后面发现还有复杂的 LOD 与位移,也能先完成一个有价值的局部。

5.2固定目标,再选择分析路径

保存版本、SHA-256、平台和工具版本;原生程序再记录地址基准。地址只有绑定到同一个样本才有意义。

随后检查目标性质。原生 PE、托管程序集和 ASAR 即使都来自桌面应用,也可能需要完全不同的工具。对于原生深度分析,REA 会选择并绑定 provider;会话期间,失败会保留原因,而不是悄悄换一个引擎继续给出外观相同的答案。7

5.3从一个锚点建立局部调用链

锚点可以是错误字符串、导出函数、资源字段、UI 事件,或者已经知道的算法常量。典型查询顺序是:

Loading diagram…

Mermaid 源代码

flowchart LR
    A[字符串或资源线索] --> B[引用点]
    B --> C[所在函数]
    C --> D[调用者与参数来源]
    C --> E[被调用者与输出消费者]
    D --> F[可检验的局部解释]
    E --> F

可选择文字复制;按 Esc 或点击空白处关闭。

函数名只提供方向。参数从哪里来、结果交给谁,通常更能确定它的职责。遇到伪代码中的可疑转换、布局或分支,就回到汇编与原始字节核对。

5.4把理解变成独立验证

可以先写解析器、数学模型或小型参考实现。然后区分检查力度:

检查方式能增加哪方面的把握
合成输入与不变量检查模型自身是否一致,边界是否合理
真实文件的尺寸与消费闭合对选定样本的格式理解是否自洽
与原函数输出做差分在受检输入上,重建行为是否一致
固定工具链后的机器码比较在明确编译与重定位条件下,代码单元能否匹配

后两项需要额外的验证环境,也不是每个调查都容易做到。单独通过前两项时,应保留这个区别。

5.5保存结果,交代未知项

最后导出 Evidence、保存适用的 snapshot,并关闭会话。报告应交代确认了哪些局部规则,以及下一次调查最值得从哪里继续。

REA snapshot 保留的是符合条件的查询结果与记录。它依赖目标、参数、provider 和配置的匹配,不等于保存了完整的 Ghidra 原生项目;新的查询仍可能需要重新启动和导入。8

6小案例:DX-Ball 的声像计算

REA 官方展示了 DX-Ball 1.07 的一个小函数调查。目标很具体:砖块横向位置怎样变成左右声像。最初伪代码把函数显示为无参,指令却读取了 [EBP+8];继续追调用者,才确定传入的是砖块屏幕 X 坐标。读取常量后,可以将其核心算术重述为:9

pan⁡(x)=trunc⁡((1.5625x−500)×scale⁡).\operatorname{pan}(x)=\operatorname{trunc}\big((1.5625x-500)\times\operatorname{scale}\big).

在 scale 为 1 的例子里,横坐标 0、320、640 分别得到 -500、0、500。这个结果的意义来自输入含义、指令、常量和转换行为的共同支持。

项目方记录了 3,205 组原始 x86 与重建实现的输出比较,并通过固定 VC4.0 工具链、核对重定位和常量,匹配了这个函数的完整 63 字节。编译器重放是重建项目额外搭建的验证步骤;REA 提供了调查所需的指令、引用与字节观察。10

这个案例具有清楚的局部终点:一个函数的行为和完整代码单元得到了检查。它并不意味着整款游戏已经重建完成。

7大案例:我们从 Enshrouded 得到了什么?

在Enshrouded 体素世界调查中,目标大得多:从磁盘资源一路追到局部网格、渲染打包和碰撞查询。

入口之一是顶点索引溢出的诊断字符串。它帮助定位单元顶点函数;沿调用者继续追踪,逐渐恢复八角采样、十二条边的零交点均值、法线计算与相邻单元连接。再向两端延伸,才接到列解码、标量塑形以及压缩顶点的消费者。11

其中一次有代表性的纠错发生在材料字段上:伪代码让一个读取看起来像 float 转换,汇编却明确是从工作记录 +0x2C 进行整数读取。核对指令后,才能正确恢复位打包。另一处名字带有 brick 上传的入口,最终确认属于水系统,因此没有把它的常数与树结构套到实体地形上。

这次成果可以按验证范围整理:

已取得的结果对应边界
真实列与 brick 解码149 个 tile、6,853 列,7,734 份不同压缩负载还原约 396 万个 u16,受检样本零失败
标量塑形与局部网格模型有合成边界、平面、球面与内腔检查,未与游戏运行输出逐顶点差分
52 字节工作记录到 12 字节顶点恢复一条 mode 0 打包路径,尚未核对实际 shader 解码与帧提交
局部碰撞网格及射线代理追到缓存与未命中构建,编辑后的失效与同步仍待研究

列解码统计来自我们的独立样本验证记录,并不是 REA 自动宣告“格式已完全逆向”。解析器、参考模型和测试由调查过程另行编写。

这里的分工也需要说清:KFC 资源读取借助社区工具和自写 reader;REA 主要连接 EXE 中的函数、指令与引用证据。整个研究成果来自多种工具和人工设定的验证标准,不能全部记作一个 MCP 调用的能力。

我们没有恢复完整的 Holistic Engine。跨 LOD 接缝、全局材料映射、编辑后的多系统一致性和实际 GPU 行为仍有缺口。不过,已经获得的解析器、算法规则、位布局和参考实现,足以成为独立原型的输入。大型目标的进展,应按这些具体模块判断。

8实际使用时,几个容易影响体验的细节

8.1MCP 接通与分析引擎可用,是两项检查

可以先用固定版本检查环境、查看设置计划。以下命令是阅读本文时的示例,不代表安装了 Ghidra:

npx -y rea-agents@6.7.0 doctor --json
npx -y rea-agents@6.7.0 setup --client codex --dry-run

第一条检查环境;第二条查看指定客户端的配置计划。确认计划中的路径与变更后,再按安装指南执行 setup 并重新连接客户端。原生分析还需要相应的引擎和运行依赖;只克隆 REA 仓库,也不等于这些依赖都已就绪。具体要求应查项目安装指南。

8.2深入原生分析时,保持会话很有用

本机第一次 Ghidra 概览查询用了约十四分钟。同一会话中的后续字符串和引用查询快得多。这个数字仅描述我们的环境;它说明了为什么要区分导入/自动分析成本与一次热查询成本,也说明连续调查不宜无意间反复启动一次性进程。12

8.3大结果要保留全文、按需阅读

函数档案可能包含大量图结构。我们的某次请求超过 MCP 响应预算,工具报告分析已经完成,并给出 retained Evidence 的后续读取方式。此时应按服务返回的指引分页或导出结果;后续只需要代码时,也可以改用较窄的伪代码查询。返回太大并不代表分析内容不存在。13

同样,“分析在本机执行”只描述分析进程的位置。Agent 若连接远端模型,工具结果仍可能进入模型上下文;数据流需要连同所用客户端和模型部署方式一起判断。

9怎样判断 REA 对自己的项目有没有价值?

我会从一个可以验收的局部问题开始:一个文件块怎样解码、一段坐标怎样转换、一次事件怎样到达系统 API。先固定目标与样本,再要求交付可定位的证据、独立实现和测试结果。

如果只有一份完整源码,普通代码搜索和测试通常就能推进理解;当关键行为藏在发布制品、混合技术栈或运行时边界里,REA 的适配层与证据组织才更容易发挥作用。尤其适合让 Agent 反复执行“提出问题 → 查证 → 修正解释”的调查循环。

衡量成果时,可以一直追问四件事:输入从哪里来,输出交给谁,结论由什么支持,怎样验证它。REA 让这些问题更容易落到工具调用和可保存的记录上;一个局部规则被解释清楚并经受检查,就是一次可以继续积累的成果。

注释

  1. morluto/REA,项目 README与 MIT License。支撑项目定位、MCP/CLI 入口与许可证说明,所引源码固定到本文核对的提交。 ↩

  2. REA,JavaScript artifact reconstruction与 CLI and Evidence。说明静态 JavaScript/ASAR 路径、托管程序集分析及随目标变化的依赖;不表示所有 provider 在所有平台都支持相同能力。 ↩

  3. REA,架构图源码。支撑 CLI/MCP 共享应用层、provider 分工与 Ghidra bridge;正文图为简化结构示意。 ↩

  4. REA,WorkflowEvidence.ts与 Native binary investigation。前者保留组合操作的来源限制,后者说明原生查询、函数档案与 provider 边界。 ↩

  5. REA,Evidence 数据模型与 MCP runtime contracts。支撑字段、分类及结果表示说明;字段可追溯不等于推断已经得到运行验证。 ↩

  6. REA,evidence.ts 中的 semanticProjection、computeEvidenceId 与 parseEvidence。源码对语义投影求摘要并校验记录标识;正文对“记录一致性”与“事实正确性”的区分是据此作出的解释。 ↩

  7. REA,AnalysisProviderRegistry.ts。说明深度 provider 的选择与绑定;具体选择和失败语义还见对应提交的 CLI 文档。 ↩

  8. REA,Save and reuse analysis snapshots。说明精确查询缓存、目标与配置匹配,以及 snapshot 不等于 provider 数据库的限制。 ↩

  9. REA,DX-Ball sound-pan 案例,2026-10-22 核对;另见固定提交的证据说明。支撑缺失参数、调用者含义、常量与局部公式;记录使用 REA 4.1.0,不应混写为本机 6.7.0 的实测。 ↩

  10. N0zoM1z0/dx-ball,编译器重放方法;REA,该函数验证范围。来源记录了 3,205 组差分与完整 63 字节匹配,条件包括指定工具链、常量及经过检查的重定位;本文未重新执行这些验证。 ↩

  11. GPT-6,2026-10-21 Enshrouded 调查摘要与渲染消费者明细。本机调查的样本、函数地址与 Evidence ID 支撑正文局部算法、打包及纠错案例,不代表完整引擎重建。 ↩

  12. GPT-6,2026-10-21 本机 REA 调查记录。首次概览约 859 秒,后续热会话查询明显更快;这是当次环境观察,不是 REA 性能保证。目标与工具版本见调查摘要。 ↩

  13. REA,MCP runtime contracts。说明结构化结果、保留记录和分段阅读机制;本机超过响应预算后的恢复是一次具体使用经验,需以实际服务返回的 continuation 指引为准。 ↩

CONTINUE EXPLORING

沿着这篇文章继续

在地图中查看

欢迎补充、提问,或分享不同的看法。使用 GitHub 账号登录后即可评论。

On this page