[CTF]Bugku Take the maze

[CTF]Bugku Take the maze 200

{写博客不重要,记录思路最重要}

1. 拿到拖Die发现无壳,从文件名和解析结果来看就是用visual C写的

2. 运行,发现关键语句:“show me your key”,拖入IDA,搜索该字句,进入到函数

3. 发现该函数中有“done!....”表明输入正确,但是正确之后还有一些函数,进去后发现还有一些奇奇怪怪的东西如下:

   根据提示,运行到此处会打印一个png文件,所以我们要让程序跑到这里

4. 拖入Ollydbg,开始运行,在输入处(搜索关键字句,很明显的%s后面是输入函数)设置断点,输入任意字符串后步进来到如下处:

   这里和0x18进行比较,从代码中可以分析到这里是比较输入串的长度是否为0x18,不想分析也没关系,直接把寄存器的标志位改掉就可以骗过去

5. 然后来到这里:

  观察这几个跳转的目的地发现,jge的跳转正好跳到done附近,于是我们在jge处将标志位改掉(具体改什么标志位可以查询一下汇编手册)使其跳转到如下位置:

  这样一来,我们的输入就“对”了。虽然开了挂。

  运行程序,得到一个二维码,上面却写着:Congratulations! The flag is your input + "Docupa"

  得到了一个提示,看来我们还是要找到正确的input

6.  回到IDA,F5,报错(忘截图了,该图是网上找的):

  是堆栈的问题,手动调试sp太麻烦,在Options -> General 中勾选Stack Pointer,然后来到报错的位置,  发现SP值有负数,这是不允许的,于是我们在负值前的最后一条语句处按Alt + K然后将其SP值改为左侧显示的应有的SP值,这时后面的负数就会变成0,按D再按C更新函数后如下:

  只要没有负值就没有关系,虽然这样栈基本上还是乱的。但至少绕过了反逆向手段。

7. F5,如下:

其中很明显可以看出sub_45D846是输入函数,输入的结果保存在v4中,随后的sub_45C22F是strlen函数,判断长度是否为24,满足后,将v4的第16位反向后进入sub_45C748函数,暂时还不知道其功能

然后是一个循环,里面有一个判断,如果输入中出现了非法字符,就跳转,而字符的范围是0-9加上a-f

也就是说,正确的input应该为24个字符,经过处理后,是一个具有0-9 a-f的串,很明显,应该是一个16进制串。

如果我们能满足条件,就会进入最后一个if语句,此时,被处理后的v4进入sub_45E593函数,显然应该是一个比较函数,暂不知道其功能,一旦比较成功就获得了flag

8.  我们先来看一下sub_45E393函数,结果又报错:

找到0x463729处,同上修改463727的sp值为0x4即可(修完之后372A还是负数,再修改3729即可):

修完之后如下:

回到刚才的F5代码,进到比较函数中,不再报错,里面代码有些复杂,如下:

  其中发现大量switch匹配式,考虑可能是走迷宫问题

9. 寻找大量switch语句中,找到一个数组:

delru正是down left right up四种走法(e不知道什么用)

而具体怎么走要看v6和v9的值,其中v6来自于第一个匹配,v9来自于第二个匹配,而v9有时根据v6来决定的,这样一来,重点就在于v6,考虑v6可能是迷宫的行走动作:

另外特别注意到这一段,v6的值是如下这样确定的,而该语句中的a2是用户的输入参数,也就是用来比较是否正确的那个user_input_key(经过处理),这种情况下显然v8就是一个指针用于逐个读入字符,也就是说,每一次循环,都会从key中读出2个字符,分别进入第一个匹配和第二个匹配:

 此时我们想到之前看到的那个数组:

如果第一个匹配中v6(来自于每两个字符中的前一个)是0或2或3或4不久正好是dlru吗?那就是说该字符决定方向

如果第二个匹配中v6(来自于每两个字符中的后一个)是5-15,那不刚好就是接着后面的0-9吗?那就是说该字符决定步数

所以,key决定了迷宫的走法,每两个字符一组,前一个决定方向,后一个决定步数

 

10. 接下来要做的就是走出迷宫,迷宫来自于如下四个函数(已改变量名):

v7来自于方向,方向包括dulr,分别对应ascii码为 100,117,108,114,减去一百就是图中的值

所以,对于不同的方向,这里调用了不同的迷宫函数进行操作(这是什么鬼操作.....)

其中,方向为‘d’时的迷宫函数如下,也就是说,如果向下走,就要走这个迷宫?

首先注意到之前的变量some_int在这里给了i的初始值,随后每次i都加上26,可以想象,26是迷宫的宽度(一维数组表示二维数组?)

随后some_int就是迷宫的格子的下标,根据汇编中如下处:

只有在Some_int是311的时候,eax是1,其它时候都是eax为0,也就是说,迷宫成功走出的最后是走到311格(其实是312格)

312=26*11,所以迷宫的长度为11

下面这里11,12,13行是当步数为0的时候,就不用走了,直接回去,然后result是i/26与10比较,这也证明了上面对迷宫的尺寸的推理是正确的,此时如果超出了第10行(其实是第11行),就返回i/26的值(一个比10大的非法行数)

否则,result被赋为当前的下标值并进行了如下异或运算

这就好理解了,如果这个异或运算算出来是1,就直接返回了(可以理解成撞墙了),否则继续循环(继续向下走)

所以这个异或运算就是在画迷宫

同样的,另外三个迷宫函数也有类似的东西,这样我们可以尝试一下画出这个迷宫:

新建一个idc文件,并且写如下代码(idc与C类似,具体语法可自行查手册):

然后在file -> Script file中运行该idc文件,得到如下结果:

值得注意的是,该迷宫不是一个常规迷宫,因为该迷宫图是由四个迷宫撮合而来,向不同方向走的时候要换不同的迷宫来判断是否可以走。该结果的使用方法是从左上(因为一开始i是0)开始,有哪个字母就表示该格可以往哪边走,比如i=0的格子只能往下走,i=1的格子可以往下或者往左走(每四个.或者字母是一个格子,这里特意用空格和换行区分开了格子)

11. 走迷宫(注意,只能是这一种走法,否则题目就错了):

以drul和步数来标识就是:d1 r1 d3 r1 d1 r6 d3 r4 d2 r9 d1 r4

根据前面我们在数组里看到的如下,d-0  r-3  1-6  2-7  3-8  4-9  5-a  6-b  7-c  8-d  9-e

转换成数组下标就是:06 36 08 36 06 3b 08 39 07 3e 06 39

得到我们要的key就是06360836063b0839073e0639

当然,是处理完之后的key,处理之前是什么呢?

12. 来到处理函数,F5进去,如下

这也太恶心了吧.....果断决定动态调试,如下,我输入了全1的字符串

发现在其中某一个函数中被处理成如下:

全2?

全3?

全0?

第1个字符总是不变的,第2个字符1-0 2-3 3-2 0-1,可以看出像是一种异或

第3个字符1-3 2-0 3-1 0-2,也是异或!刚才是异或0x1,现在是异或0x2

第4个字符1-2 2-1 3-0 0-3  异或0x3 !!!

于是我们就找到了正确的解法:

from i in (0,23)

      input[i]^i

input[i] == 06360836063b0839073e0639

于是我们将其异或回来,脚本如下(千万别忘了,在这个加密函数之前还有一句异或哦!):

别忘记了还要加那个二维码里的提示和格式

终于搞定了

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值