利用OD通过Call调用实现扫雷(win7旗舰版32位)
一直对逆向感兴趣,就拿最简单的扫雷开始,对于XP系统中的扫雷,雷的数目以及雷区的地址都是固定的,可以直接通过Cheat Engine搜索出来,然后在OD中直接下内存访问断点,找到扫雷整个区域,获得行数和列数,再顺藤摸瓜找到左键点击的处理函数和右键点击的处理函数,读取雷区数据,一一比较如果是雷就右键标记,如果不是可以直接左键点开,即可完成秒杀。
经过了大概半个月的时间,终于在查阅各种帖子和不断的摸索下,实现了Win7 32位系统扫雷的秒杀,哈哈,太开心了!
因为XP系统的扫雷中雷区的地址是固定的,可以通过CE进行搜索出来,但Win7系统的扫雷是用C++写的,雷区不再是固定的,而是在鼠标第一次点击之后再产生雷的位置。对win7扫雷一开始没有一点思路,后来看了很多牛人写的帖子,在他们的基础上才能慢慢的入手。可以参考:
《Vista的扫雷》:http://bbs.pediy.com/thread-40295.htm
《Win7自动扫雷》:http://bbs.pediy.com/thread-120152.htm
这2篇文章里的思路都是通过对rand函数下断,分析找到雷存放的地址,每个格子里存放0或1,如果是1则是雷,是0则不是雷,发送消息模拟鼠标的单机,进行自动扫雷。其中,在《Vista的扫雷》提到了重定位的处理,解决方案2对于Win7 32位下的扫雷并不适用,这篇文章中提到:
“假设扫雷入口地址设为dwCodeAddress,则[3931B8] 这个地址得到的方法是: ( dwCodeAddress & 0xFFFF0000 ) + 0x531B8”
但是在Win7 32位的扫雷中,并不是这样的,用PEiD打开扫雷
可以看到,扫雷的入口点是0x0002e08f,用OD打开扫雷,停在了入口点,代码是
001CE08F > $ E8 B5050000 call MineSwee.001CE649
001CE094 .^ E9 4DFDFFFF jmp MineSwee.001CDDE6
所以扫雷中地址的计算方法是:扫雷模块地址+偏移
入口点地址0x1ce08f = 扫雷模块地址+0x2e08f,所以此次加载扫雷模块地址为
MineSweeper.exe = 0x1A0000
在此我找到了一种可以去除重定位的方法,PE头中的文件头的Characteristics字段指定了文件的类型,占用2字节,其第0比特为1,即表示文件中不存在重定位信息,用C32Asm打开扫雷,找到该字段
该字段为0x0102,其第0比特为0,即存在重定位信息,将其修改为1,将会给我们分析带来很大的方便(地址固定),即将该字段修改为0x0103,在下面的分析中我就用修改后的文件进行分析,该修改并不影响分析结果,同样适用于没修改的扫雷(因为偏移是固定的)。分析前面的过程在《Vista的扫雷》和《Win7自动扫雷》中讲得很详细,在此不做赘述,简单走一遍,看过的可以直接跳过。
首先,用OD加载扫雷,对rand函数下断:bp rand,然后先将该断点禁止,按F9运行起来,启动该断点,扫雷断下
一看便知该模块不是扫雷的模块,而是msvcrt。在堆栈窗口中看到,
在第1行处反汇编跟随(按Enter),到
鼠标点到该函数第一行,OD在反汇编窗口下方会有提示
“本地调用来自 01020176, 01023169, 01023177, 01023BB3, 01027466, 010275B9, 01027E86, 01027E98”
对这8个call都进行下断,F9,会发现一直断在
删除这个断点,继续F9,回到游戏,不会中断了,开始游戏并点击一个格子,断在如下位置
往上看,则如《Vista的扫雷》中一样,是根据第一次点击的格子产生序号并保存序号的代码,在此列举一下,看过的可以跳过
按Ctrl+F9 2次执行到返回,或在堆栈窗口中找到第2个“返回到”,跟随到上上一层:
其中,call MineSwee.01021418中的代码及注释如下(看过的可以跳过)
到此得到了地址0x10868b4,查看入口点代码
扫雷模块地址为0x1000000,所以
方块数据=[[[[[[[minesweeper.exe+0x868B4]+0x10]+0x40]+0x0C]+4*X坐标]+0x0C]+4*Y坐标];分析一下取值有 1~8数字 9未开 10旗 11问号 12空
雷地址 =[[[[[[[minesweeper.exe+0x868b4]+0x10]+0x44]+0x0c]+4*X坐标]+0x0c]+Y坐标] 1表示有雷 0表示没雷
esi=[[minesweeper.exe+0x868B4]+0x10];minesweeper.exe表示扫雷模块地址
[esi+0x4] => 雷数
[esi+0x8] => 行数
[esi+0xc] => 列数
[esi+0x18] => 鼠标左键单击次数
第一次点击 列号:[esi+0x24]
行号:[esi+0x28]
然后找左键单击打开格子Call,既然是左键单击,该Call中的参数应该是点击格子的X坐标和Y坐标,所以在该Call之前应该有如下类似操作:
push X坐标
push Y坐标
Call 0x……
在我们之前的分析中寻找,发现有2个地方可疑
第一处:
第二处:
对于第二处,有个跳转,不是第一次点击格子的话会跳过,因此排除。怀疑第一处是我们要找的Call,用CE加载扫雷,在自动汇编中写入测试脚本:
执行,得到myscript=某个地址,记住该地址,打开创建线程,输入该地址,确定,看扫雷打开了一大片,哈哈!这就是我们要找的左键单击打开一个格子的Call。现在便可以实现一键自动扫雷了,但是为了能够把雷标记出来,我们还可以找右键单击的Call。
右键单击格子会改变格子的状态,10为旗,11为问号,在第一颗方块数据处下硬件断点,即X=0 Y=0处,[[[[[[[minesweeper.exe+0x868B4]+0x10]+0x40]+0x0C]+4*0]+0x0C]+4*0],右键单击第一个格子,扫雷断下,进行回溯跟踪,在第二次返回后,找到了可疑的地方
和左键单击一样,也是压入Y坐标和X坐标为参数,然后调用一个Call,但是调用之前给ecx进行了赋值,来源于esi,又要找esi,但是在上层中寻找,并没有发现esi来源于什么地址。不如跟进该Call看看
是不是很熟悉,原来ecx就是之前的那个指针,即[[minesweeper.exe+0x868b4]+0x10],在CE中写脚本进行测试:
执行后,发现扫雷并没有什么反应,有点失望!但是在扫雷中其他格子右键单击一下,发现第一个格子也变成被标记状态了,哈哈,这就是我们要找的右键单击格子Call,分析终于完成了!花了2周多时间,最后还是有点小激动,\(^o^)/
最后进行编程实现:
界面如上,首先点击注入会获得共有几颗雷,并安装键盘钩子,按Home键进行一键扫雷,按F12进行全部标记。
最后,附一张扫雷自定义中难度最大时进行一键扫雷的截图,如下,24*30,共668颗雷。
主程序代码:
GetProcessBase.h代码:
该函数是获得扫雷模块地址的函数,相比《Vista的扫雷》中寻找程序入口点,该函数效率更高一些。
DLL钩子程序如下:
有不足之处,希望大家提出,欢迎讨论!
本文由看雪论坛 Thvoifar 原创,转载请注明来自看雪社区
热门阅读
点击阅读原文/read,还有更多干货等着你~