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 (欢迎转载传阅)
本文记录了VOS1.0p字体补丁的制作过程。作者起初走了弯路,后用W32Dasm反汇编VOS.exe,搜索到CreateFontA函数。经分析,发现修改第一次调用该函数时设置CharSet的代码,可将VOS显示的韩文改为中文,作者修改后成功看到中文显示。

3396

被折叠的 条评论
为什么被折叠?



