- 采用的工具:x32dbg
- 在教程一中,修改编码是定位到了CreateFontIndirectA这个函数,实际上创建字体可能还会是一些其他的函数,不过一般名字会带FONT。
- 之前研究SOFTPAL ADV SYSTEM这个引擎,发现改了字体编码之后,显示的字体依旧是乱码,查了一下资料,发现游戏字体显示实际上可能还会进行字符边界检测
- GB2312和SHIFT-JIS编码中除了ASCII部分,都是两个字节组成一个符号的
- 日语SHIFT-JIS的编码范围是(前一个字节
0x80~0xA0
)以及(后一个字节0xE0~0xFC
) - 在打印字体的时候,有些程序会校验编码范围,过滤掉不在此范围的非法字符,而我使用的文本编码是GB2312,编码范围和日语不同,因此就算修改了编码,如果部分字符被过滤,显示出来的字符依旧会是乱码。
- GB2312的编码范围是0xA0A0-0xFEFE
- 因此,在修改完createFontxxx函数的编码参数之后,如果依旧乱码,则还要检查一下是否有进行字符边界检测。
- 目前大部分游戏的字体输出都是调用GetGlyphOutlineA这个函数,一般都会在调用这个函数之前进行字符边界校验。
- 因此需要在GetGlyphOutlineA的上面,或者是调用GetGlyphOutlineA的函数(可能不止嵌套一个)的代码上面,寻找边界检测的特征代码
- 边界检测的代码的特征也很好认,留意一串连续的jb,ja等跳转判断(一般跳转的地址是一样的),cmp的参数有0xA0,0xE0,0xFC(或者相差+/-1的数值)
- 下面以一个我调试的游戏为例
下面以Hearts的恋するココロと魔法のコトバ为例子
- 修改编码的操作忽略~~,该游戏是在pal.dll里面进行编码修改的
- 找到边界检测代码
- 分析边界检测代码
标识符 | 说明 |
---|---|
JA | 较大则跳转 |
JB | 较小则跳转 |
JBE | 较小或相等则跳转 |
对上述的代码使用x32dbg自带的反编译分析,得到下面的代码(实际的代码要更长,这里截取部分代码,感觉这种形式应该更加方便理解代码)。
这里的al41是当前读取到的字符(1字节),esi50->f1是下一位字符(1字节)
if (!(int1_t)(al41 == 60)) {
// 这里的60对应的ascii码是<符号,由于调试的游戏文本中存在<br>等标记符,所以猜测else是用来处理这些特殊文本的
if
(
(
(uint8_t)al41 >= 0x81 && (uint8_t)al41 <= 0x9f || (uint8_t)al41 >= 0xe0 && (uint8_t)al41 <= 0xfc
)
//上面的条件就是用来判断第一个字节编码范围
//但是这里的判断不仅是判断一个日文的前一个字节,也判断了后面一个字节这一种情况
//并且判断第一位字节的时候范围偏差了1,正常来说应该是0x81~0xA0,暂时不知道是为什么
&&
(esi50->f1 >= 64 && esi50->f1 <= 0xfc) || (int1_t)(al41 == 37) && (esi50->f1 >= 48 && esi50->f1 <= 57)
)
//这里的判断条件,前半部分应该是用来判断第二个字节的范围
//后半部分的判断条件有点迷,为:第一个字节为ASCII的%并且第二个字节为0~9的数字
//用或连接,说明两种情况都有效
{
do something #1
} else {
do something #2
}
do something
}
else{
do something #3
}
由上面的代码可以看出,正常显示的符号应该是#1代码块
里面执行,因此修改的时候需要保证GB2312编码的字符可以进入到#1代码块
执行(只看上面的代码其实无法得出这个结论,因为在第一个判断条件的else里面的代码其实有着其他逻辑,但是这里先不管,直接修改编码范围了再说)。
需要修改的地方有三处,如下图所示(红色的16进制码即为修改的地方,这里修改的不一定是对的,由于暂时没搞懂原先代码里面的判断条件,但是至少程序运行起来没什么问题)
- 初步跑了一下程序,使用gb2312编码的文本显示并没有什么问题。
- 上述的修改不一定是正确的,这里只是提供一下思路~~
- 注意SOFTPAL ADV SYSTEM这个引擎,字体显示相关的函数导入了一个叫
pal.dll
的库,createfont这个函数的编码参数0x80就是在这个dll里面传的。 - 在网上有看到这个dll的相关解析,具体可以看Nomeluka的GalPatches项目。
- x32dbg个ollydbg比起来,界面好看了挺多的,也很简洁,不过缺点还是有的,插件貌似是比ollydbg要少(个人觉得)。
- SOFTPAL ADV SYSTEM这个引擎的资料好少(
一定是我的搜索姿势错了)
调试的小技巧
- 如果你调试到了系统的dll(像是gdi32.dll之类的)里面的函数,就直接跳出来吧,我们进行修改一般都是游戏的程序本体或者是它自己定义的dll。
- x32dbg有一个可以看dll和游戏程序里面定义的函数的地方,可以节省我们下断点的时间。
- x32dbg在汇编代码的区域里面右键-反编译,可以得到转化之后的c++代码