逆向分析某网游对话框删除汉字异常的bug并修复
2020-02-09 14:23:27 Author: bbs.pediy.com(查看原文) 阅读量:115 收藏

[原创]逆向分析某网游对话框删除汉字异常的bug并修复

1天前 612

[原创]逆向分析某网游对话框删除汉字异常的bug并修复

目录

一、前言

二、准备工具

三、分析

四、修复

五、总结

0x01 前言

       看雪萌新, 正儿八经学习逆向不到半年时间,期间学习了不少关于逆向的理论基础知识作为铺垫,扎实自己的基础。在此要感谢看雪图书《加密与解密四》与《C++反汇编与逆向分析技术揭秘》补足了我基础知识的空白。作为闭关修炼后的第一次实战分析,虽然没有什么技术含量,但起码是自己的一次实践、尝试;也是对这几个月所掌握知识的检验。在看雪记录自己一次次的分析过程,也见证自己一步步的成长,话不多说,我们进入正题。 因为游戏是从国外某服直接汉化的 未修改代码,所以有了“对话框删除汉字异常”的bug,具体现象为对话框输入的汉字删除时,一个汉字需要两次摁删除键才能删除。具体现象如下:


本次的目的就是通过逆向分析找到问题所在并修复它。

0x02 准备工具

       分析环境: win7 32位虚拟机

       所用工具:OD、Cheat Engine、LordPE、WinHex

0x03 分析

       

首先我们能想到的一条思路就是利用CE找到字符串的写入地址,设置内存访问断点,找到调用该地址的函数从而定位问题所在。进入游戏,CE中打开游戏进程,在对话框中随便输入字符串,CE搜索结果如下:

红框标注绿色的地址即为字符串实际存放的地址,用od附加的方式打开游戏主模块so3d.exe,F9继续运行,我们在od数据窗口中ctrl+g输入01172050,找到了存放该字符串的内存地址,ASCII显示为“hello”。

 反复测试我们发现,对话框中字符串的写入地址总是为01172050,因此我们在游戏对话框中重新输入“看雪”, 回到od在01172050可以看到ascii显示为“看雪”:

既然我们找到了字符串写入的地址,不妨先看看写入过程中程序都进行了哪些操作。清空游戏对话框内容,在数据窗口01172050第一个字节处设置内存写入断点,游戏中输入字符后od中断到如下位置:

通过分析上下文,程序写入数据的流程为:堆栈取出要本次写入字符的ascii码值放入bl,将bl与0x26(ASCII为“&”)比较,若相等,则跳过本次写入,然后依次将esi+118和esi+114中存放的字符串数组中的索引值与esi+110中存放的数值(0x41)作比较,若大于或等于,则跳过本次写入,这意味着对话框中最多只能输入64个字符。符合写入条件后,将索引值赋给ecx,在0061775E处用数组下标寻址的方式将bl写入地址,其中esi+0x4为要写入字符串数组的首地址,ecx为索引值,写入后,将三处存放的数组索引值(esi+528、esi+118、esi+114)依次+1,再将写入地址的后一个字节清零后返回。

       紧接着分析程序删除数据的流程。一个思路是在01172050处下内存访问断点,在游戏对话框中删除字符时,od便会中断在删除字符的处理流程中,但实际操作发现一旦设置内存访问断点,od会反复中断在其他函数中,无法定位到删除函数里,看来有其他函数在反复访问该地址进行操作,我们只能换条思路。因为删除字符肯定会改写字符数组中的最后一个字符,因此我们可以在最后一个字节处设置内存写入断点,我们先用“hello”做测试,在它的最后一个字节处,也就是 01172050+4的位置处设置断点,删除字符后,od中断到如下位置:

通过分析上下文,程序删除数据的流程与写入流程相反,就不写汇编注释了。流程为:将esi+528和esi+118处存放的字符串数组索引值依次减1,随后将esi+528处的索引值赋给ecx,依次判断各个存放的索引值ebx(ebx为0)的关系,若小于,则会将索引值修改为ebx, 符合删除条件后,将索引值赋给ecx,在00617A32处用数组下标寻址的方式将bl(ebx为0)写入地址,其中esi+0x4为要写入字符串数组的首地址,ecx为索引值,写入后,将删除字节的位置清零并返回。

        到此,bug产生的原因就很清楚了,本程序中,要想删除一个汉字,有两种途径,一种是将删除函数执行两次(因为在删除函数中每次只操作一个字节)、一种是一次删除两个字节。 跟进程序可以发现,根本没有以上所述的两种方式,程序只会一个字节一个字节的进行操作,其实很正常,因为开篇提到了,此游戏是直接用外服汉化来的,没有对程序进行修改,又因为一个汉字由两个字节组成,所以摁一次删除键,程序只会执行一次删除流程并且只会删除一个字节,从而留下了另外一个字节,显示为“?”。

0x04 修复

      找到问题所在,并且清楚了程序写入和删除的流程后,写补丁就容易的多了。实现汉字的删除有很多思路方法,打补丁也有很多种方式,本次采用增加判断,一次操作两个字节的方式实现删除,打补丁的方式采用SMC补丁。

       PE文件的各区段为了实现大小成倍对齐,会在各区段末尾处留下或多或少的无用字节,用“00”填充,用LordPE打开游戏主模块so3d.exe,区段信息如下:


区段表显示第二个区段.rdata开始的ROffset(文件偏移)为276400,将so3d.exe用 WinHex打开,Alt+G输入276400,转到相对于文件开头处的276400,即下图所示的位置:

箭头所指位置为第二个区段.rdata的开始处,红框标注的即为为了实现对齐而增加的无用字节,我们就选择在276310处写入我们的补丁代码。

        首先我们要找到 276310在内存中的位置,通过简单计算即可得到。 查看区段表, 276310处在第一区段中,是从文件开头处偏移400的位置开始的,因此用 276310-400计算出相对于第一区段的偏移为275910‬,加上内存中第一区段的加载基址00401000得到676F10,在od中跳转到 676F10,如下所示:

要想利用jmp指令让程序跳转到我们指定的位置执行,就需要修改原程序的执行流程。前面说到,在00617A32是执行删除的指令,jmp跳转指令共需要5个字节, 00617A32所处的指令只有四个字节,不满足改写要求,00617A32前一条指令大于五个字节,因此在此处修改,修改如下:

676F10 处的补丁代码及注释如下:


00676F18和00676f1D处的指令为判断字符是否为汉字,因为0x7A在ASCII中为小写的“z”,若小于7A,则删除一个字节,否则为汉字删除两个字节,将这两处修改到可执行文件并保存,替换原文件最终效果如下:


0x05 总结

       知道写一篇分析很累,没想到这么累,对于我这种极度强迫症的人来说,第一篇开山之作耗时9小时,有点浪费时间了。不管怎么样,也算为自己开了个好头吧,会再接再厉的。初出茅庐,若以上分析有错误之处,还望各位同学及时指出,感激不尽。终于可以休息了,搞点夜点心切切咯......

2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!


文章来源: https://bbs.pediy.com/thread-257567.htm
如有侵权请联系:admin#unsafe.sh