首页 > 其他分享 >re | buuctf逆向刷题之Ultimate MineSweeper全分析

re | buuctf逆向刷题之Ultimate MineSweeper全分析

时间:2023-06-07 11:03:36浏览次数:50  
标签:buuctf false 函数 MineSweeper 程序 MinesPresent re set 雷区

写在前头

最近在buuctf上刷逆向题,做到Ultimate MineSweeper,这是一道用.NET写的扫雷题,题目不难,有类名和函数名符号,分析起来很容易,耐心一点都能找到flag,但是我还是对这个题目很感兴趣,毕竟每个逆向爱好者都有一颗破解扫雷的心,所以我还是认真的把整个程序都逆了一遍,再加上目前在网上看到的解法都需要patch程序,所以我写了这篇笔记,展示了一种不需要修改任何程序的解法

观察程序

经典扫雷游戏,鼠标左右键控制,点到雷就炸

修改程序的解法

.NET程序,那就用reflector打开看看,一通点点点,找到一个可疑的GetKey方法,取了三个revealedCells进行处理获得buffer数组,再用buffer同bytes数组逐字节异或,返回ascii编码,很像啊

找到调用函数SquareRevealedCallback,是翻完方格的回调函数,大概意思是,如果翻到雷了,停止游戏,弹出failurepopup失败框,如果所有非雷区都被翻开,则弹出successpopup成功框,并且将上面生成的flag显示到框中

也就是说,只要游戏通关了,程序就会把flag打印出来,网上有无敌挂和透视挂两种做法
无敌挂,把弹出失败框的那部分代码删掉,点到雷游戏也不会退出,然后就无脑暴力点雷,将所有框都点一遍,游戏就赢了,弹出flag

透视挂,首先看一下进入赢分支的判断函数TotalUnrevealedEmptySquares,这个MinesVisible看起来像是表示可见区域的

查看该数组set方法的引用,发现在MineField初始化时,被全部置为了false,也就是不可见,那么如果在这里改为全部置true,变成全部可见,就可实现透视

透视挂效果

程序完整分析

不管是无敌挂还是透视挂,都是破坏了程序本身的逻辑,不讲武德的实现通关。但显然程序是有一套判断雷区的规则的,更具体点,应该是有一个数据结构用来存储雷区,如果能够通过动态调试的方法将这个数据结构给打印出来,那就可以直接拿到通关答案。因为题目比较有意思,所以我把整个程序逆了一遍,顺便找一下这个数据结构
首先,分析这六个最主要的类

SuccessPopup和FailurePopup,表示成功框和失败框的类
MineFiled用来表示方块区域的类,里面的MinesFlag、MinesVisible和MinesPresent,以及set\get方法,猜测是用来表示插上红旗区域、区域可见性和不知道啥的

MineFiledControl定义了用户操作的回调方法,里面最重要的是MouseClick这个方法,获取用户点击方块坐标,判断左右键,改变MineFlagged和MinesVisible这些状态变量,其中点击左键后调用了SquareRevealed,最终调用了上面的SquareRevealedCallback,进入是否点中雷区的判断

再看一下这个初始化函数,初始化了一个imageList,0->未翻面,1->炸弹,2->隐藏,3->插旗,4->安全

再看一下这个paint函数,每次点击以后回调,根据MinesVisible等状态变量重新绘制游戏区域,结合上面imageList编号对应的含义,现在可以确定,MinesVisible用来表示哪些区域可见,MinesFlagged表示哪些区域被插旗,MinesPresent用来表示哪些区域有雷,嗯这个MinesPresent要重点关注

MainForm这个类用来实例化MinesFiled和MinesFiledControl类,在其构造函数里注册了一些回调函数,游戏的主要交互逻辑都在里面

Program类,程序的主函数入口类,实例化了MainForm类

到这里,基本上把程序主要逻辑分析了一遍

不用修改程序的解法

已经确认MinesPresent就是用来表示哪些地方是雷区的结构,现在只要把MinesPresent取出来,就可以得到答案

MinesPresent在MinesFiled类初始化时被全部置为了false,那应该是在后续步骤中被重新赋值,通过静态分析交叉引用,没有发现别的地方调用了MinesPresent的set方法,虽然还不清楚具体是哪里赋的值,但是我们可以通过动调,找到一个确认已经赋值了的地方,把MinesPresent取出来,好,那就打开我的dnSpy

可以确定的是,在第一次点击方块前,MinesPresent已经被赋了值(否则无法判断是否点中雷区),所以我选择了FirstClickCallback函数,因为其位于MainForm类中,可以直接获取到MinesField变量的值,在这里下断点,程序跑起来,随便右击一个方块,程序断了下来,可以看到MinesPresent已经被赋了值

将这几列复制到excel表格,重新排列下,bingo,找到了总共三个非雷区,答案get

MinesPresent到底在哪赋的值

到这里就结束了吗?怎么可能,前面还留有一个疑问,没有找到MinesPresent被赋值的地方,那现在就来跟踪一下

由于没有找到其他对set方法的引用,那只能是通过其他方法对其赋值了,静态分析的思路到这里就断了

既然程序不长,那就从程序开始,一步步调试呗,观察啥时候MinesPresent的值发生变化了

前面说到,MineFiled初始化时对MinesPresent全置false,那我们从初始化后进行观察,首先是AllocateMemory函数,下个断点


可以看到,在调用该函数后,MinesPresent就被赋值了,第一把就找到了...

那点进去看看干了啥,num2是横坐标,num是纵坐标,对整个游戏区域进行了遍历,根据那个if条件判断是否置false

GarbageCollect函数,别被它善良的名字欺骗了,它的set方法才是我们一直找的真正赋值的地方,MinesPresent的set方法只是用来给个初值

看看它怎么判断的,DeriveVallocType函数如下,就是根据横纵坐标进行运算,判断是否等于某常量,是就置false

涉及到的常量

最后循环下来,只有[7,20]、[24,28]、[28,7]这三个地方被置了false,也就是游戏中被设置为无雷的只有这三处

收工

标签:buuctf,false,函数,MineSweeper,程序,MinesPresent,re,set,雷区
From: https://www.cnblogs.com/z5onk0/p/17462714.html

相关文章

  • 【HMS Core】Health Kit查询历史数据查询数据和返回数据不一致
    【问题描述】查询一个月运动记录,只能查询到最早5月26的数据,但是华为健康app里的数据最早为5月8日,为什么会查询不到? 【解决方案】1、需要检查是否申请了历史数据权限,查询数据时,出于对用户的数据保护,只允许开发者查询在用户授权之后的数据。例如用户是在2022年2月14日授权,那么2......
  • .net core WebAPI 初探及连接MySQL
    1.前言笔者最近跟着微软官方文档学习.netcoreWebAPI,但发现其对WebAPI连接数据库、读取数据库方面讲得不够细致明了。写此文的目的,即实现.netcoreWebAPI的GET、POST方法访问数据库,并输出结果。2.开发准备2.1操作系统Windows10/Windows72.2.netcoresdk.netcore......
  • 详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿
    说起异步,Thread,Task,async/await,IAsyncResult这些东西肯定是绕不开的,今天就来依次聊聊他们1.线程(Thread)多线程的意义在于一个应用程序中,有多个执行部分可以同时执行;对于比较耗时的操作(例如io,数据库操作),或者等待响应(如WCF通信)的操作,可以单独开启后台线程来执行,这样主线程就不会......
  • IO流 p9 转换流-InputStreamReader 和 OutputStreamWriter
    转换流-InputStreamReader和OutputStreamWriter介绍InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成Reader(字符流);OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流);当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文......
  • 通过redis学网络(1)-用go基于epoll实现最简单网络通信框架
    本系列主要是为了对redis的网络模型进行学习,我会用golang实现一个reactor网络模型,并实现对redis协议的解析。系列源码已经上传githubhttps://github.com/HobbyBear/tinyredis/tree/chapter1redis的网络模型是基于epoll实现的,所以这一节让我们先基于epoll,实现一个最简单的服......
  • Redis实现限流的三种方式
    一、固定窗口所谓固定窗口限流即时间窗口的起始和结束时间是固定的,在固定时间段内允许要求的请求数量访问,超过则拒绝;当固定时间段结束后,再重新开始下一个时间段进行计数。我们可以根据当前的时间,以分钟为时间段,每分钟都生成一个key,用来inc,当达到请求数量就返回一些友好信息。......
  • h5移动端页面调试工具Chii与 weinre 一样的远程调试工具
    与 weinre 一样的远程调试工具,主要是将webinspector替换为最新的 chromedevtoolsfrontend.电脑上跑一个chii服务,把对应的js嵌入h5页面内,用手机访问h5页面,chrome内看chii服务地址即可找到对应管理控制台  安装可以通过npm安装。npminstallchii-g 使用......
  • 一定要看的前端codeReview规范指南
    一、前言针对目录结构、CSS规范、JavaScript规范、Vue规范可参照官方给出的风格指南这里主要总结业务开发中常遇到的代码问题和实践,帮助大家后续各自做好codeReview,一些你遇到的典型问题,也可以在留言区评论,帮助团队共同进步。二、实践规范2.1防止重复提交--表单提交或者编......
  • OverTheWire攻关过程-Natas模块0
    我们来看下Natas模块的介绍机器翻译Natas教授服务器端web安全的基础知识.每个级别的natas都有自己的网站,位于http://natasX.natas.labs.overthewire.org,其中X是级别号。没有SSH登录。要访问某个级别,请输入该级别的用户名(例如,natas0为级别0)及其密码。每个级别都可以访问下一级别的......
  • Redis哨兵模式搭建
    ##一:哨兵主要作用监控:监控redis主库及从库运行状态;通知:如果redis发生故障转移,可以通过邮件通知管理员;自动故障转移:一旦发现主库宕机,则在从库中通过选举新的master进行故障转移。##二:工作原理哨兵(sentinel)是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel)进程,......