REA 逆向 DX-Ball:63 字节声像函数,3205 个差分测试用例全通过与原始 x86 逐字节一致
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
REA(Reverse Engineer Anything)是一个让 AI Agent 直接操作二进制的逆向分析工具:查函数、看指令视图、读内存常量,把"看起来像这么写的"变成有证据支撑的结论。下文用 REA 官方的 DX-Ball 重建案例,完整演示这条证据链怎么搭起来——目标不是"把 1996 年的游戏跑起来",而是拿到一个63 字节小函数的可维护 C 实现,并用两条独立路径证明它与原始 x86 逐字节等价。
屏幕横坐标怎么变成左右声像:问题比函数更小
DX-Ball 被击中砖块时会播放带左右声像(pan)的音效,重建这段行为要先回答一个很具体的问题:屏幕上的横坐标,是被什么公式换算成了左/右平衡值?
分析对象是 158,208 字节的 Windows i386 可执行文件DXBALL.EXE(DX-Ball 1.07),环境为 REA 4.1.0 + Ghidra 12.1.4。目标函数0x406400–0x40643e,全部指令只有 63 字节。
第一次对0x406400执行analyze_function后,反编译视图给出的伪代码却让人卡住:
longlong FUN_00406400(void) { longlong lVar1; lVar1 = __ftol(); return lVar1; }参数列表是空的,转换调用__ftol()的来源也不明——这是反编译器"没看全"的典型信号。但 REA 返回的函数档案同时包含指令视图和调用方信息,顺着这条线索,Agent 用三个查询把缺口全部补上。
从指令视图找回丢失的入参
指令视图中MOV EAX, [EBP+0x8]后面紧跟FILD:函数实际有一个整型入参,只是伪代码把它丢了。重建源码把它命名为x。
从调用方确定输入含义
档案里记录了调用方:砖块命中函数0x411f40在CALL之前做了"格子坐标 ×30 后 +20"的计算再压栈。据此确定x就是砖块的屏幕横坐标:20 + 30 × tile_x。
从内存字节读出三个常量
指令流是三步浮点运算:FMUL [0x420068]、FSUB [0x420070]、FMUL [0x4210a0],最后CALL 0x41678c(__ftol)转回整数。三个操作数都存在数据段里,用read_bytes读出并解码为双精度浮点:
| 数据地址 | 解码值 | 含义 |
|---|---|---|
0x420068 | 1.5625 | 位置放大系数 |
0x420070 | 500.0 | 屏幕中心偏移 |
0x4210a0 | 1.0 | 存盘比例系数dxball_pan_scale的初始值 |
证据齐了,翻译出来的 C 函数只有 6 行:
DxBallInt dxball_screen_pan(DxBallInt x) { double 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 字节编译回放
写完 C 只是起点,关键在验证。重建项目为这个函数设了两条互相独立的验证路径,回答两个不同的问题。
- 行为差分测试:直接执行原始 x86 函数,把返回值与 C 实现逐一比对。横坐标取整数 0–640(覆盖整个屏幕宽度),比例系数取 0、0.5、1、20、−1 五种(含极端值),边界与中间态组合后共3,205 个用例,全部通过——任何一个输入上两者返回不同,测试立刻失败。
- 编译器回放:用锁定版本的 VC4.0 工具链(DX-Ball 当年的编译器)编译 C 函数,逐字节对比可执行文件。应用审阅过的全部重定位并核对所引用常量后,63 个字节完全匹配——即这个 C 函数在同款编译器下产出与原函数一模一样的机器码。
这些结论绑定在重建项目固定的分析检查点(commit
a55dca27,2026 年 10 月 7 日)上,只针对这一个函数;游戏级的整体集成是独立的任务线。
重建进度:1 个函数的方法复制到 55 个函数
这不是单次演示,而是持续推进的工程。截至 2026 年 10 月的检查点:
- 55个已维护的 C 函数,覆盖棋盘与资源处理、砖块命中、动画、粒子与奖励生成
- 45,380次与原始代码的对比
- 33个函数已通过编译字节匹配
同一套方法正在复制到粒子更新、爆炸队列、奖励生成等部分。每个新函数的流程固定不变:REA 检查函数 → 恢复状态与依赖 → 写 C → 与原始 x86 对比,让每行新代码自带证据链。
复现步骤:在自己的二进制上搭起证据链
- 克隆仓库
https://gitcode.com/GitHub_Trending/rea2/rea,按 docs/installation.md 安装 REA 并连接一个 Provider(Ghidra、Hopper 或 IDA)。 - 对目标函数执行
function命令并落盘快照,DX-Ball 项目中实际运行的命令是:
scripts/rea function original/DXBALL.EXE 0x00406400 \ --snapshot .analysis/rea/dxball.snapshot.json --jsonAgent 会基于analyze_function返回的指令视图、调用方和常量读取结果补齐证据,再用普通代码工具写出并测试 C 实现。完整证据(逐条指令、Evidence ID、字节读取记录)都在 website/evidence/dx-ball-sound-pan.md;系统了解工具能力可从 docs/native-investigation.md 的原生二进制调查指南入手。
三条收尾对照:这套做法改变了什么
| 传统手工逆向 | REA 证据驱动 |
|---|---|
| 反编译缺参数、伪代码带不解释的转换调用 | 指令视图 + 调用方 +read_bytes三路交叉,缺口逐个补齐 |
| "我觉得这个函数是这样算的" | 3,205 个原始 x86 差分用例 + 63 字节编译回放 |
| 结论散落在笔记里,换个检查点无法复核 | 每条结论绑定 Evidence ID 与固定 commit |
| 分析结果与可交付代码是两件事 | Agent 的查询结果当场落成带测试的 C 函数 |
逆向不再等于对着汇编猜:反编译器没看全的地方,变成了继续深挖的具体线索;而"和原版一模一样"这句话,第一次有了 3,205 个用例和 63 个字节作为凭证。
【免费下载链接】reaReverse engineer anything with agents, from app behavior down to native binaries.项目地址: https://gitcode.com/GitHub_Trending/rea2/rea
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考