软件逆向基础-扫雷篇
软件逆向分析
3.1完成针对扫雷游戏的逆向复现报告
- 分析“初级”、“中级”和“高级”的棋盘内存地址范围;
①扫描类型 选择 “未知的初始值”,点击初级棋盘上第一格,进行“首次扫描”
图3.1 初次扫描
②第一格显示为空,我们继续查看下一次扫描第一格格子是否有数字
图3.2 二次扫描
③点击第一格,又是空白,故扫描类型选择“未变动的数值”-->“再次扫描
图3.3 三次扫描
与上一次不同,因此我们扫描类型选择“变动的数值”-->“再次扫描”
重复进行以上操作,直到出现基址,我们把这个地址保存下来,右键点击该地址,选择“浏览相关内存区域”或者选择雷数右击浏览。
图3.4 多次扫描
④开始扫雷,发现点击时内存区域变红,以此判断棋盘内存地址范围
图3.5 初级棋盘扫描
⑤初级棋盘内存区域:点击第一行第一列,观察红色区域,确定起始地址(0100535E)。点击最后一行最后一列,观察红色区域,确定结束地址(01005469)。
图3.6 中级棋盘扫描
⑥中级棋盘内存区域:点击第一行第一列,观察红色区域,确定起始地址(0100535E)。点击最后一行最后一列,观察红色区域,确定结束地址(01005550)。
⑦高级棋盘内存区域:点击第一行第一列,观察红色区域,确定起始地址(0100535E)。点击最后一行最后一列,观察红色区域,确定结束地址(0100555E)。
图3.7 高级棋盘扫描
图3.8 高级棋盘扫描
⑧最终结果为
初级棋盘: 0100535E-01005469
中级棋盘: 0100535E-01005550
高级棋盘: 0100535E-0100555E
- 找出“雷数”、“笑脸”和“计时器”的内存地址;
①首先,将游戏难度设置为“初级”可见此时雷数为“10”,使用CE扫描类型“精确数值”输入10,进行“首次扫描”。
②再将游戏难度设为“中级”,此时可见雷的数量变为了“40”。
③然后我们再将游戏难度设置为“高级”,此时雷数为“99”,我们查找99,进行再次扫描
图3.9 查看雷数
图3.10 查看雷数
图3.11 查看雷数
图3.12 寻找笑脸
图3.13 寻找笑脸
④最终可以判断出010056A4为雷数的内存地址,因为当踩到雷时,这个地址会变成2,没有踩雷,数值是0,可以初步判断,这个就是笑脸对应的内存地址。
图3.14 踩雷
图3.15 未踩雷
计时器
①计数器的时间是一个具体的值,所以可以通过精确数值扫描出来
图3.16 计时器查询
②这里我们进行确定,每一次计时器从零开始,地址后面的数值都会随之改变,由此,我们确定这是计时器的内存地址。
图3.17 查询成功
图3.18 确认成功
- 分析地雷存放的算法;
①在游戏开始阶段,并不立即调用地雷布置函数。直到玩家首次点击棋盘上的任意格子时,才会触发地雷布置的过程。
②使用随机数生成器来决定地雷的具体位置。一种有效的策略是从玩家首次点击的格子开始,避免在该格子及其周围直接放置地雷。然后,对于剩余的格子,随机选取位置放置地雷,直到达到预定的地雷总数为止。为保证随机性,可以采用Fisher-Yates洗牌算法来实现地雷位置的均匀分布。
③计算邻近地雷数量 (CalculateAdjacentMineCounts):对于非地雷格子,计算其周围八个方向上存在的地雷数量。这一步骤可以通过遍历每个格子,并检查其邻居(如果存在的话)来完成。为了避免边界条件导致的错误访问,应首先检查待访问的邻居是否位于有效范围内。计算结果存储在一个独立的二维数组中,以便快速访问。
④当用户点击某个格子时,首先检查该格子的状态。如果该格子是地雷,则游戏结束。如果该格子为空,则展示该格子周围地雷的数量。对于显示为空(即周围没有地雷)的格子,应该递归地展开其相邻的所有空格子,直到遇到含有地雷数的格子为止。这种方法称为“级联展开”,有助于加快游戏进程。
⑤在处理用户点击及计算相邻地雷数量时,特别注意边界格子的处理。例如,位于角落或边缘的格子可能只有少于八个邻居。为此,可以预先定义一个辅助函数来判断给定坐标是否位于合法范围内,从而防止访问无效索引。
- 利用思维导图分析“ 扫 雷 ” 游戏软件的工作原理 ( 设计原理)。
图3.19 思维导图
图3.20 结构