REA 逆向实战指南:AI Agent 如何靠 3205 个测试用例重建 DX-Ball 的 63 字节函数
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
63 字节的函数,凭什么要接受 3205 场考试?这个问题的背后,是 REA——一款为 AI Agent 打造的逆向分析工具——在 1996 年 Windows 游戏 DX-Ball 上跑通的一次真实案例:没有一行原始源码,AI Agent 靠证据反推,写出一个与原版机器码逐字节吻合的 6 行 C 函数。
实验对象与工具链:158,208 字节可执行文件里的 63 字节函数
📋本次案例的五组数据:
| 项目 | 内容 |
|---|---|
| 分析目标 | DXBALL.EXE(DX-Ball 1.07,1996 年经典打砖块游戏),158,208 字节 Windows i386 可执行文件 |
| 工具版本 | REA 4.1.0 + Ghidra 12.1.4 Provider |
| 聚焦函数 | 0x406400起、63 字节的"声音平衡"函数 |
| 验证方式 | 3,205 个原始 x86 差分测试用例 + 锁定版 VC4.0 编译器回放字节比对 |
| 项目进度 | 55 个已维护 C 函数、45,380 次与原始代码对比、33 个通过字节匹配 |
游戏的源码早已失传,重建项目要的不是"能跑起来的产物",而是可长期维护的 C 代码:每个函数都要有二进制层面的可核对依据,"和原版一样"由测试给出证明,而不是口头声明。
REA 支持 Ghidra、Hopper、IDA 等多个 Provider。上图是 Agent 深入分析目标时的典型画面:左边是指令级反汇编,右边是函数、段与调用约定信息,整个过程会被持续记录。
三条线索锁定一个丢失的入参:从反编译器盲区到 6 行函数
Agent 对0x406400做函数分析时,反编译器给出的是一段无参数伪代码,中间还夹着一个来路不明的__ftol()调用。一个不接收参数的函数却在做强转长整型的浮点运算——这正是反编译器的盲区,也是后续取证工作的起点。Agent 分三步补齐了盲区:
- 从指令视图找回输入。指令级视图里躺着
MOV EAX,[EBP+0x8]+FILD,说明函数实际带一个整型入参(记作x),伪代码把它弄丢了。 - 向调用方确认输入语义。
0x411f40(砖块命中函数)在发起调用前,先把砖块的格子坐标乘 30、再加 20——由此反推,x就是砖块的屏幕横坐标,即20 + 30 × tile_x。 - 读取内存地址背后的数值。用
read_bytes读出三处数据地址并按双精度浮点解码:0x420068→1.5625、0x420070→500.0、0x4210a0→1.0,后者正是存盘比例系数dxball_pan_scale。
证据到位后,Agent 把它翻译成 6 行可维护的函数:
DxBallInt dxball_screen_pan(DxBallInt x) { double pan; pan = (double)x; pan = pan * 1.5625; pan = pan - 500.0; pan = pan * dxball_pan_scale; return (DxBallInt)pan; }数字本身也站得住脚:比例取 1 时,画面左缘对应 -500、中心对应 0、右缘对应 +500,恰好是标准立体声声像的取值范围。
两层"一模一样":3205 次逐条对账与 63 字节回放
写完代码只是起点,验证才把猜测与证明分开。这个案例走了两条互相独立的验证路径。
差分测试怎么设计:541 × 5 组合
行为层最直观:给横坐标和比例系数,比对返回值。它的覆盖面接近全量遍历——横坐标取整数 0 到 640,覆盖整个屏幕宽度;比例系数取 0、0.5、1、20、−1 五档,极端值也在其中。两者交叉得到 541 × 5 = 2,705 组,再加上边界与中间态用例,合计3,205个。每一个输入都把 C 实现的返回值与原始 x86 函数的返回值直接对比,任何一处对不上,测试立刻失败。
字节层怎么回放:锁定版 VC4.0 编译
字节层回答的是另一个问题:同一份 C 函数用当年同款编译器编译,产出的机器码与原始函数是否一致?答案是一致的,63 字节全部吻合。
| 验证分支 | 做法 | 结果 |
|---|---|---|
| 🧪 行为差分 | 直接执行原始 x86 函数,与 C 实现逐条比对返回值 | 3,205 个用例全部通过 |
| 🔁 编译器回放 | 锁定版 VC4.0 工具链编译 C 函数,逐字节比对可执行文件 | 63 字节完全匹配 |
⚖️ 字节匹配是在应用了审阅过的重定位、并核对所引用的常量之后才成立的,这同时说明分析阶段用到的常量地址都有可回溯的出处。
结论的适用边界:绑定 commit a55dca27 与单一函数
调查的结论只在证据范围内有效。本案例的全部数字,都绑定在重建项目固定的分析检查点 commita55dca27(2026-10-07)上,且只覆盖0x406400这一个函数。
⚠️ "3205 个用例通过 + 63 字节匹配"不等于整款游戏已复原。游戏级集成是独立的任务线,引用或复用本案例时,请连同检查点与函数范围一起注明。
两步复现路径:装好 REA,再打一个函数快照
先装工具:克隆仓库(https://gitcode.com/GitHub_Trending/rea2/rea),按 docs/installation.md 完成安装,并连接一个 Provider(Ghidra、Hopper 或 IDA 均可)。
再对目标函数存一份快照,DX-Ball 项目中实际执行的就是这一条命令:
rea function original/DXBALL.EXE 0x00406400 --snapshot .analysis/rea/dxball.snapshot.json --json📸 命令产出的是 JSON 快照,Agent 随后基于其中的指令视图、调用方信息与常量读取结果继续补齐证据,再用普通代码工具写出 C 实现并完成测试。
本案例涉及的全部资料都放在仓库里:
- docs/installation.md:安装与 Provider 连接
- docs/native-investigation.md:原生二进制深度调查指南(指令/调用/类型原语、值追踪)
- docs/ghidra-dos.md:Ghidra Provider 使用文档
- README "DX-Ball: game reconstruction" 一节:官方案例说明
- website/evidence/dx-ball-sound-pan.md:本案例完整证据清单,含逐条指令列表与 Evidence ID
- website/public/showcase/dx-ball/index.html:可交互案例页,"Checking the recovered function" 一节即验证细节
这个案例留下的,是三条可以直接挪用的经验:
- 用证明代替猜测:3,205 次对账代替主观判断,63 字节的回放代替"编译器应当给出相同代码"的假设;
- 每行重建代码都有可回溯的出处:地址、Evidence ID、固定检查点 commit
a55dca27,全部落在证据清单里; - 同一流程可复制到任意二进制:REA 检查函数、恢复状态与依赖、写 C、与原始 x86 逐条对账,一个字节一个字节地推进。
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考