OPENGL汽车销售需求分析问题求分析

基于OPENGL引擎3D游戏逆向分析及汉化修改实例(上)(下)
标 题:基于OPENGL引擎3D游戏逆向分析及汉化修改实例(上)(下)
作 者:bitt
时 间: &&&&在上文中,我们已经成功的使游戏创建了我们需要的汉字纹理,不过仅仅有这1024个汉字纹理是不行的,还得想办法让它显示出来。前面说过,游戏会调用glCallLists显示显示列表,glCallLists原型如下:
void&WINAPI&glCallLists(
&&&&GLsizei&n,
&&&&GLenum&type,
&&&&const&GLvoid&*lists
&&其中n为字符串长度,type为字符串类型,*lists为字符串指针,glCallLists函数下断调试发现,游戏在调用glCallLists时第二个参数使用了0x1400,即GL_BYTE,表示单字节:
00439D3D&&|.&&BB&&&&mov&&&&&ebx,&1400&&&&&&&&&&&&&&&&&&&&&&&&;&&第二个参数,GL_BYTE
00439D42&&|.&&890424&&&&&&&&mov&&&&&dword&ptr&[esp],&eax
00439D45&&|.&&E8&464B0500&&&call&&&&&jmp.&OPENGL32.glListBase&
00439D4A&&|.&&83EC&04&&&&&&&sub&&&&&esp,&4
00439D4D&&|.&&893424&&&&&&&&mov&&&&&dword&ptr&[esp],&esi&&&&&&&&&&&&&;&|
00439D50&&|.&&E8&136D0800&&&call&&&&&jmp.&msvcrt.strlen&&&&&&&&&&&&&&;&\strlen
00439D55&&|.&&890424&&&&&&&&mov&&&&&dword&ptr&[esp],&eax&&&&&&&&&&&&&;&将strlen结果作为第一个参数
00439D58&&|.&&&&&&&mov&&&&&dword&ptr&[esp+8],&esi
00439D5C&&|.&&895C24&04&&&&&mov&&&&&dword&ptr&[esp+4],&ebx
00439D60&&|.&&E8&234B0500&&&call&&&&&jmp.&OPENGL32.glCallLists&
&&因为游戏原有256个显示列表,字符串为单字节字符串,而现在我们要使用1024个显示列表,相应的字符串必须使用双字节编码,这里第二个参数必须修改,截取gl.h部分如下:
#define&GL_BYTE&&&&&&&&&&&&&&&&&&&&&&&&&&&0x1400
#define&GL_UNSIGNED_BYTE&&&&&&&&&&&&&&&&&&0x1401
#define&GL_SHORT&&&&&&&&&&&&&&&&&&&&&&&&&&0x1402
#define&GL_UNSIGNED_SHORT&&&&&&&&&&&&&&&&&0x1403
#define&GL_INT&&&&&&&&&&&&&&&&&&&&&&&&&&&&0x1404
#define&GL_UNSIGNED_INT&&&&&&&&&&&&&&&&&&&0x1405
#define&GL_FLOAT&&&&&&&&&&&&&&&&&&&&&&&&&&0x1406
#define&GL_2_BYTES&&&&&&&&&&&&&&&&&&&&&&&&0x1407
#define&GL_3_BYTES&&&&&&&&&&&&&&&&&&&&&&&&0x1408
#define&GL_4_BYTES&&&&&&&&&&&&&&&&&&&&&&&&0x1409
#define&GL_DOUBLE&&&&&&&&&&&&&&&&&&&&&&&&&0x140A
&&无符号双字节为GL_UNSIGNED_SHORT,所以应将0x00439D3D处指令改为mov&&&&&ebx,&1403。接下来修改第一个参数,第一个参数改起来比较麻烦。原游戏使用ascii码所以可以调用strlen,而我们使用双字节字符串,那么必须使用wcslen来求字符串长度,而导入表里没有wcslen,这时候我们必须自己加入一个导入函数。这里为了省事我使用了pe工具stud_pe,wcslen位于动态链接库msvcvrt.dll中,增添该函数后如图:
&&图中可以看出,导入函数wcslen的RVA为0xB05214B,理论上只要我将call&&jmp.&msvcrt.strlen&改为call&[0xB05214B],便可以达到目的。但是事情总是比之前想象的复杂一点。这里如果直接改为call&dword&ptr&[0xB05214B],目的地址与指令地址偏移量大,call为远call,指令长度为6字节,而原来的call是近call,指令长度为5字节,这将覆盖掉下面的mov&dword&ptr&[esp],&eax指令。后果将是glCallLists永远得不到正确的字符串长度。
&&不过这很容易解决,我们只需要在代码的缝隙中找到一块6字节的空白区,然后加入指令jmp&[0xB05214B],再call到这条新加入的指令,就可以顺利解决了。我将这条指令放在了0x439c36,然后修改0x439d50处的指令为call&0x439c36,问题解决。如图:
&&至此,对游戏引擎的修改已经结束。
&&剩下的工作比较简单了,将游戏的英文文本找出并逐一翻译。统计翻译后的中文文本,也就是统计使用了那些汉字。然后制作一张32格*32格的字库,其中前128个位置放置游戏原有字符并与游戏原来字符顺序保持一致,以便能够正常显示一些特殊字符,后896个位置依次放入统计出的汉字。按照字符在字库上的位置制作一张码表,然后按照码表将翻译后的文本进行编码转换,再将转换后的结果导入游戏。
&&事实上,我有意无意地淡化了在分析调试过程中遇到的种种麻烦,因为事后想想也不过如此。逆向是非常痛苦的,因为下一步总是不可预料的。任何一个小小的麻烦都有可能导致前功尽弃。然而逆向的魅力也正在于此,当咬牙踏出那一步之后,回头看看自己的脚印,我想这都是值得的。
&&最后附上一张中文版截图:

参考资料

 

随机推荐