非常恶心的引擎,研究时花了不少功夫。

解/封包

解包用的garbro,但是其实封包的结构很简单。文件头部是一串int32,依次表示各文件开头的偏移。然后是整个一个int32表示封包文件的大小,然后是\x00\x00\x00\x00,后面是文件数据。

比较坑的一点是,所有文件末尾必须对其到4字节,不足的地方用\x00补齐,否则会报错。推测是使用rep movsd读取的脚本,如果没有对齐,会复制到下一个文件的数据。

文本

这作最恶心的地方就是文本编码。

首先看脚本,完全是一坨乱码,无从下手,遂启动x32dbg。内存里完全也搜不到文本,只能先断GetGlyphOutlineA,往前找找。发现字符是一个一个输出的,往前跟踪,发现了一个字库,所有文本都是通过偏移索引,从字库里取出来的。将字库dump出来。结合ida,简单分析汇编,发现了文本解码的规则。文字分为单字节和双字节。0x00-0xe9为单字节文字,0xea-0xf7为一些单字节控制符:表示主角的姓名(本作可以改名)、文本进行控制、颜色格式等。单字节部分直接编号×2就是字库中的偏移。0xf8-0xff开头的为双字节文字,0x100-第一个字节,乘0x100,加上第二个字节,再×2,就是字库中的偏移。

脚本是虚拟机的二进制字节码,还得进一步分析一下,将脚本从字节码变成伪汇编代码。这主要靠猜+硬凑的方式,之前提过了,这里不再细说。变成伪汇编代码后提取和替换文本就很方便了,再将脚本编译回字节码就可以了。

字库

我原本想,把字库里的字和译文中的字映射一下,然后改字体,就能正常显示了。结果……根据前面所说的字库的编码规则,字库里只能有0x100×9=2304个不同的字符,而译文中有2700个左右的字符。这下问题就很严重了,不仅需要完全重建和替换字库,还得修改字库的编码规则。

前面提到了,0xf8-0xff开头的为双字节文字。但是,0xf0-0xf7为控制颜色的控制符,这几个在脚本里没有使用。如果把这几个开头的也解析成双字节文字,就能大大扩充字符上限。我在游戏程序里读取虚拟机脚本的代码附近找到了两个cmp dl, 0xf8的地方,我将其改为了cmp dl, 0xf5,这样字库的字符上限就增加了0x300个。之后通过在字库的位置下硬件断点(字库的位置是固定的),找到了生成字库的地方,在那里hook,把我自定义的字库写入内存;然后通过替换sjis不支持的汉字,结合修改后的字体,实现了所有文本的正常显示。

免DVD

直接断messagebox,往前找到调用messagebox的地方,把前面的两个条件跳转改一下就行。