今天刷掘金榜单,连续看到几篇 REA。名字也很直接:Reverse Engineer Anything,逆向一切。
看完介绍,我想试一个小问题:给它一个 Electron 项目的源码目录,它能不能顺着「添加草稿」这个按钮,找到最后处理数据的代码?
结果有点意思。它配上了两条 IPC 通道,也标出了代码位置;但页面里的调用,还有一部分停在 unknown。
先交代这次实际做了什么:准备了一个自写的 5 文件样本,用 REA 6.5.0 做静态分析。没有启动 Electron,也没有让模型复刻界面。这篇记录的是工具输出和源码复核。
REA 是给 AI Agent 使用的逆向分析工具,也提供 CLI。它可以把代码结构和分析证据交给模型,继续追踪某个功能。这里先单独跑 CLI,看看模型拿到的材料到底是什么。
样本很小:main.js 管主进程,preload.js 暴露桥接方法,renderer.js 处理页面操作,再加一个 HTML 和 package.json。功能只有添加、统计和清空草稿。
本机用 Node 24.19.0,REA 固定为 6.5.0。首次安装停在 Frida 的依赖安装脚本,后来使用已下载的缓存、跳过安装脚本,完成了静态分析。下面是成功执行的命令,样本路径换成了占位符:
bash
npm --cache /private/tmp/rea-demo-npm-cache --offline --ignore-scripts \
exec --yes --package rea-agents@6.5.0 -- \
rea analyze-javascript-application /absolute/path/to/sample-app --json \
> application-evidence.json
这里的 --offline 依赖前一次已经下载的缓存,首次安装不能直接照抄。常规运行方式见官方 CLI 文档。跳过安装脚本只在本文的 JavaScript 分析中验证过,原生分析能力没有测试。
输出中,3 个 JavaScript 文件均解析成功,找到了 1 个 BrowserWindow、1 个 preload 入口和 1 个桥接 API。更具体的结果是下面这组代码。
preload.js 把添加方法交给页面:
js
contextBridge.exposeInMainWorld('drafts', {
add: (text) => ipcRenderer.invoke('draft:add', text),
list: () => ipcRenderer.invoke('draft:list'),
onCleared: (callback) =>
ipcRenderer.on('draft:cleared', () => callback())
});
main.js 接收添加请求:
js
let drafts = [];
ipcMain.handle('draft:add', (_event, text) => {
const draft = { id: drafts.length + 1, text: String(text).trim() };
drafts.push(draft);
return draft;
});
REA 将 preload 中的 invoke 和 main 中的 handle 配了起来。下面是原始输出中这条关系的部分字段,省略了 ID 等内容:
json
{
"channel": "draft:add",
"pairing_basis": "unique-exact-literal-channel",
"handler_path": "main.js",
"handler_operation": "handle"
}
也就是根据唯一、相同的通道名,定位到了另一端的处理函数。draft:list 也完成了配对。
对接手陌生项目的人来说,这种结果有用:至少知道接下来该打开哪个文件,而不是只拿到一段「这是一个草稿管理程序」的概括。不过,这条静态关系还不能证明运行时真的调用成功。
接着看页面代码:
js
await window.drafts.add(editor.value);
const drafts = await window.drafts.list();
人对照刚才的 preload,很容易理解这里想调用什么。但在这次输出的语义图里,这两个调用仍然有未解析记录。工具找到了桥接 API,不代表页面到主进程的每一段关系都已经自动串好。
清空功能也一样。源码里有 mainWindow.webContents.send('draft:cleared'),preload 里有对应监听;这次结构图识别了监听,却没有生成主进程一侧对应的发送边。
所以,报告里没找到某条关系,不能直接写成代码里没有这段逻辑。
这也是把报告交给模型时最值得保留的信息。只给模型一张整理得很漂亮的调用图,把 unknown 和限制说明删掉,它后面就更难区分哪些是工具找到的,哪些需要回到源码继续查。
还有一个小细节:草稿存到哪里了?
回看上面的 main.js,处理函数只是往数组里放数据。检查这个样本的源码,没有实现磁盘持久化。因此「找到了添加草稿的处理代码」可以说,「已经验证草稿保存成功,重启也不会丢」就说过头了。后一句还需要运行应用、重启和核对结果。
如果下一步接到 AI 编程助手里,我会把任务缩小到这几件事:
沿着添加草稿的功能继续查。每一步给出文件和行号,区分工具已建立的关系与需要读源码补充的关系。遇到 unknown,说明缺什么证据。最后检查数据存在哪里,并列出还需要怎样的运行验证。
下一步可以固定这份证据和问题,比较不同模型会不会主动追查 unknown。编程助手如果已通过 moyi API 接入支持的模型,就能沿用模型入口,REA 的工具连接仍需单独配置。这次没有做模型联调,因此还不能评价哪种组合效果更好。
跑完这个小样本,我更愿意把 REA 用在「帮我找到该读的代码」上。找到位置后,继续读、继续验证,比直接让 AI 给整个软件下结论踏实得多。
你们接手陌生项目时,会先让 AI 通读整个仓库,还是先挑一个具体功能,把调用过程追到底?