吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5626|回复: 112
上一主题 下一主题
收起左侧

[原创] 破解初体验:尝试破解微软经典扫雷小游戏,实现一秒通关

  [复制链接]
跳转到指定楼层
楼主
tzbuneasy 发表于 2025-3-9 16:44 回帖奖励
最近开始正经学破解了,应老师要求,尝试破解微软经典的扫雷小游戏,实现一秒内通关。实验环境是win11,以及od

要实现软件的破解,我认为先得玩一下看看大致思路:


显然是一个非常典型的Windows窗口程序,点击小方格就可以开始扫雷并且计时了,要在 一秒 之内扫完所有雷我猜可以选择冻结时间,但似乎非常不妥,另一种方法应该是在点击之后快速将所有没有雷的地方触发,这样应该更符合要求

使用OllyDbg打开程序看看,根据吾爱破解论坛的前人文章的指点,所有Win操作系统上的窗口程序最开始都会给自己注册一个窗口类,根据注册窗口类(RegisterClassW),以此为切入点想必会很快找到窗口运行代码核心。
微软提供了该函数的一些信息,按图索骥,我们得到了其数据结构。



注册窗口需要一个包含窗口类属性的结构体,而该结构体的第二位WNDPROC即是该回调函数的指针,处理的结构体就在里面,使用OD进入。
先得到注册窗口函数的地址,但发现出了一点问题。

似乎是不在该程序领空,不知道该怎么办了,遂直接根据前人经历直接找到了函数所在位置。

下断点,运行:



能看见堆栈区域的lpwndClass的地址,右键在数据窗口跟随就能看见WNDCLASSW的具体内容,其中4-8字节就是窗口回调函数的指针,选择在反汇编窗口跟随。

一路向下执行,发现到达了DefwindowsProc函数处,查询发现这是应用程序未处理任何输入时进入的函数,说明主处理函数就在上面。

向上查询果然能发现一大堆swich case表,以及VM_LBUTTON等字样,应该是主处理函数没错,根据我最初的思路,在左键点击时触发所有非炸弹区域,所以前往左键处理处查看逻辑。大概是这么一团。


最开始两句是switch的判断部分,无需在意。看了半天发现不大对,游戏在执行过程中是在左键抬起来的时候才真正执行了点击这一过程,不然就是这个样子,按下去但没起来,所以到VM_LBUTTONUP处寻找函数

能看见在[01005140]处数据与edi(此时为0)比较后判定是否跳进010021A9(Def函数),即在1005140这里的全局变量如果为零0就不管了,我猜测是判断是否抬起的一个标志位,此时不会是游戏胜负判定,抬起在不论胜负的时候还要处理别的事。随后是一个释放鼠标的一个API调用。随后的test和je我开始认为应该是判断Release的返回值是否正确,但想了一下ebx似乎是保留的寄存器,bl应该不会发生函数里面的变化,所以我猜测其是判定105000的某一个位是否为零用的如果为零,就会从je跳转走,可能是某个判断游戏胜利或者失败的部分。
最后的010037E1应该是核心代码。

在游戏中有一个比较经典的就是递归展开,就是当点击处附近没有雷时递归展开周围的未解开的格子从这方面,很容易能想到一种破解方式就是解除递归展开的限制,一次性把所有没有雷的格子全部展开,似乎是最好的一个方式。不过先回到这段代码上。

始这段代码基本上都跳往了函数末尾,比较的还多是数据区的一些东西,多半是一些对常量设置检查,可以掠过。
随后是一个看着十分重要的函数调用:SetTimer,

显然就是函数随意点击某个节点后才开始的计时器部分,随后是对返回值的处理,盲猜点击处理函数就在下面不远。仔细一看发现直到函数末尾基本上都是短跳转,只有两个除外:

先进010035B7看看:


双层循环,我猜十有八九跟要找的递归展开有关,往上翻翻,可以找到一个关键点,eax * 32(shl eax , 5),根据前人的经验,这个游戏把地图分成了32*32大小的一块块地图,此时左移五位显然是为了计算某个点的下标(行 + 列 * 32,或者反过来),汇编层面应该是没有所谓的双层数组可以绕过这种叠加法的大概(

此时可以确定eax是行或者列,反正是方形地图,大抵无所谓

显然esi就是对应的列或者行,下面对40h的与应该是检查某个标记位的,暂且不明,似乎为零了就直接跳到结尾了,暂时猜测为已经解开或者是雷的标记位,循环的判定如下,看着像把里面所有点都遍历一遍,edi每次加一,esi每一加一排,也就是32,而ebx作为单纯的判定限度作用,只加了1。


看循环体,一眼就能看见只有两个长跳转:先进01002EAB看看。一进来就是注册表的什么东西,下面全是pushcall,都是push一些常量,然后调用同一个函数,连格子的坐标都没看出来用,应该是来错了,先去另一个看看。下面是另一个:

pushcall一大堆,但是看见了ediesi,怎么也说明多半跟坐标相关,稍微看看数据构成,发现push的参数不是一些不明所以的常数而是一些非常固定的寄存器:

从上而下输入的参数分别是(esi,edi – 1),(esi,edi),(esi,edi + 1),(esi + 1,edi – 1),(esi + 1,edi+ 1),(esi + 2,edi – 1)(esi + 2,edi)(esi + 2,edi + 1).这八个下标完全是连在一起的八个格子,加上上面调用的一次,就构成了一个点和它周围的八个点。


显然,这01003008里面藏着这个游戏的核心,这上面说到的逻辑完全符合点击一个格子并揭开后根据情况(如果没有雷在周围,即不需要打印数字,开始递归)查看并且揭开周围八个格子情况的逻辑。有相当大把握01003008里的就是揭开格子和计算周围雷数的核心代吗。

一进01003008,就看见几个非常熟悉的操作,使用shl和add计算下标,再把下标对应的数取出来做后续判断。所有揭开格子的操作都会经过这一步,可谓是元操作了,直接在函数开头下断点,开始调试。

随便点了一个格子,刚好触发递归展开,能看见周围格子从上至下,从左至右一个一个的被揭开。
说明没找错地方,再次观察代码结构:

能看见下标对应的数值给了eax,随后比较判定也是针对eax,下标地址构成为esi + 1005340,这个1005340应该就是存储格子状态的地区基址,在数据窗口查找z:

能看见批量的0F围着一个似乎是方形的场地,前面提到,计算基址的行列计算会乘32,此处竖向排列的10也是隔一排出现一次(一排16个字符)似乎是作为边界存在,仔细观察就能发现一些异常的节点:3 * 3的由4开头的数组成的方形,以及稀少的8F,我猜这个4开头的就是解开的格子,与扫雷界面对照:

显然,4开头的就是被揭开的格子,后八位是周围地雷数,那8F是什么呢,点一下炸了,应该是炸弹的意思。综上,可以得知高八位的第一位是炸弹,第二位是被揭开。 低八位是F表是未被揭开,其他的表示周围雷数,应该是如此。观察下面的几个跳转:

显然就是判断是否已经被揭开(40),是否是墙(10),是否是旗子(0E,这是我猜的,随后进入揭开流程


这里进去发现是查看周围雷数的,返回如果是有雷就跳过,即进入下一个循环,我尝试在这里改一下,让就算是雷也照常进入递归揭开流程
发现把雷也揭开了,真是抽象,所以在上面再另作修改

最后在此处把对旗子的判定改成了对雷的判定,如果是雷自动跳过揭开流程,但周围有雷,继续揭开流程








image.png (81.13 KB, 下载次数: 0)

image.png

image.png (90.52 KB, 下载次数: 0)

image.png

免费评分

参与人数 42威望 +1 吾爱币 +46 热心值 +34 收起 理由
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Yonghang + 1 + 1 我很赞同!
太极打柔道 + 1 + 1 我很赞同!
weibai973 + 1 热心回复!
QYD + 1 我很赞同!
suunuian + 1 谢谢@Thanks!
lbs7666667 + 1 + 1 我很赞同!
sc162550 + 1 + 1 我很赞同!
yahuodan + 1 我很赞同!
sophist + 1 用心讨论,共获提升!
weizhi151 + 1 + 1 谢谢@Thanks!
温馨提示 + 1 + 1 热心回复!
一只梦蝶 + 1 + 1 用心讨论,共获提升!
hyw9527 + 1 热心回复!
ihengli + 1 + 1 我很赞同!
lerCHEN + 1 用心讨论,共获提升!
ilalcl + 1 + 1 我很赞同!
frank369 + 1 我很赞同!
clin27 + 1 膜拜!!
kitalry + 1 + 1 谢谢@Thanks!
coolilio + 1 + 1 好厉害!但是手动扫雷才能让我的摸鱼时间变得更快哈哈哈!
Ardon20071208 + 1 我很赞同!
52ong + 1 我很赞同!
chuling01 + 1 我很赞同!
CherMiku + 1 + 1 我很赞同!
tomolin + 1 我很赞同!
239257 + 1 我很赞同!
yp17792351859 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
complex + 1 谢谢@Thanks!
MarkChan + 1 谢谢@Thanks!
Ylvan + 1 + 1 热心回复!
foxfoxfoxfox + 1 我很赞同!
Shuery + 1 用心讨论,共获提升!
gugouo163 + 1 用心讨论,共获提升!
1595901624 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
mrjian + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
AZ2020 + 1 用心讨论,共获提升!
gqdsc + 1 + 1 谢谢@Thanks!
xuezhang18 + 1 谢谢@Thanks!
hoon + 1 谢谢@Thanks!
anning666 + 1 + 1 我很赞同!
liyitong + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
shuijingkoubei 发表于 2025-3-10 00:21
真是佩服你们这些代码大神,我看图片上的几张代码图,我脑袋嗡嗡的,眼前直迷糊。向你们致敬,有你们的坚持不懈,才有我们香甜丝滑的应用。感谢你们
推荐
 楼主| tzbuneasy 发表于 2025-3-9 16:49 |楼主
图片怎么多了几张,不要在意

免费评分

参与人数 1吾爱币 +1 收起 理由
liyitong + 1 上传了的图片未在正文中使用,就会在末尾显示一下。

查看全部评分

推荐
 楼主| tzbuneasy 发表于 2025-3-11 02:09 |楼主
abcxyzmn 发表于 2025-3-10 11:51
不太明白最后结果。

曾经,扫雷成绩:初级3秒;中级10几秒;高级70多秒,有记录的是81秒。xp里面的

厉害厉害,我可能最后写的不大清楚,就是在最后判定的地方会先后对是否已经被揭开,是否是墙壁(边界)和是否是右键插的旗子做判定,但凡满足一个,就跳转到函数末尾不做处理,原来的更改是去掉后续对地雷的审查(因为周围有地雷也会停止递归,使当前的格子被揭开并且打印数字上去),但是这样所有格子,包括地雷格子都会因为递归不终止而被强制揭开,搞得赢不了也输不了。把前面三个审查中的旗子判定(就当不用旗子了)改为对地雷的判定,这样递归不会终止,但是会绕过地雷格子
4#
SherlockProel 发表于 2025-3-9 22:17
不明觉厉,一键三连
5#
52pj朱朱 发表于 2025-3-9 22:21
厉害  真的厉害
6#
skm415889471109 发表于 2025-3-10 04:36
学习了,感谢分享
7#
jieyang0663 发表于 2025-3-10 06:33
这值得点赞,但我还是喜欢手动按扫雷的感觉,哈哈
8#
unizhang 发表于 2025-3-10 08:16
这这这。。。我摸鱼的乐趣又少了一个
9#
ilpj 发表于 2025-3-10 08:40
厉害了,啥时我也有这水平?
10#
anning666 发表于 2025-3-10 08:44
适合我这样的小白学习,tks
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-3-25 08:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表