maze.exe下载:https://www.kanxue.com/author/attach-download-1538.htm
执行maze.exe,提示我们输入移动方向,应该是让我们走迷宫,但是迷宫的具体布局存放在程序内部
you can choose one action to execute
1 up
2 down
3 left
4 right
:
下面我们先通过ida分析代码整体执行情况:
我们定位到输出提示信息的部分,在scanf之后,将读取的值与2比较,如果jz判断成功执行绿色线,否则执行红色线。因为这个程序的意图我们已经大概猜到了,无非就是将结果与1,2,3,4比较。这里先与2比较,应该是switch语句为了提高效率进行的优化(打破纯线性结构,结合二分方法减少判断次数)
接着向下看,可以看到有几个模块指向的是exit,是在读取到<1或者>4的数值后退出,如果合法则分别跳转到四个块中
如果我们用类似矩阵的坐标编码方式,行号为x,列号为y,推断出rsp+0x30处存放当前的x坐标,rsp+0x34存放y坐标。一般出题人习惯从原点(0,0)出发,但是也不能保证在其它位置。进一步将不同的块与命令对应,标上注释
这四个块都汇聚到了共同的一个区域40144A,具体跳转到哪里要看rsp+0x3c处的值,如果是0,1则向右跳转,否则向左跳转。大概看一下左边的代码,其中用到了和'1'、'#'的比较,很可能这些字符标志代表了迷宫中的一些特殊坐标,继续细看,如果和1比较的时候相等就直接exit,那么1是障碍物,而如果和#相等就会提示成功,#是终点。
那么右边的代码是什么呢?在开始具体分析之前,我们可以换位思考一下,对于这样一个简单的程序,我们在写的时候要注意什么呢?首先注意scanf读取的时候是一次性一个字符,而不是读取字符串再解析,所以一定有一个循环来反复读取scanf,而在读取字符之后面临着一个跳转,其中一个是与字符比较,另一个很可能就是判断是否越界,而判断是否越界其实就是揭示了迷宫的大小。而且应该对x和y都进行检验,我们注意到这样一句话:mov eax, [esp+eax*4+30h]
因为跳转到右侧时eax只能是0或者1,所以这里读取的就是esp+0x30或者esp+0x34,这不就是我们分析的x、y地址吗?
再看下面,有inc dword ptr [esp+3Ch]
,每次将esp+0x3c的值加1,然后在40144A那里进行循环判断。如果没猜错的话,应该还有一个位置是当esp+0x3c的值等于2之后将其重新归零,仔细一看,就在上面的401417处!
目前推断的逻辑已经闭环,只需要看左侧的和字符比较:
在加载字符的过程中,先是计算出了5x+y (这里也暗示了数组的宽度为5),因为每个字符就是1字节,所以直接将5x+y加上数组的首地址就是该位置处的迷宫字符,照这样推断,迷宫数组的首地址应该是esp+0x40-0x29,最后的0x29看上去并不怎么优美,但或许有存在的理由,时机已经成熟,接着转入动态分析
使用x32dbg打开程序,我们可以从字符串入手,很容易就定位到了函数的主体发现esp的值是60FEB0,经过确实x和y的初始值确实是0,0,计算出存放迷宫数组的地址为60FEC7,在dump窗口中可以看到
原来刚刚减去0x29是为了让数据的结尾对齐。这里我们可以画出这个迷宫,问题解决。最后输出“路径就是flag”,这种存储信息的方式也阻止了我们直接修改eip来跳转到最后。
总结:
(1)在分析时要抓住一些关键的跳转,比如通过分析跳转到exit的条件,我们可以快速理清程序的框架
(2)要换位思考,至少对于小规模的程序是有用的(建立在能猜测出程序执行逻辑的基础上),想想程序执行需要什么功能
(3)静态分析和动态分析结合
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。