pscj's Blog

走过岁月我才发现世界多不完美,成功或失败都有一些错觉

博客园 首页 新随笔 联系 订阅 管理
 

经过前边的字库改造,已经完成了一半的工作,剩下最关键的显示汉字部分了。字库已经是中文的了,但是能让中文显示出来却不是件容易的事。不信现在进游戏试试,看到的中文全是乱码。为何?因为中文是双字节,两个字节才代表一个汉字。游戏显示英文字体的函数是为显示单字节的英文设计的,是不适合显示中文的,必须要修改。因为不可能得到程序的源代码,修改方法只能采用比较极端的修改可执行文件的方法了,即所谓的逆向工程。

于是操起常用的调试工具Ollydbg开始调试游戏。经过2天的不懈努力,终于找到了显示字库的函数,以下列出读取字符的函数部分代码:

004AA909   8A08          mov cl,byte ptr ds:[eax]       

004AA90B   40            inc eax                                                                      

004AA90C  8BF1           mov esi,ecx                    

004AA90E  8BD6           mov edx,esi                    

004AA910  F7DA           neg edx                        

004AA912  1BD2           sbb edx,edx                    

004AA914  23D0           and edx,eax                    

004AA916  85F6           test esi,esi                   

004AA918  8917           mov dword ptr ds:[edi],edx     

 

函数开始Eax指向脚本文件grim.tab文件中某行脚本的第一个字符。例如主菜单”Control Help”中的C位置。004AA909一行的意图很明显,读取字符串中当前位置的的一个字符的ASCII码到放到cl中,然后Eax加一,指向下一个字符。然后会将此cl中的字符当作参数,调用另外一个显示字符的函数,完成读取字库文件并显示字符到屏幕的功能。

我们需要对此部分做改造。如当前Eax指向一个英文字符,则还沿用程序原来的部分,读取一个字节到cl,并使Eax增一;如当前Eax指向一个中文汉字,则需要程序读取2个字节到cx中,并使Eax增二,指向下一个字符的正确位置。那么如何判断当前Eax指向的是一个英文字符还是中文汉字呢,GB2312汉字的编码有一个的特性:两个字节编码最高位(8)一定是1。每次读取字符时,先判断第8位是0还是1,如果是1一定是中文,是0则是英文。

有了思路,对读取字符的函数做如下修改,红色为新增代码:

004AA909       8A08         mov cl,byte ptr ds:[eax] 

004AA90B       40            inc eax                   

                      f6c180       test cl,80h              

                     7406           je 4aa90c                

                     c1e108       shl ecx,08h              

                      8a08          mov cl,byte ptr ds:[eax] 

                      40              inc eax                           
       004AA90C     8BF1           mov esi,ecx               

004AA90E     8BD6           mov edx,esi              

004AA910     F7DA           neg edx                  

004AA912     1BD2           sbb edx,edx              

004AA914     23D0           and edx,eax              

004AA916     85F6           test esi,esi             

004AA918     8917           mov dword ptr ds:[edi],edx

 

先放Eax一个字节到cl中,然后判断cl的第8位是否为1,如果是0,说明是英文字符,则按程序原来的进度跳转到004AA90C这行的代码继续执行。如果是1,则要将cl向左移8位,为汉字第二个字节留下位置,然后再取一次Eax的值,把第二个字节放到cl中。最后Eax增一(Eax增了两次1)。此时Ecx的数值正是一个汉字两个字节的内码。Finish!

然后用Uedit打开可执行文件,找到一段nop(90)比较多的位置,最后将红色部分的机器码加到合适位置就OK了。

posted on 2005-05-10 23:01  pscj's Blog  阅读(3386)  评论(4编辑  收藏  举报