陷阱技术探秘----动态汉化Windows技术的分析(3) 这样,我们在EXEHDR这一简单而非常有用的工具帮助下,已经在Windows的浩瀚海洋中畅游了一会,下面就来掀开“陷阱”技术的神秘面纱。 三、动态汉化Windows原理 我们知道,传统的汉化Windows的方法,是要直接修改Windows的显示、输入、打印等模块代码,或用DDK直接开发“中文设备”驱动模块,这样不仅工作量浩大,而且,系统的完备性很难保证,性能上也有很多限制(早期的长青窗口就是这样),这样,只有从内核上修改Windows核心代码才是最彻底的办法。 从Windows的模块调用机制,我们可以看到,Windows实际上是由包括在KERNEL,GDI,USER等几个模块中的众多函数支撑的。那么,修改其中涉及语言文字处理的函数,使之能适应中文需要,不就能达到汉化目的了吗?因而,我们可以得出这样的结论:在自己的模块中重新编写涉及文字显示,输入的多个函数,然后,将Windows中对这些函数的引用,改向到自己的这些模块中来。 修改哪些函数才能完成汉化,这需要深入分析Windows的内部结构,但CHINESE.DLL已明确无误地告诉了我们,在其数据段的重定位表中列出的引用函数,正是CStar修改了的Windows函数! 为了验证这一思路,我们利用RichWin作一核实。 用EXEHDR分析GDI.EXE,得出ExtTextOut函数在GDI的第一代码段6139H偏移处(不同版本的Windows其所在代码段和偏移可能不一样)。然后,用HelpWalk(也是MicrosoftVisualC++开发工具中的一个)检查GDI的Code1段,6139H处前5个字节是B8FF054555,经过运行RichWin4.3forInternet后,再查看同样的地方,已改为EA08088F3D,其实反汇编就知道,这5个字节就是代表Jmp3D8F:0808,而句柄为0x3D8F的模块,用HelpWalk能观察到正是RichWin的WSENGINE.DLL的第一代码段(模块名为TEXTMAN)。而偏移0808H处B8B73D45558BEC1E,正是一个函数起始的地方,这实际上就是RichWin所重改写的ExtTextOut函数。退出RichWin后,再用HelpWalk观察GDI的Code1代码段,一切又恢复正常!这与前面的分析结论完全吻合!那么,下一个关键点就是如何动态修改Windows的函数代码,也就是汉化Windows的核心——“陷阱”技术。 四、“陷阱”技术 讨论“陷阱”技术,还要回到前面的两个发现。发现之二,已能解释为修改的Windows函数,而发现之一,却仍是一个迷。 数据段存放的是变量及常量等内容,如果这里面包含有重定位信息,那么,必定要在变量说明中将函数指针赋给一个FARPROC类型的变量,于是,在变量说明中写下: FARPROCFarProcFunc=ExtTextOut; 果然,我自己程序的数据段中也有了重定位信息。这样,当程序调入内存中时,变量FarProcFunc已是函数ExtTextOut的地址了。 要直接修改代码段的内容,还遇到一个难题,就是代码段是不可改写的。这时,需要用到一个未公开的Windows函数AllocCStoDSAlias取得与代码段有相同基址的可写数据段别名,其函数声明为 WordFARPASCALAllocCStoDSAlias(WORDcode_sel); 参数是代码段的句柄,返回值是可写数据段别名句柄。 Windows中函数地址是32位,高字是其模块的内存句柄,低字是函数在模块内的偏移。将得到的可写数据段别名句柄锁定,再将函数偏移处的5个字节保留下来,然后将其改为转向替代函数(用EAJmp) *(lpStr+wOffset)=0xEA; *(lpStr+wOffset+1)=lpFarProcReplace; 反汇编即是JmplpFarProcReplace,最后,内存解锁。 这就是我们为Windows设的“陷阱”,当所有对此函数的调用都无条件地转到我们规定的替代函数处。当程序结束之前,将保留的5字节内容再置回来,否则,系统会崩溃。 下面给出作者编写的使Windows的ExtTextOut函数落入自己函数“陷阱”的源程序。 //源程序 relocate.c