- 採用的工具: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++代碼