逆向分析某网游对话框删除汉字异常的bug并修复
2020-02-15 18:59:00 Author: mp.weixin.qq.com(查看原文) 阅读量:86 收藏

本文为看雪论坛优秀文章

看雪论坛作者ID:Passdtab

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小时,有点浪费时间了。
不管怎么样,也算为自己开了个好头吧,会再接再厉的。初出茅庐,若以上分析有错误之处,还望各位同学及时指出,感激不尽。终于可以休息了,搞点夜点心切切咯......

- End -

看雪ID:Passdtab

https://bbs.pediy.com/user-875819.htm 

*本文由看雪论坛  Passdtab  原创,转载请注明来自看雪社区

推荐文章++++

Dex文件结构学习

Bambook把玩心得

PHPStudy后门事件分析

CVE-2012-0003漏洞分析

X86指令混淆之函数分析和代码块粉碎

好书推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]
“阅读原文”一起来充电吧!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458303454&idx=1&sn=e88d078774fc4f27277b54d629c8b751&chksm=b1818b5486f602425b4c6e7a6e63ba7d817338adeeebc6592c0be640c86be07a4d40007a3bc1#rd
如有侵权请联系:admin#unsafe.sh