原生程序 / 交互案例 / 阅读约 20 分钟
DX-Ball:能听出砖块在哪一侧吗?
使用 REA 分析 DX-Ball 的立体声声像函数。追踪指令与常量,体验声音演示,并测试还原的计算规则。
本页内容
01. 拆解之前,先试一试
先按“左侧”,再按“播放短音”;在右侧重复一次。现在把缩放系数设为 −1:位置没动,声音却换了方向。设为 0 时声音居中。上方数值来自还原的算法,下方声音只是演示。
trunc((320 × 1.5625 − 500) × 1) = 0
戴上耳机更容易听出位置。只有按下播放按钮才会发声。
数值规则依据报告。声音是归一化的 Web Audio 演示,并非原版音频引擎。
一个将位置换算为声像的函数、一段可听的演示,以及将重建结果与原机器码对比的方案。
分析之前实验建议使用耳机。若要进行二进制分析,需要你自己的英文 DX-Ball 1.07 可执行文件和原生分析后端。报告提供了目标摘要和已记录证据。 配置 REA →
02. 从砖块撞击追踪到声音调用
从可见事件开始:屏幕一侧的砖块被击碎。从声音调用反向追踪,确定调用方传了什么值。看似坐标的数字,也可能是格子索引、偏移量或缩放后的位置。
复用上游报告中的地址前,先确认版本完全匹配。报告中的目标辅助函数从 0x406400 开始。如果可执行文件不同,应定位对应行为,不要默认相同地址仍适用。
用 REA 分析与报告匹配的 DX-Ball 1.07 可执行文件。从官方报告定位的声像辅助函数开始,分析调用它的砖块撞击逻辑。说明调用方如何构造参数。引用调用点指令和辅助函数的输入加载指令。不要默认反编译函数签名完整。03. 伪代码丢失参数时,查看指令
即使机器指令完整,反编译器仍可能生成很短且信息不足的函数体。结合查看栈加载、浮点运算、引用数据和整数转换。要求给出每个常量的原始字节,以及类型和字节序。
记录中的计算式为 trunc((x × 1.5625 − 500) × scale)。调用方提供横向位置。注意最后的转换:向零截断会影响负数结果,与向下取整不同。
- 输入从哪里进入函数?
- 哪些被引用的字节解码后对应各个浮点常量?
- scale 是参数、已保存的状态,还是固定字面量?
- 在测试输入范围内,转换会截断、舍入、饱和还是溢出?
04. 谨慎地让数字变成声音
先实现数值函数,检查左、中、右三个位置,再加入会产生小数的相邻位置。当 x = 319、scale = 1 时,原始值是 −1.5625,整数结果为 −1。如果向下取整,就会错误地得到 −2。
声音按钮把 pan / 500 映射到 Web Audio 立体声声像器,并将试听值限制在 −1…1。这能直观呈现方向,但不会复现 DirectSound 的音量曲线或原游戏音效。显示的整数值不会被限幅。
独立实现记录中的位置到声像换算。分别测试 x = 0、1、319、320、321、640,以及 scale = 0、0.5、1、20、−1。保留向零转换。制作由用户触发的短音试听,单独注明归一化处理,不能把试听的限幅当成还原的数值行为。05. 理解通过 3,205 项验证能证明什么
项目报告将 641 个整数位置与五种缩放设置组合,与原 x86 函数进行了对比;还单独报告了在指定历史环境中得到 63 字节编译匹配。这是两种不同的验证:选定输入的行为一致,以及生成的机器码一致。
自己分析时,保存每组输入和两边输出。遇到差异,把它缩小为最小失败用例。只有明确编译器版本、选项和重定位处理后,再尝试字节匹配。本站 JavaScript 测试覆盖记录中的算术规则,并未重复原二进制对比。
06. 对比已知结果
将这些结果作为明确的检查点。与它们一致,只能支持这一小段规则,不能证明与整个应用兼容。
| 屏幕 X / 缩放系数 | 整数声像值 | 意义 |
|---|---|---|
| 0 / 1 | −500 | 左边缘 |
| 319 / 1 | −1 | 负数截断 |
| 320 / 1 | 0 | 居中 |
| 321 / 1 | 1 | 正数截断 |
| 640 / −1 | −500 | 反向缩放 |
| 640 / 20 | 10,000 | 数值结果超出音频试听范围 |
将两个文件保存在同一文件夹,用 Node.js 运行验证脚本,无需安装软件包。
node check-case-labs.mjs07. 到底验证了什么?
3,205 组原 x86 对比和 63 个匹配字节,都是上游对一个函数的验证结果。本站用有理数参考实现,在相同的位置/缩放组合上测试独立算术实现。我们没有运行 DXBALL.EXE、重建整款游戏,也没有复现音频引擎。
来源: REA 的 DX-Ball 证据报告 · 固定版本的已维护声像函数。教程、图示和浏览器实验均独立编写。