红楼梦十二金钗游戏资源分析(十三)

到上一篇我们这个系列也算是告一段落了,但其实我们还可以做一些扩展

目录

本系列已完结,以下是各章节说明,17 之前是 dos 版相关,之后是 2001 版:

  1. 背景、简单分析
  2. 显存位置
  3. 事件图保存算法: LZW
  4. 调色板
  5. MGP2
  6. 结局图
  7. 事件图中的眼睛
  8. 音频文件
  9. 按位读取
  10. 循环之前
  11. 读取循环
  12. 重现 LZW
  13. PAT 的图形格式
  14. STAFF 调色板
  15. 字体文件
  16. 脚本解密
  17. 版本比较
  18. 第一张图
  19. 调色板1
  20. 第二张图
  21. 调色板2
  22. 调色板处理
  23. 静态事件图、结局图
  24. 动态图、鉴赏模式

其他图形格式

根据之前的分析,我们知道程序中还用到了另一种图形格式,不过这次我们还没见到, 其实找到这个也不难,我们知道 LZW 解码的函数是 FUN_1018_3da2, 那看哪里引用了这个函数,应该就会有收获。

只有一个地方有引用,那就更简单了,这个函数是 FUN_1028_0b64,这个函数很长, 不过我们只看 FUN_1018_3da2 相关的部分就好。

if (cVar1 == '\x02') {
  uVar2 = *(undefined4 *)(iVar5 + 9);
  FUN_1018_3da2(local_92,local_90,(int)uVar2,(int)((ulong)uVar2 >> 0x10),uVar9,uVar10);
}
else if (cVar1 == '\x01') {
  uVar2 = *(undefined4 *)(iVar5 + 9);
  FUN_1028_0a0a(local_92,local_90,(int)uVar2,(int)((ulong)uVar2 >> 0x10),uVar9,uVar10);
}
else if (cVar1 == '\0') {
  uVar2 = *(undefined4 *)(iVar5 + 9);
  FUN_1008_3e43(*(undefined2 *)(iVar5 + 5),*(undefined2 *)(iVar5 + 7),(int)uVar2,
                (int)((ulong)uVar2 >> 0x10),uVar9,uVar10);
}

FUN_1018_3da2 并列有三个函数,所以我们推断,游戏里 PAT 的文件中包含了三种格式, 我们已经知道 FUN_1018_3da2 是 LZW 格式了,所以还有两种。

FUN_1028_0a0a

do {
  if (*local_8 < 0xc1) {
    ……
  }
  else {
    ……
  }
  ……
} while ((local_e <= param_2) && ((local_e < param_2 || (local_10 < param_1))));

看到这个循环,我想系列老读者们应该会会心一笑:这是 PCX 格式。细节我觉得 ghidra 的代码还值得商榷,不过我没有深究,因为我打算用之前的代码,毕竟之前我们的 pcx 代码也没什么问题。

FUN_1008_3e43

这个代码我就不贴了,循环非常长,但是与 FUN_1028_0a0a 一样,函数中不涉及其他函数,只是一个纯粹的复杂循环,所以我的想法是,先在游戏中找一些实际读写的日志,然后根据日志和 ghidra 双管齐下确定代码怎么还原,然后再用游戏数据验证我们还原的程序。

思路有了,但是不晓得你有没有想出要怎么做呢,很简单,其实就是在 dosbox 中下断点,注意我用的是 dosbox-x,因为我发现有些版本的 dosbox 是没有调试功能的,这点需要注意,另外如果你发现调试窗口的排版如果有问题,那么你可能需要用 conhost 命令行来启动 dosbox-x。

对于 dosbox-x,alt + pause 就可以进入调试模式,之前我们说过,ghidra 和 dosbox 默认的段位置有差别,但是偏移量是一样的,所以我们可以先找到 ghidra 中的代码位置,然后根据 cpu log,确认我们要下断点到哪里。

1028:0ec1 c4 be 6c ff     LES        DI,[BP + local_96]
1028:0ec5 26 8a 45 23     MOV        AL,byte ptr ES:[DI + 0x23]
1028:0ec9 3c 02           CMP        AL,0x2
1028:0ecb 75 1f           JNZ        LAB_1028_0eec
1028:0ecd c4 3e ac 24     LES        DI,[DAT_1050_24ac]
……
1028:0ee5 9a a2 3d 18     CALLF      FUN_1018_3da2                                    undefined FUN_1018_3da2(undefine
          10

ghidra 这里,0ec5 行取出值,然后根据 al 值进行不同的解码,比如 2 就是调用我们之前的 LZW 方式解码,那么我们的 cpu log 一定也有 0ec5 这行:

0227:00000EC1  les  di,[bp-0094]               ss:[0000577E]=0825     EAX:00030000 EBX:0000000A ECX:00000064 EDX:00000000 ESI:00000070 EDI:00005752 EBP:00005812 ESP:0000576A DS:0287 ES:028F FS:0000 GS:0000 SS:028F CF:0 ZF:1 SF:0 OF:0 AF:0 PF:1 IF:1
0227:00000EC5  mov  al,es:[di+23]              es:[00000848]=0002     EAX:00030000 EBX:0000000A ECX:00000064 EDX:00000000 ESI:00000070 EDI:00000825 EBP:00005812 ESP:0000576A DS:0287 ES:031F FS:0000 GS:0000 SS:028F CF:0 ZF:1 SF:0 OF:0 AF:0 PF:1 IF:1
0227:00000EC9  cmp  al,02                                             EAX:00030002 EBX:0000000A ECX:00000064 EDX:00000000 ESI:00000070 EDI:00000825 EBP:00005812 ESP:0000576A DS:0287 ES:031F FS:0000 GS:0000 SS:028F CF:0 ZF:1 SF:0 OF:0 AF:0 PF:1 IF:1
0227:00000ECB  jne  00000EEC ($+1f)            (no jmp)               EAX:00030002 EBX:0000000A ECX:00000064 EDX:00000000 ESI:00000070 EDI:00000825 EBP:00005812 ESP:0000576A DS:0287 ES:031F FS:0000 GS:0000 SS:028F CF:0 ZF:1 SF:0 OF:0 AF:0 PF:1 IF:1
0227:00000ECD  les  di,[24AC]                  ds:[000024AC]=0000     EAX:00030002 EBX:0000000A ECX:00000064 EDX:00000000 ESI:00000070 EDI:00000825 EBP:00005812 ESP:0000576A DS:0287 ES:031F FS:0000 GS:0000 SS:028F CF:0 ZF:1 SF:0 OF:0 AF:0 PF:1 IF:1

所以我们可以在 dosbox-x 中找到这里,输入 C 0227:0ec5

ghidra 中 FUN_1008_3e43 的调用位置为 1028:0f2f,所以 dosbox 中应该是 0227:0f2f,我们可以用 c 命令再次定位,也可以直接按下往下拉:

所以我们可以在这里下断点,输入 BP 0227:0f2f,然后 F5 继续游戏,玩一会吧。

神奇的是,我转了一会儿,发现,没有进入断点。

不晓得你们得出了什么结论,我的判断是,这是一段无效代码,可能以前有这种类型的资源,后来替换掉了。当然严格一点我们不应该把话说死,起码,这种图像不是常用类型。

之前的系列中,我们有一个 PAT 文件的列表,现在我们可以更新一下了:

  1. AREA.PAT: MGP2,LZW,额外调色板
  2. END.PAT: MGP2,PCX,额外调色板
  3. EVENT.PAT:MGP2,LZW,额外调色板
  4. EVENTEYE.PAT: MGP2,LZW,套用 EVENT 调色板
  5. FACE.PAT: MGP2,PCX,单一调色板
  6. ITEM.PAT:MGP2,PCX,单一调色板
  7. MAP.PAT:MGP2,LZW,额外调色板
  8. MARK.PAT:视频文件
  9. MOUSE.PAT:MGP2,PCX,单一调色板
  10. OPEN.PAT:视频文件
  11. PERSON.PAT:MGP2,PCX,单一调色板
  12. SAREA.PAT:MGP2,PCX,单一调色板
  13. SETUP.PAT:视频文件
  14. STAFF.PAT:MGP2,LZW,调色板有误
  15. SYSTEM.PAT:MGP2,PCX,单一调色板
  16. TITLE.PAT:MGP2,PCX,单一调色板
  17. WINICON.PAT:MGP2,PCX,单一调色板

这么看来,PAT 文件我们已经全看过了,可能真的没有用到第三种格式。

总结

原来觉得可以扩展一下,结果扩展刚开始,就走到了尽头,游戏图形方面对我们基本也没什么秘密了, 再挖下去估计就是事件和文本了,这也是两个未知的领域,有时间我们再研究好了。