软件逆向之扫雷(二):破解雷区
目录
问题导入
上一节中我们通过修改注册表修改了扫雷英雄榜,自行改动了榜上的昵称和时间。然而这只是表面工作,没有解决扫雷游戏的本质:找出所有雷区。这一节我们分析雷区的存储方式和位置,人工破解雷区。
雷区分析
扫雷的界面是一个n*m的矩形雷区,每个小方块代表一个位置,和矩阵十分类似。因此我们猜想是通过二维矩阵来存储数据,将矩阵中特定位置标记为雷区,而每次点击非雷区时会出现数字,即计算点击位置周边八个块的地雷数目,然后显示在块上。
将矩阵转化成扫雷的界面则需要调用几个API函数,比较常用的就是BitBlt函数。BitBlt将某一内存块的数据传送到另一内存块,前一内存块被称为”源”,后一内存块被称为”目标”。使用该函数我们可以将矩阵进行变换,从而显示出来。
逆向分析
使用OllyDBG打开扫雷程序winmine.exe,查看调用的API函数。
可以看到从GDI32.dll导入的函数很多与作图有关,如SetLayout、CreatePen等。我们选中BitBlt函数,在每个参考上设置断点,然后运行至断点处。
第一个断点处,整个扫雷界面都未加载完成,而且我们也没有进行点击,故不是所需代码块,取消该出断点,继续运行。
图像界面显示出来,程序停止了运行,表示程序还未运行到第二个断点,可能在等待用户点击鼠标。我们选择雷区任意一个位置点击,程序运行到第二个断点处停止。
函数中刚好有两条类似的寻址语句。[edx+eax+01005340h]和[edx*4+105A20]。第一条是mov操作,并且更符合二维数组寻址,因此我们猜测01005340h是数组基址。
在左下角数据窗口使用ctrl+G,输入01005340h,跳转到该位置。查看数据窗口内容。
数据窗口一开始全是10,有33个。由于我们使用的是高级模式,扫雷界面是16*32,初步猜测10代表边界。然后是大量0F和少量8F。前七个数据是六个0F和一个8F,那我们点击扫雷第一排前七个格子。前七个均没有雷,第八个是雷。
查看数据区内容是否发生变化:
前五个格子为空,数据由0F变为40;第六个格子是数字1,数据由0F变为41。同时数字2、3对应数据也分别变为42、43。得出结论:未点开非雷区数据为0F,点开的非雷区数字x的数据为4x。
第七个格子是我们点中的雷,数据由8F变为CC;而第八个格子我们未点中的雷由8F变为8A。得出结论:原数据8F即表示该位置是雷。
除此之外,扫雷还有两个符号,旗子和问号,现在我们再次尝试,分别在雷区和非雷区标上旗子和问号,查看数据。
标上旗子,雷区数据由8F变成8E,非雷区数据由0F变成0E;标上问号,雷区数据由8F变成8D,非雷区数据由0F变成0D。由此可得雷区最高位为1,不论是8(1000)还是C(1010),最高位都是1;非雷区最高位为0。
由以上情况作出总结:
雷区(最高位为1):
1.未点开为8F
2.点开为CC,其他为8A
3.标上旗子为8E
4.标上问号为8D
非雷区(最高位为0):
1.未点开为0F
2.点开为4x(x代表格子显示数字)
3.标上旗子为0E
4.标上问号为0D
当然我们也可以人为修改数据达到各种效果,如初始化是雷区却不爆雷等。