1. 介绍
偶然见看到了好久以前存的想要复现的扫雷教程,突然发现已经过去那么久了啊。刚好趁着最近有时间,上手AK一波,让我也来感受下当初那些大佬们屠榜的快乐!!!
哦,对了。前提声明,本文的所有脚本都是建立在大佬的基础上来的,因为我太菜了。。。
2. 时间修改实现
2.1 时间清零实现
扫雷这个游戏大家都很熟悉了,就是根据出现的数字来判断周围的雷点,然后标注出来,给它插上咱的小红旗。
先上OD,把我们的扫雷跑起来
接下来,我们要做的就是定位到存储时间的基址。CE大法好啊
初始未开始状态为0,搜索0这个数值,结果很多,不过不要慌。
因为我们一旦点了开始,那么扫雷的秒数就会不断+1,这样很不利于我们分析。不过,我们自有对策,我们可以直接把游戏打输啊,直接点到雷爆掉,时间不就可以停止了吗?(机智如我.jpg)
嗯哼,点爆了,变成了4秒
上CE修改数值,再次扫描
这次可以看到结果少了很多,有5个固定基址有可能是我们存储时间的地方。
现在结果依旧不确定,但是我们可以重复上述操作啊,重置游戏,继续搜索嘛。
当我们数值清0的时候,可以一眼看出,这里的数值进行了改变,所以我们的结果就是它了~~~
为了确定这个地址的正确性,我们直接修改下它的数值来看下
嗯~~~ 很好,就是它了。
既然找到了这个地方,那我们要做的就很简单了,让它的数值清0就完事了?不过真的会这么简单吗?
当然不会啦~~~
因为扫雷的时间是累加的,所以我们要想让它的数值彻底清0,还需要修改它的逻辑。不过在这小节里我们暂时不讨论这个,我们只单纯的修改时间。
当然,每次修改时间还要开CE好麻烦的说,所以,我们这里可以搞个脚本啊。
1 |
|
欸嘿,脚本一跑,时间清0。(这里的1是因为又开始计数了,我截图肯定截不了这么快的)
2.2 时间停止实现
上面我们也说了啊,让时间清0并不能让我们完成屠榜!!!的壮举,所以我们需要修改它的计时逻辑来完成这一伟大的目标。
当然,首先还是要掏出我们万能的OD,然后在数据窗口中定位到我们在上面用CE获取到的地址0100579C
(PS:做出OD和IDA的人真是神仙啊,CE更是早些年不可割舍的回忆呢。)
可以看到,我们的时间在随着扫雷中时间的跳动而改变。
既然已经确定了地址了,后面的就简单很多了啊。直接对我们这个地址下一个写入断点
断点下完后,发现我们的程序断在了0x01002FF5
这个地址处。而且可以看到这行代码的意思是让0x0100579C
地址处的数值累加1,所以不用看了,就是它了。(当然,不放心也可以在点两下运行,分析分析。看看是不是运行完这行代码后,扫雷时间数值+1)
那么接下来我们要做的就是将这行代码nop掉。这里我们可以直接借助OD来进行操作,但是我今天不想这么干,大佬的脚本实在是太让我心动了。所以我要 上!脚!!本!!!
1 |
|
欸嘿,脚本跑完后,OD中看到的这行累加代码果然被nop掉了,舒服啊~~~
而且可以看到,我们的时间也不增加了欸
让我们先将我们上一步的修改结果保存下来。
但是!!!在我们运行保存下来的程序时,我们发现时间会加1,这说明扫雷程序并不是完全通过我们nop掉的那行代码实现时间累加的。
看来我们需要掏出我们的OD在给它点教训了!
将修改后的扫雷程序载入OD,继续在0100579C
处下一个内存访问断点,然后运行
在游戏中点击任意一个小方块,然后!!!我们又发现了一处对时间+1的操作
运行跑起来测试后得知,这行代码就是我们要找的地方。把它nop掉即可实现0s扫雷
哦,对了。这里也可以用脚本,直接把上面的脚本修改一下,添个地址就好。改后的脚本就不放了,大佬博客里有。
总结一下,扫雷里一共有两处对时间进行+1的操作。一处是在我们第一次点击的时候,另外一处是程序跑起来之后,所以我们修改的话两处都要修改才可以。这也从侧面反映出了,为什么当初榜上会有一堆1s的大佬,emmmmm,仿佛明白了什么呢(滑稽.jpg)
3. 一键扫雷实现
3.1 自动标注地雷分布
下面我们继续上面的过程来分析。这里我们还拿原版的扫雷程序,因为里面有很多下好的断点,方便些。
这里载入OD后,我们直接一路F8,让程序跑起来。随意选中一个方格点击(这里随意算了2行3列)
程序成功断在了方格中显示出字符之前,我们继续往下分析
这两行分别将我们鼠标点击的列和行
赋值给了寄存器,可以通过不断变换点击位置确定
继续往下运行,我们发现了一处很有意思的代码
这块代码的作用,就是将我们鼠标点击位置的状态存入数据段中。因为由前面可知,EAX和ECX
是取了我们鼠标点击的位置,这里将ECX赋值给了EDX,然后循环左移5位。接着以0x1005340
为基址进行了偏移,由此可见,0x1005340
就是我们存放雷区表的地址。
往下运行至0x10038B1
处后,雷区中成功显示出了字符,在数据窗口中,我们也成功看到了我们所存放的数值
另外,网上翻下数据窗口的数据,还可以看到很有意思的数据
看到这三个数据是不是很意外呢,0xA,一共10个雷,9×9的方格,是不是和我们的初级扫雷一样呢。
更改扫雷模式也可以看到,这三个数据在不断改变,可以确定这三个数据就是扫雷的长宽和雷数。
反复测试,仔细观察数据窗口的雷区数据,其实可以得到很多东西。比如10
是边框,0F
是未开启的方格,8F
是雷,8E
是插得棋子,然后我们可以提取出我们的雷区数据(因为反复调试了很多次,所以这里就用以前提出来的一个数据啦,还请见谅)
这样就可以很方便的看出来,里面9×9的数据。
但是!!!到了这里还有一个很重要的问题,我们的雷区初始化有两种情况。一种是在我们打开游戏后,雷区自动被初始化,此时雷区位置是一种情况。但是,当我们对雷区中任一方格点击的时候,我们的雷区会再一次被初始化,生成新的雷区,这时的雷区才是真正的雷区。
那么问题来了,我们该怎样获得最后的雷区来进行标记呢?这里其实取巧了的,因为如果我们不点击方块,那么雷区就不会被再次初始化,所以我们可以直接标注出所有的雷,给它插上小旗子。
那么,这里我们再次借助大佬的脚本。(哦,对了。这里要说明下,大佬原文的脚本是C++的。我这里是用的C,在VC6.0编译器里,C对字符的定义需要放在main函数开头,不能什么时候用什么时候定义。但是C++貌似要求不严格,可以这么做)
1 |
|
当当当,一共10个雷全被标出来了
但是这里我们的游戏还没有获胜,因为我们只是单纯的将雷标注了出来,还需要将所有的空白全部点开才会判定Winning the game。所以,我们后续的工作还没有结束啊。
3.2 一键扫雷Get
书接上回,我们暂时只是实现了我们对扫雷游戏中雷的标注,才插上了棋子。但是这并不足以判定我们的游戏胜利,我们还需要把所有未点开的方格点开。当然,如果不嫌麻烦,这一步也可以人工实现。但是嘛,我们的目的当然不只是这样,我们需要脚本来完成所有操作。
这一块的关键点在于我们鼠标按下
和抬起
这两步操作,还有就是我们的坐标
如何确定。关于这点,我就决定不在详细介绍了,分析完后不想写步骤了呢,去看大佬的吧。大佬的写的很详细,我只是单纯的记录下自己的复现流程。
1 |
|
当当,运行脚本,游戏结束。
4. 最终脚本
1 |
|
5. 参考链接
1 | 扫雷辅助的研究 |
发布时间: 2022-01-28
最后更新: 2023-02-12
本文标题: 扫雷辅助
本文链接: https://foxcookie.github.io/2022/01/28/扫雷辅助/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!