VOS1.0p字體補丁製作手記
先說說我走的彎路,一開始我認爲VOS是在韓文狀態下編譯的,所以他的進程(thread )的Local也是韓文的,那我只要把進程的Local改成中文的就可以了。在MSDN中查找,發現 有一個API正合我意:SetThreadLocale。但是VOS沒用到SetThreadLocale,於是我修改 import表,插入了SetThreadLocale,再在代碼段中插入代碼去調用SetThreadLocale,都改好後,雙擊VOS運行……熟悉的韓文出現在我面前,當場暈倒。
說出我走過的艱辛的彎路,是爲了告訴大家,一開始找對方向有多麼重要。下面的正路要比彎路簡單多了。
進入正題,我用的工具:W32Dasm用來靜態反彙編,SoftIce用來動態跟蹤,UltraEdit 用來編輯。
首先,當然是用W32Dasm反彙編VOS.exe,還好HanseulSoft沒進行什麼噁心的壓縮加殼 ,輕鬆得到Vos的反彙編代碼。我們是要做的是VOS字體補丁,字體的英文叫Font,搜索Font ,果然VOS用到CreateFontA這個函數,而且跟Font有關的就是隻有這個函數。繼續搜索 CreateFontA,發現VOS共用了兩次CreateFontA,一次在0043DD0B,還有一次在0043DE17。
先看後面的那次調用:
:0043DDEF 50 | push eax | //lpszFace |
:0043DDF0 0FBF942490000000 | movsx edx, word ptr [esp+00000090] | |
:0043DDF8 6A02 | push 00000002 | //fdwPitchAndFamily |
:0043DDFA 6A00 | push 00000000 | //fdwQuality |
:0043DDFC 0FBF84249C000000 | movsx eax, word ptr [esp+0000009C] | |
:0043DE04 6A00 | push 00000000 | //fdwClipPrecision |
:0043DE06 6A00 | push 00000000 | //fdwOutputPrecision |
:0043DE08 6A01 | push 00000001 | //fdwCharSet DEFAULT_CHARSET |
:0043DE0A 6A00 | push 00000000 | //fdwStrikeOut |
:0043DE0C 6A00 | push 00000000 | //fdwUnderline |
:0043DE0E 6A00 | push 00000000 | //fdwItalic |
:0043DE10 51 | push ecx | //fnWeight |
:0043DE11 6A00 | push 00000000 | //nOrientation |
:0043DE13 6A00 | push 00000000 | //nEscapement |
:0043DE15 52 | push edx | //nWidth |
:0043DE16 50 | push eax | //nHeight |
* Reference To: GDI32.CreateFontA, Ord:0036h | ||
| | ||
:0043DE17 FF1578104400 | Call dword ptr [00441078] |
VC中函數的參數是倒着壓入堆棧中的,所以看的時候要倒過來看,熟悉一下CreateFont這個 函數:
HFONT CreateFont(
int nHeight, // logical height of font
int nWidth, // logical average character width
int nEscapement, // angle of escapement
int nOrientation, // base-line orientation angle
int fnWeight, // font weight
DWORD fdwItalic, // italic attribute flag
DWORD fdwUnderline, // underline attribute flag
DWORD fdwStrikeOut, // strikeout attribute flag
DWORD fdwCharSet, // character set identifier
DWORD fdwOutputPrecision, // output precision
DWORD fdwClipPrecision, // clipping precision
DWORD fdwQuality, // output quality
DWORD fdwPitchAndFamily, // pitch and family
LPCTSTR lpszFace // pointer to typeface name string
);
跟國家有關係的是fdwCharSet這個參數,顯然VOS把這個參數設成了HANGUL_CHARSET,所以在裝了 韓文字體的Windows下,VOS會顯示出韓文字。在VC的include目錄中,搜索HANGUL_CHARSET ,在wingdi.h中有:
#define HANGUL_CHARSET 129
129的十六進制是81,而0043DE17的那次CreateFont的CharSet是1,1是DEFAULT_CHARSET,所以不是我們的目標。
再看第一調用:
:0043DCD2 50 | push eax | //lpszFace |
:0043DCD3 6A02 | push 00000002 | //fdwPitchAndFamily |
:0043DCD5 83E180 | and ecx, FFFFFF80 | |
:0043DCD8 6A00 | push 00000000 | //fdwQuality |
:0043DCDA 6A00 | push 00000000 | //fdwClipPrecision |
:0043DCDC 81C181000000 | add ecx, 00000081 | // <---源頭在這裏 |
:0043DCE2 6A00 | push 00000000 | //fdwOutputPrecision |
:0043DCE4 51 | push ecx | //fdwCharSet <--- 犯人就是它!!! |
:0043DCE5 6A00 | push 00000000 | //fdwStrikeOut |
:0043DCE7 6A00 | push 00000000 | //fdwUnderline |
:0043DCE9 6A00 | push 00000000 | //fdwItalic |
:0043DCEB 52 | push edx | //fnWeight |
:0043DCEC 6A00 | push 00000000 | //nOrientation |
:0043DCEE 6A00 | push 00000000 | //nEscapement |
:0043DCF0 6A00 | push 00000000 | //nWidth |
:0043DCF2 6A48 | push 00000048 | //nHeight |
:0043DCF4 6A5A | push 0000005A | |
:0043DCF6 57 | push edi | |
* Reference To: GDI32.GetDeviceCaps, Ord:0125h | ||
| | ||
:0043DCF7 FF1534104400 | Call dword ptr [00441034] | |
:…… | ||
:* Reference To: GDI32.CreateFontA, Ord:0036h | ||
:0043DD0B FF1578104400 | Call dword ptr [00441078] | |
這次調用被VC優化過,參數都在前面設好了,GetDeviceCaps用到兩個參數,倒推上去,可以看到CharSet是通過寄存器CX設置的,所以只要在前面
:0043DCDC 81C181000000 add ecx, 00000081
改成
mov ecx, 1
nop
就可以了。
當我第一次在SoftIce裏改好後進入VOS,看到熟悉的中文,興奮之情難於言表。
2003-08-30
by noword (歡迎轉載傳閱)