到上一篇我们这个系列也算是告一段落了,但其实我们还可以做一些扩展
本系列已完结,以下是各章节说明,17 之前是 dos 版相关,之后是 2001 版:
根据之前的分析,我们知道程序中还用到了另一种图形格式,不过这次我们还没见到,
其实找到这个也不难,我们知道 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 文件的列表,现在我们可以更新一下了:
这么看来,PAT 文件我们已经全看过了,可能真的没有用到第三种格式。
原来觉得可以扩展一下,结果扩展刚开始,就走到了尽头,游戏图形方面对我们基本也没什么秘密了, 再挖下去估计就是事件和文本了,这也是两个未知的领域,有时间我们再研究好了。