首页
社区
课程
招聘
[原创]基于OPENGL引擎3D游戏逆向分析及汉化修改实例(上)(下)
发表于: 2010-11-29 23:47 13388

[原创]基于OPENGL引擎3D游戏逆向分析及汉化修改实例(上)(下)

2010-11-29 23:47
13388

游戏全名:Air Aces: Pacific
中文译名:空中王牌:太平洋
下载地址:c84K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4k6W2M7Y4W2U0k6q4)9J5k6h3y4G2L8g2)9J5c8Y4c8G2M7r3W2U0M7#2)9J5c8U0t1^5x3K6t1K6y4U0k6Q4x3V1j5`.
[I]【原创】基于OPENGL引擎3D游戏逆向分析及汉化修改实例(下)[/I]
        这是一款模拟空战游戏,画面和操控性和市面上其他游戏相比较,算是比较粗糙的。不过这不是我关心的,因为游戏发行只有英文版,所以我想通过pediy的方法加入中文支持,也就是汉化。当然最好能借此找出一些通用的游戏汉化方法。
        OD载入主程序,输入表如下(部分):

	0B029B20   .idata     输入         OPENGL32.glRotatef
	0B029B24   .idata     输入         OPENGL32.glScalef
	0B029B28   .idata     输入         OPENGL32.glShadeModel
	0B029B2C   .idata     输入         OPENGL32.glStencilFunc
	0B029B30   .idata     输入         OPENGL32.glStencilOp
	0B029B34   .idata     输入         OPENGL32.glTexCoord2f
	0B029B38   .idata     输入         OPENGL32.glTexCoordPointer
	0B029B3C   .idata     输入         OPENGL32.glTexEnvf
	0B029B40   .idata     输入         OPENGL32.glTexEnvi
	参考位于 AAP:.text 到 OPENGL32.glGenLists
	地址       反汇编                                    注释
	00415872   call    <jmp.&OPENGL32.glGenLists>
	0041595B   call    <jmp.&OPENGL32.glGenLists>
	00439A56   call    <jmp.&OPENGL32.glGenLists>
	0048E748   jmp     dword ptr [<&OPENGL32.glGenLists  OPENGL32.glGenLists
	0041586B   .  C70424 010000>mov     dword ptr [esp], 1
	00415872   .  E8 D18E0700   call    <jmp.&OPENGL32.glGenLists>
	00415954   .  C70424 010000>mov     dword ptr [esp], 1
	0041595B   .  E8 E88D0700   call    <jmp.&OPENGL32.glGenLists>
	00439A4F  |> \C70424 000100>mov     dword ptr [esp], 100
	00439A56  |.  E8 ED4C0500   call    <jmp.&OPENGL32.glGenLists>

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (12)
雪    币: 30
活跃值: (1193)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
沙发~~ 嘿嘿
2010-11-29 23:49
0
雪    币: 435
活跃值: (1422)
能力值: ( LV13,RANK:388 )
在线值:
发帖
回帖
粉丝
3
[I]【原创】基于OPENGL引擎3D游戏逆向分析及汉化修改实例(上)[/I]
    在上文中,我们已经成功的使游戏创建了我们需要的汉字纹理,不过仅仅有这1024个汉字纹理是不行的,还得想办法让它显示出来。前面说过,游戏会调用glCallLists显示显示列表,glCallLists原型如下:
void WINAPI glCallLists(
    GLsizei n,
    GLenum type,
    const GLvoid *lists
);

        其中n为字符串长度,type为字符串类型,*lists为字符串指针,glCallLists函数下断调试发现,游戏在调用glCallLists时第二个参数使用了0x1400,即GL_BYTE,表示单字节:
00439D3D  |.  BB 00140000   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  |.  897424 08     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个位置依次放入统计出的汉字。按照字符在字库上的位置制作一张码表,然后按照码表将翻译后的文本进行编码转换,再将转换后的结果导入游戏。
        事实上,我有意无意地淡化了在分析调试过程中遇到的种种麻烦,因为事后想想也不过如此。逆向是非常痛苦的,因为下一步总是不可预料的。任何一个小小的麻烦都有可能导致前功尽弃。然而逆向的魅力也正在于此,当咬牙踏出那一步之后,回头看看自己的脚印,我想这都是值得的。
        最后附上一张中文版截图:
上传的附件:
2010-11-29 23:55
0
雪    币: 95
活跃值: (419)
能力值: ( LV9,RANK:310 )
在线值:
发帖
回帖
粉丝
4
thanks for share,support
2010-11-30 22:30
0
雪    币: 6051
活跃值: (1441)
能力值: ( LV15,RANK:1473 )
在线值:
发帖
回帖
粉丝
5
这么好的文章,怎么没人支持?

学习了
2010-12-1 20:58
0
雪    币: 435
活跃值: (1422)
能力值: ( LV13,RANK:388 )
在线值:
发帖
回帖
粉丝
6
可能是游戏引擎里有很多和逆向无关且很难理解的东西,所以关心的人少
谢谢前辈支持 刚刚把上文的链接加进去
2010-12-1 21:05
0
雪    币: 435
活跃值: (1422)
能力值: ( LV13,RANK:388 )
在线值:
发帖
回帖
粉丝
7
谢谢前辈support,下文的链接我已经加进正文了
2010-12-1 21:13
0
雪    币: 6802
活跃值: (4480)
能力值: (RANK:600 )
在线值:
发帖
回帖
粉丝
8
好几年前,也曾有段时间整过opengl, 但是都没有逆向过, 这又来复习复习.
哈哈,谢谢楼主!
2010-12-1 23:06
0
雪    币: 95
活跃值: (419)
能力值: ( LV9,RANK:310 )
在线值:
发帖
回帖
粉丝
9
支持LZ,学习ing
2010-12-2 00:41
0
雪    币: 1694
活跃值: (862)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
一个入手点很重要啊。。学习。
期望楼主发更多的游戏汉化文章
2010-12-4 10:12
0
雪    币: 559
活跃值: (354)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
好资料收下!!
2010-12-4 10:21
0
雪    币: 559
活跃值: (354)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
受教!!
2010-12-4 10:28
0
雪    币: 435
活跃值: (1422)
能力值: ( LV13,RANK:388 )
在线值:
发帖
回帖
粉丝
13
谢谢版主加精,谢谢各位支持,近期再准备一篇关于dx游戏的,个人感觉比这个更有实际作用
2010-12-4 20:24
0
游客
登录 | 注册 方可回帖
返回