adm244/ags2_decomp
GitHub: adm244/ags2_decomp
对经典冒险游戏引擎 AGS 2.x 运行时进行逆向工程和指令匹配的反编译项目,旨在为软件保存和教育目的还原接近原始版本的源代码。
Stars: 0 | Forks: 0
# AGS 2.x 反编译
Adventure Game Studio (AGS) 2.x 的匹配反编译项目。
目标是出于软件保存和教育目的,反编译所有公开发布的 AGS 2.x 版本。
本项目**仅**专注于 runtime engine,**不**包含编辑器组件(DOS 版的 `roomedit` 以及后来的 Windows 版 `agsedit`)。
本仓库中的代码是逆向工程、源码重构和指令匹配过程的结果。源码重构基于 AC 1.14 [roommake](https://archive.org/details/rmakesrc) 和 AGS [legacy](https://github.com/adventuregamestudio/ags/tree/legacy) 源码,主要目标是生成尽可能接近原始版本的源代码。
## 状态
版本 2.00 已**完成**,demo game 可以完全游玩。下一个里程碑将是 2.05,因为这是第一个可以通过“真实”游戏进行测试的版本:LassiQuest。
有关更多信息,请参阅 [STATUS](./STATUS.md)。
## 构建
要构建 DOS 可执行文件,您需要运行在 DOS 上的完整 [DJGPP 环境](https://archive.org/details/DJGPP_Development_System_August_1998)或 DJGPP [交叉编译器](https://github.com/andrewwutw/build-djgpp)。如果您计划进行指令匹配,请使用 DJGPP 环境;否则,建议使用交叉编译。
构建说明假定使用 **unix** 类操作系统,如果您使用的是 **windows**,请考虑使用兼容层或 DJGPP 环境方法。
### 交叉编译
1. 下载并解压 DJGPP [交叉编译器](https://github.com/andrewwutw/build-djgpp/releases/tag/v2.6)。
2. 克隆或[下载](https://github.com/adm244/ags2_decomp/archive/refs/heads/main.zip)本仓库:
```
git clone https://github.com/adm244/ags2_decomp.git
```
3. 进入您希望编译的 AGS 版本目录(例如 `ags200`):
```
cd ags2_decomp/ags200
```
4. 运行 GNU make 以创建构建目录结构(只需一次):
```
make prepare
```
5. 运行 GNU make 进行编译。将 `DJGPP_DIR` 指向交叉编译器的根目录(即 `setenv` 所在的位置)(例如 `~/cross/4.9.4/djgpp`):
```
make DJGPP_DIR=~/cross/4.9.4/djgpp
```
如果构建成功,您将在 `bin` 目录中找到编译后的二进制文件(例如 `ags200/bin`)。
要删除所有可执行文件和目标文件:
```
make clean
```
或者要同时删除已编译的依赖项:
```
make distclean
```
### DJGPP 环境
此方法允许使用与生成原始二进制文件相同的编译器版本,这是指令匹配所必需的。如果您不关心这一点,建议使用交叉编译。
尽管您可以使用任何 DJGPP 版本,但这些说明假定您使用的是 1998 年的[此](https://archive.org/details/DJGPP_Development_System_August_1998) CD ISO,它与原始环境非常匹配。
#### 准备环境
1. 创建一个包含 DJGPP 环境的目录(例如 `~/djgpp-env`)并进入该目录。
2. 创建 `DJGPP` 目录并将 `v2/djdev201.zip` 解压到其中。
3. 按照以下顺序将以下包解压到 `~/djgpp-env/DJGPP` 中:
```
v2gnu/bnu27b.zip # GNU binutils 2.7 (do NOT use 2.8.1)
v2gnu/fil316b.zip # GNU fileutils 3.16
v2gnu/gcc281b.zip # GNU gcc 2.8.1
v2gnu/gdb416b.zip # GNU debugger 4.16 (optional)
v2gnu/gpp281b.zip # GNU g++ 2.8.1 (unpack with replace)
v2gnu/lgp2811b.zip # GNU libg++ 2.8.1.1
v2gnu/mak3761b.zip # GNU make 3.76.1
v2misc/mlp107b.zip # ML's djp 1.07 (optional)
# 如果你需要 DPMI 也要解压这个:
v2misc/csdpmi3b.zip # CS's DPMI 3 (names in UPPERCASE)
```
4. 确保 `DJGPP/djgpp.env` 包含 `+LFN=n` 以禁用 LFN 支持。
此时,您应该在 `~/djgpp-env` 中拥有一个完整的 DJGPP 环境,已准备好进行编译步骤。
5. 克隆或[下载](https://github.com/adm244/ags2_decomp/archive/refs/heads/main.zip)本仓库到 `~/djgpp-env`:
```
git clone https://github.com/adm244/ags2_decomp.git
```
6. 将 `ags2_decomp` 重命名为 `agsdec`(为了符合 8.3 规范,可选):
```
mv ags2_decomp/ agsdec/
```
如果您计划使用 DOSBOX(推荐使用 [DOSBOX-X](https://dosbox-x.com/)),请在 DJGPP 环境目录中创建具有以下内容的 `dosbox.conf`:
```
[autoexec]
@SET PATH=C:\DJGPP\BIN;%PATH%
@SET DJGPP=C:\DJGPP\DJGPP.ENV
```
7. 从 `~/djgpp-env` 启动 DOSBOX。
#### 编译
以下说明假定您已将 DJGPP 环境目录挂载为 C 盘,并且本仓库的内容位于 `C:\AGSDEC`。
1. 进入您希望编译的 AGS 版本目录(例如 `AGS200`):
```
cd AGSDEC\AGS200
```
2. 运行 GNU make 以创建构建目录结构(只需一次):
```
make prepare
```
3. 运行 GNU make 进行编译:
```
make
```
如果构建成功,您将在 `BIN` 目录中找到编译后的二进制文件(例如 `AGS200\BIN`)。
## 指令匹配
此过程确保重构的源代码在使用特定编译器版本编译时,能生成与原始二进制文件完全相同的汇编指令。匹配是通过一个简单的 diffing 脚本,对所有目标文件中的每个函数手动完成的。
请记住,这**不**保证输出是逐字节相同的,因为跳转指令可能具有不同的目标,并且全局变量被放置在不同的地址。因此,在此步骤之后应进行行为匹配过程,以确保行为完全一致。
指令匹配应在 **host** 系统上进行,因为 `diff_symbol.sh` 脚本需要相对较新版本的 `bash` 和 `binutils`,您还需要安装 `cat`(textutils 的一部分)、`grep`、`awk`、`diff` 和 `less`。
确保您已成功编译 `ac.exe` 并且 `obj` 目录中包含目标文件。
运行以下命令以匹配 `AC.O` 中的 `update_stuff` 函数:
```
make diff OBJECT=AC.O SYMBOL=update_stuff
```
在某些情况下,可能有多个具有相似名称的函数,您可以指定符号索引来选择其中一个:
```
make diff OBJECT=AC.O SYMBOL=run_animation SYMBOL_INDEX=1
```
有关可以匹配的所有函数的列表,请参阅 `orig/ac_symbols.txt` 文件。该列表是通过逆向工程并从 Ghidra 导出标记的函数获得的。
有关指令匹配和 GCC2 特定模式的信息,请参阅 [GCC2_NOTES](./docs/GCC2_NOTES.md)。
标签:C++, DOS, UML, URL提取, 云资产清单, 反编译, 客户端加密, 数据擦除, 游戏引擎, 软件遗产, 逆向工程