分析main函数
首先发现main函数中实现了许多初始化,不难发现里面注册了关于输入输出的exception,然后打开了flag.txt文件,从其中读取数据,然后将数据传给start_check
然后我们考虑进入start_check函数分析,发现其中是个递归函数,对比成果后就向后移动,直到对比了34个字符,下标多余34则出现异常,
然后查看下global_flag明显发现是假的flag,说明这个逻辑是假的,flag.txt中放入这个字符串是错误的逻辑。
我们考虑main函数中注册了一个输入输出的Exception,那么如果在读取文件的过程中出现了异常是否控制流就会发生改变呢。所以我们试着建立一个空的文件,这样就能触发这个异常。由于Exception的代码一般就在函数附近,用cfg窗口查看不难发现可疑的代码。
然后下个断点,发现触发异常后程序执行到了这里,而非原来的start_check,所以就能知道这个main函数真正的逻辑并非f5看到的那样,而是进入到了这个start函数中。
分析start函数
我们接着进入start函数,里面只有一个read
然后进入read发现里面读入了一个字符串,并且作为异常T2的参数抛出了
根据异常的原理,当出现异常时,程序会进行unwind,然后找到能够处理异常的handler,所以这里发现read中没有handler后回到start查找handler。所以应该使用cfg窗口查看,发现果然有可疑代码,正好对应T2的handler
发现就是对strng求了一个长度,然后对每个字符进行了一个make_move的操作,传入参数输入的字符串,到第几个字符,posx和posy。
分析make_move函数
进入make_move函数,发现主要逻辑是一个switch,如果是c就抛出T7的异常,是dlru则抛出T3的异常,是f则抛出T9的异常,这次我们直接在cfg窗口里找handler
不难发现所有的handler都会以___cxa_begin_catch开头,所以我们只需要在所有有这个函数调用的代码块处下断点,然后根据抛出的exception不同获得对应的handler。
T3的操作为调用process_move
T7的异常会调用check_substr
T9的handler会检查一个CHKPOINT的变量,如果到4则会输出flag,否则到exit
所以总结一下就是c代表check_substr,f代表最终的检查,dlru代表着process_move
分析check_substr
发现这个函数先判断了地图的当前位置是否是偶数,然后不难发现这个map是个10*10的地图,然后T5代表着exit的异常,然后根据MOVES从strings表中取出,然后取地图当前位置的数据和输入字符串c后面的5个字符异或对比,如果对了就抛出T8,错了就T5exit。
发现T8的handler在这个函数中不存在,所以肯定存在于make_move函数,下断点,不难找到对应的handler,就是CHKPOINT++的操作,所以说只要有四个c的check_substr操作满足就能获得flag.
分析process_move函数
对输入的字符串进行了一个判断,不难看出这应该是一个在地图上移动的操作,u代表up,d代表down,l代表left,r代表right,但是这里抛出的是T6的handler
T6的handler就在这个函数里面
去看看is_ok函数发现就是一个可行性的检查,ok则更新x和y,map|0x80然后抛出T4,不ok则直接exit
然后我们看看is_ok是怎么检查的,is_ok看的是一个变量*(this+4),这个数据在T6初始化的时候就被赋值了
其实就是判断了map[x][y]是否小于0,而我们知道,这其实代表着判断数据最高位是否是1,也就是map[x][y]&0x80。而抛出的T4的exception其实是返回make_move函数。
解题
分析到这里其实逻辑已经大致清楚了,就是我们的输入其实是一个路径,dlru代表着不同方向,而如果是c则是根据走的步数来判断后续5个字符是否正确,这个c的操作必须要走到一定位置才能使用,当实现了四个c操作之后就能得到flag了,我们先得到地图长啥样。
不难发现,这路径其实是唯一的,因为不让后退(走过的地方会&0x80),然后就需要注意一下c操作,我们可考虑枚举,对所有的strings中的字符串进行异或,猜测对应的字符串。
然后找到明文依次的测试即可得到四个检查点对应的字符串,最后拼接路径最后加个f即可得到flag。
但是其实这个flag后面还可以接东西,因为走过了四个检查点也不能保证迷宫走完。