# 1.分析过程
# (1)寻找游戏基础信息存储位置
调整扫雷游戏难度等级,使地雷数量发生改变,然后在 CE 界面填写新的地雷数量,单击“再次扫描”按钮。不断重复这样的操作,直至 CE 左侧找到的地址数降为个位数,双击所找到的地址,将其添加到 CE 下方地址列表中。
存储地雷数量的地址:0x01005194、0x01005330、0x010056A4
寻找地图高存储位置,将地图高从24修改为20
存储地图高的地址为:0x01005338和0x010056A8
寻找地图宽存储位置,将地图宽从30修改为26
存储地图宽的地址为:0x01005334和0x010056AC
寻找存储游戏时间的地址,首次扫描数值为0
开始游戏后,不断扫描增加的值,直至扫描结果地址变为个位数
存储游戏时间的地址为0x0100579C
寻找已扫数量存储的位置,通过不断增值查找
存储已扫数量的地址为0x010057A4
# (2)使用ollydbg找到游戏计时指令存储位置
在0x0100579C除设置硬件写入断点,找到计时指令存储位置为0x01003830和0x01002ff5。可在程序中修改这些地址的数据为0x90(nop指令),因此可以在游戏运行时不执行计时递增指令,从而做到游戏计时器停止。
# (3)点到雷不结束游戏
通过调试发现,程序会将点击位置所在地址的内容与80进行test操作,然后执行je 0x01003595跳转。若点击位置所在地址的内容的若为0x8F,则不执行je跳转;若点击位置所在地址的内容的若为0x0F,则执行je跳转。
通过对0x01003595的跟踪调试,发现后续执行的是继续游戏的操作,而在不跳转0x01003595则会执行到0x01003593处执行jmp 0x010035AB指令结束游戏。因此可以将内存中0x01003591-0x01003594处的指令修改为nop指令填充,从而满足无条件的游戏继续的跳转(点到雷继续游戏)。
# (4)自动游戏获胜功能1——确定雷区真实的内存起始地址
在扫描得到的多组地址中,依次通过右键“浏览相关内存区域”,打开地址所对应的内存空间,然后通过开始新一局游戏和点击雷区左上角的操作,确定雷区真实的内存起始地址,以及地雷和非地雷的标识,地址为0x01005361
地雷标识数据为0X8F,非地雷标识数据为0X0F 。
修改地图宽
修改地图高
最后通过创建新一局游戏,依次点击第 1、2、3 行最左侧格子的操作确定雷区每行的起始地址,寻找起始地址与雷区行和列之间的对应关系,即确定每行格子的数量为32。
# (5)自动游戏获胜功能2——确定扫雷游戏格子大小
打开 Spy++,单击“监视–日志消息”,勾选“隐藏 Spy++选项”,拖动“查找程序工具”至扫雷游戏主界面,如图 8-4 所示,显示的内容包括扫雷窗口类(WNDCLASS)的名称以及标题名。
切换至Spy++的“消息”窗口,先清除所有消息,然后勾选 “WM_LBUTTONDOWN 和 WM_LBUTTONUP”两个消息,如图 8-5 所示,单击确定后返回 Spy++主界面。
返回扫雷游戏界面,依次单击左上角、紧邻左上角右方、紧邻左上角下方的三个格子,查看 Spy++记录的鼠标单击时的 xPos 和 yPos 的值,以此计算每个格子的宽度和高度。
首个雷区坐标为:
xPos =14
yPos =58
在Spy++界面,右键–清除消息日志,然后重复上述操作,也可间隔数个格 子单击,以此计算每个格子的平均值,作为每个格子的宽和高度值。格子的宽度为16 ,格子的高度为16 。
(6)自动游戏获胜功能3——根据雷区存储数据自动游戏
1)创建控制台项目;
2)打开扫雷进程,根据雷区的行和列所在内存地址,获取行、列的值;
3)根据雷区首地址和雷区范围,读取雷区数据;
4)将扫雷游戏界面置顶,读取雷区第i行第j列的数值,判断是否为地雷,如果不是则模拟鼠标左键单击操作,如果是地雷则模拟鼠标右键单击操作。
5)根据扫雷游戏界面的客户坐标系,计算第i行第j列的坐标位置,然后将鼠标移动到该位置,执行第3步的鼠标操作。
6)重复 3-4,直至雷区数据全部被扫描完成。
程序源码以及可执行文件见附录
# 2. 使用手册
(1)显示游戏运行时基础信息(地图大小、地雷总数等)——输入1
修改地图信息后重新查看基础信息
游戏运行后重新查看游戏运行时基础信息
(2)计时器停止——输入2
(3)点到雷不会结束游戏——输入3
(4)自动游戏获胜功能——输入4
(5)退出程序——输入5
# 3.代码附录
|
|