夜雨聆风学习资料网

ARTICLE · 1167606

REA 实战:让 AI 编程助手替你做逆向工程

REA 实战:让 AI 编程助手替你做逆向工程

为什么 Windows 计算器算「200 + 10%」会得到 220?一个小恐龙游戏为什么越跑越快?一个打包好的 Electron 应用,到底把 CSV 导出到哪儿去了?过去这些问题只能靠人肉啃汇编,现在,REA 把逆向工程工具交给你的编程助手,你只需要用大白话提问。本文带你从零装好 REA,走通原生二进制、JavaScript/Electron、浏览器三条分析路线,并复盘四个真实案例。

先说一个反直觉的现象

打开 Windows 自带的计算器,输入 200 + 10%。

回车。

结果是 220。

再试试 200 × 10%,结果是 20。

明明按的是同一个 % 按钮,为什么一次加上了 20,一次折成了 0.1?

因为在这个按钮背后,藏着一个分支判断:在 + 和 - 之后,% 取的是第一个数的百分比;在 × 和 ÷ 之后,% 只是把当前数除以 100。

这不是什么冷知识,而是一个典型的逆向工程问题——你手里只有一个编译好的、没有源码的 calc.exe,但你想知道它到底怎么算的。

放在以前,这意味着你得打开 IDA 或 Ghidra,读十六进制的指令,追踪函数调用,一个一个还原常量。天赋异禀的人要花一个下午,普通人可能要花好几天。

而现在,有人给这件事找到了一个新解法:把逆向工程工具装进你的 AI 编程助手。

这个工具,就是 REA。

读汇编、追踪函数调用、还原计算规则——传统逆向工程的三步人工调查

逆向工程,到底难在哪

先给不太熟悉这个词的读者补一课。

逆向工程(Reverse Engineering),简而言之就是通过检查程序本身,弄清软件是如何工作的。你的目标不是破解,而是理解——理解一个功能,从而能解释它、修改它,或者重新实现它。

而它难,难在三个地方。

第一,你没源码。 摆在面前的只有一堆编译后的产物:原生程序是 x64 汇编指令,Electron 应用是一坨 .asar 打包文件,网页是压缩混淆过的 JavaScript。

第二,信息是碎的。 一个「导出 CSV」的功能,可能横跨页面按钮、preload 脚本、IPC 通道名、主进程处理函数四个文件。你得自己把它们串起来。

第三,门槛不在概念,在工具。 IDA、Ghidra、Hopper 这些工具极其强大,但学习曲线陡峭,界面反人类,新手光是把文件拖进去就要折腾半天。

所以,真正的问题不是「逆向工程难」,而是「逆向工程的工具链,离开发者太远了」。

REA 想干的事,就是把这条距离缩到一句话。

REA 是什么:给助手装上「读程序」的眼睛

REA 的自我定位只有一句话:为编程助手提供分析工具,让它检查程序并解释程序的行为。

拆开看,这里有两个角色。

一个是你的编程助手。 不是浏览器里的对话机器人,而是能真正在你电脑上干活的 AI Agent——它能读文件、跑命令、在动手前征求你确认。Claude Code、Codex、Cursor、Gemini CLI、Windsurf 都属于这类。

另一个是 REA。 它通过 MCP(Model Context Protocol)连接到助手,为助手补上「逆向工程」这一块能力:读取汇编、反编译伪代码、追踪调用关系、匹配 IPC 通道、捕获网络请求。

于是整个工作流就变成了这样:

你给助手一个本地目标路径和一个具体问题,REA 负责把程序拆开、把证据摆到桌面上,助手负责用大白话把结果解释清楚,甚至直接写出一份能跑的实现来验证。

举个官网的原话,你的编程助手可以直接被这样吩咐:

用 REA 检查 Windows 计算器。为什么 200 + 10% 会得到 220?

它返回给你的不是一堆十六进制,而是一句人话:

在 + 之后,% 按钮计算的是第一个数的百分比。10% of 200 = 20 → 200 + 20 = 220。

更关键的一点是:REA 的每一项结论都附带源码位置。 它不会给你一个凭空捏造的答案,而是告诉你「这条规则来自哪个函数、哪条分支、哪个常量」。这一点,决定了它是工具而不是玄学。

编程助手通过 MCP 调用 REA 的分析能力,REA 在本地检查目标,返回带源码位置的证据

安装:让助手学会逆向工程

REA 的安装不需要你懂逆向,甚至不需要你打开终端——你可以直接把安装任务丢给你的编程助手。

第一步:确认 Node.js 版本

REA 需要 Node.js 22.19+、24.11+ 或 26+。npm 会随 Node.js 一起安装。

打开终端,检查版本:

node -v npm -v

如果版本太旧,或者提示「无法识别」,先装 Node.js 24 LTS。

Windows(PowerShell):

winget install OpenJS.NodeJS.LTS

macOS(Homebrew):

brew install node

macOS / Linux(fnm):

curl -fsSL https://fnm.vercel.app/install | bash fnm install 24 fnm default 24

装完记得关掉终端重新打开,再跑一次 node -v 确认。

第二步:一句话完成 setup

如果你已经有编程助手,直接把下面这句话复制给它:

使用 npx rea-agents@latest setup 安装 REA,并连接到这个编程助手。先展示安装计划,等我确认后再执行,然后验证安装结果。

助手会运行 REA 的 setup,先给你看一份安装计划,等你点头之后才动手。

当然,你也可以自己在终端里跑:

npx rea-agents@latest setup

setup 会做三件事:

  • 注册 REA 的 MCP 连接;
  • 安装配套的调查技能(investigation skills);
  • 备份你已有的配置
    ,确认之后才应用更改。

REA 官方支持的客户端清单相当长:Claude Code、Claude Desktop、Codex、Cursor、Gemini CLI、Windsurf、Devin、OpenCode、Antigravity、GitHub Copilot CLI、Command Code、Grok Build、OMP、VS Code。基本上,只要你的助手支持本地 MCP 服务器,就能接上。

第三步:重启,然后提问

配置完成后必须重启客户端。注意,桌面应用(Cursor、Windsurf、VS Code)要完全退出再打开,只关窗口不算数;终端类助手(Claude Code、Codex)退出当前会话再启动即可。

然后给它一个目标路径和一个具体问题。以 Electron 应用为例:

检查 /absolute/path/to/app,找出它如何导出数据。展示涉及的入口点、函数调用和依赖,并给出分析结果对应的源码位置。

把 /absolute/path/to/app 换成你自己的项目目录就行了——Windows 用户直接右键文件夹「复制文件地址」即可。

检查 Node 版本 → npx setup → 确认计划 → 重启助手 → 给路径提问 → 拿到带源码位置的答案

三条分析路线,对号入座

REA 并不是一把万能锤子。根据你手上的目标类型,它提供三条不同的路线。

路线一:JavaScript / Electron 应用。 静态分析应用目录或 .asar 文件,还原模块、导入关系、IPC 通道,无需启动应用。

路线二:浏览器与运行时活动。 连接到一个正在运行的浏览器,捕获真实的点击、请求和脚本,比较不同运行的结果。

路线三:原生二进制。 检查可执行文件和动态库里的函数、字符串、引用和调用关系,这一条需要配合 Ghidra、Hopper 或 IDA。

JS/Electron 静态分析、浏览器运行时观察、原生二进制分析,三条路线各有适用场景

接下来我用四个真实案例,把这几条路线走一遍。

实战一:计算器为什么算成 220

这是 REA 官网的招牌案例,也是最能说明「人肉 vs 助手」差距的例子。

先看人肉路线要面对什么。下面是计算器里 % 处理函数的一段原始 x64 指令节选:

0x180124945: MOV EAX, dword ptr [R13 + 0x18] 0x180124949: CMP EAX, 0x5c 0x18012494c: JZ 0x180124aba 0x180124952: CMP EAX, 0x5b 0x180124955: JZ 0x180124aba 0x18012495b: MOV EDX, 0x64

要读懂它,你得回答三个问题:

「0x5b?0x5c?两个跳转去了同一个位置,它们对应哪些运算符?」

翻命令 ID 表才知道:0x5b 是除号 ÷,0x5c 是乘号 ×。

「100 很明确,但函数调用只有地址。哪个负责除法?传进去的是哪个值?」

得去检查辅助函数,追踪数值的流向。

「这个分支乘上了另一个输入。所以在 + 之后,10% 表示 200 的 10%。」

最后才拼出规则:200 × 10 / 100 = 20。

全程靠脑子。而用 REA,你只需要问一句:

用 REA 检查 Windows 计算器的 % 按钮。还原 + 和 × 后的规则,再做一个同时采用这两条规则的小计算器。

REA 返回给助手的,是这段处理函数的可读摘要:

if (operation == multiply || operation == divide) {   percent = current / 100; } else {   percent = current * previous / 100; }

一眼就懂。两条规则清清楚楚:

  • 在 + 之后:
     取第一个数字的 10%。10% of 200 = 20 → 200 + 20 = 220
  • 在 × 之后:
     把 10% 变成 0.1。200 × 0.1 = 20

而且这个结论是可验证的——它和微软公开的 Calculator 源码里 scifunc.cpp 的实现完全对得上。

这就是 REA 最有价值的地方:它不只是给你一个答案,它给你证据链。

实战二:小恐龙为什么会越来越快

第二个案例更贴近我们平时会遇到的需求:我想搞懂一个游戏规则,然后自己做个小版本。

目标很明确:重建一个速度可调的小恐龙(Chrome 离线小游戏)。

但问题在于,要让你的复刻版「手感对」,你必须知道原版的确切数值:起始速度是多少?每次加速加多少?什么时候停止加速?

这些数值藏在运行中的游戏脚本里。REA 的做法是:读取正在运行的页面脚本,把它交给助手。助手直接在源码里找到了答案:

if (this.currentSpeed < this.config.MAX_SPEED) {   this.currentSpeed += this.config.ACCELERATION; }

配置常量:

ACCELERATION: 0.001, MAX_SPEED: 13, SPEED: 6

翻译成人话就是:

  • 起始速度 6
    ;
  • 只要当前速度低于 13,每次「没有发生碰撞的更新」就增加 0.001;
  • 到达 13 之后就不再加速。

这个规律还经过了实机验证:在受控的浏览器检查里调用原版更新函数,禁用障碍物和自动调度,保留一位小数——更新 4,000 次后速度是 10.0,更新 10,000 次后是 13.0,和公式完全吻合。

拿到规则,助手就能直接写一个带速度滑块的复刻版,你去玩就够了。

这就是「理解一个功能」的价值:你不是在抄一个游戏,你是在掌握它的运行规律。

实战三:Electron 应用把 CSV 导出到哪儿去了

这一节是给本系列的老读者准备的——REA 对 Electron 应用的支持,几乎是为你量身定做的。

假设你手上有一个别人写的 Electron 应用,界面上有个「Export notes」按钮,点了之后会导出一个 CSV。你想搞清楚:这个 CSV 到底是怎么生成的?存到了哪个目录?

问题是,这个行为散落在好几个文件里:

  • 渲染层 → preload:renderer.js
     调用 notes.exportCsv(),而这个名字是由 preload.js 通过 contextBridge 暴露出来的;
  • 进程之间:
     preload 调用了一个 IPC 通道 notes:export;
  • 主进程:main.js
     里 ipcMain.handle("notes:export", ...) 处理这个通道,再调用 CSV 写入函数。

三个文件,一处链路。人肉翻代码,你得一个个 find。

而 REA 会把字面量 IPC 调用和它的处理函数直接配对,并识别出公开的 API。你只需要问助手:

用 REA 找出这个应用导出笔记时发生了什么。CSV 文件在哪里创建?

它会给你一份归纳好的 IPC 摘要:

{   "literal_channels": 1,   "renderer_transmissions": 1,   "main_handlers": 1,   "paired_renderer_transmissions": 1,   "ambiguous_renderer_transmissions": 0 }

然后顺着源码位置读下去,答案一目了然。渲染层只是调了个名字:

document.querySelector("#export").addEventListener("click", async () => {   const destination = await window.notes.exportCsv();   document.querySelector("#status").textContent = `Saved to ${destination}`; });

preload 把它暴露出去,顺便写死了通道名:

contextBridge.exposeInMainWorld("notes", {   exportCsv: () => ipcRenderer.invoke("notes:export"), });

真正的实现在主进程:

ipcMain.handle("notes:export", () => {   const destination = path.join(app.getPath("downloads"), "notes.csv");   writeFileSync(destination, toCsv(notes), "utf8");   return destination; });

读到处理函数,最初的问题就有答案了:csv.js 负责把笔记格式化成 CSV,主进程把 notes.csv 写进用户的下载文件夹。

如果你不想开助手,用命令行也一样行得通:

npx -y rea-agents@latest analyze-javascript-application \   /absolute/path/to/notes-example --json

结果里的 normalized_result.summary.ipc 包含通道统计,normalized_result.graph 里带源码位置。REA 无法解析的关系(比如动态拼接的通道名)会明确标注出来——它宁可告诉你「这里没搞定」,也不给你编一个。

renderer.js → preload.js → IPC 通道 notes:export → main.js 处理函数 → 写入 downloads/notes.csv

顺带说一句:真实的 Electron 应用,你通常是在 resources 目录下找到 app.asar 的。

  • Windows:C:\Users\<you>\AppData\Local\Programs\<App>\resources\app.asar
  • macOS:/Applications/<App>.app/Contents/Resources/app.asar
    (右键应用,选「显示包内容」)
  • Linux:
     通常位于 /opt/<App>/resources/app.asar

三大平台 Electron 应用 app.asar 文件的常见位置

实战四:还原游戏里的声音定位公式

最后一个案例,是三条路线里最硬核的——原生二进制。它需要你先配好 Ghidra、Hopper 或 IDA 中的一个。

问题本身很有意思:在经典游戏 DX-Ball 里,球击中砖块会发出声音,声音的左右声道位置跟砖块在屏幕上的横向位置有关。这个「平移值(pan)」到底是怎么算出来的?

REA 给出的三条证据:

证据一,指令。 启动函数 0x00406400 从栈上读一个整数,转成浮点:

MOV EAX, dword ptr [EBP + 0x8] MOV dword ptr [EBP + -0xc], EAX FILD dword ptr [EBP + -0xc]

证据二,调用方。 往上追,找到砖块碰撞处理函数 0x411f5b,它把砖块横坐标乘以 30,再加上 0x14(也就是 20),得到屏幕位置:

ADD EAX, 0x14 PUSH EAX CALL 0x00406400

证据三,常量。 读取被引用的字节,按小端序解释成双精度浮点数:

0x420068 000000000000f93f → 1.5625 0x420070 0000000000407f40 → 500.0 0x4210a0 000000000000f03f → 1.0

三块拼起来,公式就出来了:

pan = (x × 1.5625 − 500.0) × scale

当比例 scale 为 1.0 时,屏幕位置 0、320、640 会分别映射到 −500、0、500——正好把屏幕中心对齐到立体声场的中心。

更厉害的是验证环节:助手根据这个公式写出的 C 代码,单独测试了 3,205 个输入,并且成功复现了原函数全部 63 个编译字节。

这已经不是「猜」了,这是可验证的还原。

如果你也配了 Ghidra,可以直接从终端查询某个函数:

npx -y rea-agents@latest function /absolute/path/to/program main \   --provider ghidra --json

把 main 换成你要检查的函数名或地址就行。

REA vs 传统逆向工具,怎么选

看到这里你可能会问:那我干脆学 IDA 不就行了?

当然可以,但两者解决的其实是不同层次的问题。

维度
传统逆向工具(IDA / Ghidra 单独使用)
REA + 编程助手
使用者门槛
需要懂汇编、反编译、调用约定
会用自然语言描述问题即可
目标范围
主要是原生二进制
原生二进制 + JS/Electron + 浏览器
交互方式
图形界面 / 脚本,手动导航
一句话提问,助手自动归纳
输出结果
汇编、伪代码、引用关系
人话解释 + 源码位置 + 可运行实现
验证
靠自己判断
助手可写实现并对照原版测试
定位
底层分析引擎
引擎之上的一层「翻译与编排」

关键点在于:REA 并不替代 Ghidra / Hopper / IDA,它是站在它们之上的。 深度原生分析依然需要这些后端工具,REA 负责把它们的输出交给 AI 助手去解释和组织。

所以正确的选择是:

  • 只是想搞懂一个 JS/Electron 应用或网页的行为
     → 直接上 REA,不需要任何原生分析工具;
  • 要分析原生程序,但不想人肉啃汇编
     → REA + Ghidra/Hopper/IDA 组合;
  • 纯粹做深度二进制漏洞研究
     → 传统工具依然是你的主武器,REA 可以帮你加速理解过程。

避坑指南:最容易踩的五个坑

坑一:Node 版本不够。 REA 要求 22.19+、24.11+ 或 26+。如果你的发行版自带的 nodejs 包太旧,别犹豫,用 fnm 装一个新的。

坑二:PowerShell 禁止运行脚本。 运行 npx 时如果报错 「running scripts is disabled on this system」,执行一次下面这条命令再重试:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

坑三:装完没重启客户端。 这大概是最常见的问题——助手看不到 REA 工具,十有八九是因为没重启。桌面应用要完全退出(Windows 上别忘了托盘图标),终端助手要退出会话重开。

坑四:只装了技能,没连 MCP。 从 skills.sh 单独安装技能是不够的,技能只是告诉助手「如何开展调查」,MCP 连接才是真正给助手装上工具。两件事都得做。

坑五:担心隐私。 REA 在你的机器上分析目标,不会把你的程序上传到服务器。需要注意的是,助手会收到分析结果,所以这部分仍然受你所选模型服务商的隐私政策约束。心里有数就好。

排障神器:doctor。 一旦出问题,先跑诊断:

# 检查某个客户端的连接 npx -y rea-agents@latest doctor --client codex --json  # 检查原生分析后端 npx -y rea-agents@latest doctor --provider ghidra --json

报告会列出每一项失败的检查,并给出下一步建议。另外注意:REA 更新很频繁,遇到怪问题先 rea update(或重跑 npx rea-agents@latest setup)再试一次,很可能已经修好了。

写在最后

回到开头那个问题——为什么计算器算 200 + 10% 得到 220?

现在你知道答案了。但我更想让你记住的,是这个答案是怎么被找到的。

过去,逆向工程是一门需要专门修炼的手艺,工具链厚重、门槛高耸,把绝大多数开发者挡在门外。而 REA 这类工具的出现,正在把「理解一个程序」这件事,从一项专业技能,变成一个你随时可以发起的提问。

它递给你的不是一把破解的钥匙,而是一副理解的眼睛。

当然,能力越大,边界越重要。逆向工程本身完全合法——读自己的程序、分析自己买来的软件、研究恶意样本、做安全审计、学习优秀作品的实现思路,都是正当需求。但理解可以,越界不行:绕过授权、窃取数据、复制他人作品,那就是另一回事了。工具中立,用的人得有数。

至于我,更期待的是另一种用法:当你遇到一个看不懂的老项目、一个行为诡异的第三方库、一段没人敢动的祖传代码时——你终于可以指着它,问一句「你到底在干什么」,然后真的得到答案。

这大概就是 AI 时代,给开发者最实在的一份礼物。


延伸阅读:

  • REA 官方文档:https://rea.tools/zh-CN/
  • 安装与配置指南:https://rea.tools/zh-CN/get-started/
  • GitHub 仓库:https://github.com/morluto/rea
  • 社区 Discord:https://discord.gg/GkcryMnJDM

本文基于 REA 官网 4.1.0 版本文档整理,案例数据均来自官方公开示例。

相关学习资料