一个开源项目把 2004 年 11 月 25 日调试版的 GameCube 生化危机 4 完整重建为 C 和 C++,编译产物能和原版 main.dol 以及全部 114 个 REL 覆盖模块逐字节对上,合计覆盖 15641 个函数,src 目录约 55 万行,include 目录约 3.3 万行。这类工程的价值不在能不能玩,而在它证明了当年二进制背后的源码结构可以被完整恢复,对软件保存、漏洞研究和旧平台维护有直接意义。写给对逆向工程、代码复原和软件保存有兴趣的工程师,门槛在工具链复原和符号保真,不在体力。
字节级一致到底指什么
匹配反编译的验收标准和普通还原完全不同。这个项目以编译源码能逐字节复现 main.dol 和全部 114 个 REL 为目标,构建结束会报告 DOL 和 REL 模块 100% 匹配链接,校验和验证打印 115 行 OK。调试符号文件提供了每个原始函数名,675 个对象在 DOL 主可执行文件里,408 个对象分布在 114 个 REL 覆盖模块里,合计 1083 个对象。没有汇编码源文件,少数函数以 C 文件里的整体 asm 块实现。
项目用了什么工具链
三套工具链按代码归属分开。游戏代码用 SN Systems ProDG 3.9.3,内置 GCC 2.95.3,从 SN 公开的 GPL 源码编译。CRI 中间件用 Metrowerks CodeWarrior 2.4.7。任天堂 SDK 用 Metrowerks CodeWarrior GC/1.2.5n,源码取自 dolsdk2004。整个构建在 Linux 上跑,用 Python 3 和 ninja,多数工具首次配置时自动下载,原生 SN GCC 需要单独编译。需要自备调试版光盘镜像,第一张提供 main.dol 和 110 个 REL,第二张提供四个海岛关卡 REL,流程是编译 SN GCC、把两个镜像放进 orig/G4BE08/、运行 configure.py 再 ninja。
匹配是怎么做到的
每个编译单元用当年的编译器产出原始字节。编译器需要特殊源码形状才能得到特定寄存器选择和指令调度的地方,代码里带 COMPILER-DIFF 注释,共 644 处,这些注释本身不产生指令,asmcheck.py 会确认只有硬件内核是指令模板生成的。剩下的汇编对应原作者当年因为编译器没有替代方案而手写的例程,包括配对单精度数学内核、GQR 设置、声音异常处理器,以及 CRI 和 SDK 的矩阵向量 intrinsics 和 DCT 解码器里的一段寄存器控制块。八个整体汇编单元是 crt0、eabi、几个 SN 系统库和 Capcom 的 memset_2、yz2asm。
工程上有哪些值得借的做法
技术亮点集中在把当年的编译器脾气摸清楚。项目从 CRI 库里移除了约一百处手工放置的内联指令和约一百处寄存器钉扎汇编块,换成纯 C。函数名从调试版的 C++ 修饰符号文件恢复。部分结构体布局参考 PS2 调试版的类型信息,用脚本匹配到 GameCube 偏移。用 #line 指令复现厂商原始行号。动画导出管线用游戏自己的代码求值并在模拟器里验证,保证导出结果和运行时行为一致。
这类工程有什么用和边界
复原出的游戏、SDK 和中间件源码的知识产权仍归卡普空、任天堂和 CRI Middleware,项目只用于研究和保存,构建脚本、工具和文档以 CC0 发布。对工程师来说,这套方法可以直接搬到其他旧平台的保存项目上,思路是先用符号文件恢复函数边界,再用当年的编译器逐单元复现原始字节,最后只把编译器实在还原不了的手写例程留成汇编。判断一个反编译项目是否可信,先看它有没有可重复的构建验证,再看它能不能说清每一段汇编为什么留着。
FAQ
Q 需要原版光盘吗。A 需要自备调试版光盘镜像,两张盘分别提供主可执行文件、大部分 REL 和四个海岛关卡 REL。
Q 普通版能和调试版对上吗。A 项目目标是 2004 年 11 月 25 日的调试版,调试符号文件是函数名和结构体能恢复的前提。
Q 能从中学到什么可迁移的技能。A 按代码归属拆分工具链,用当年编译器做逐字节验收,把手写例程单独隔离,这套流程对任何旧平台复原都适用。