今天在云演平台上看reverse模块最后一节讲的是迷宫问题,觉得挺有意思。去攻防世界看了看,Reverse模块新手练习区的最后一题就是迷宫问题(maze),所以拿来练练手。
收集信息
将附件下载下来之后,用 Exeinfo PE 分析,可见不是exe可执行文件,而是ELF。且此文件是64位,加壳与否信息未知,我们用IDA Pro64位进行静态分析。
静态分析
shift + F12查看字符串窗口
首先查看字符串窗口,发现最底下一串字符是由 * ,# 以及空格组成的,不难猜测出这应该就是迷宫了。其次,Congratulations代表恭喜,这里面是不是有 flag 的信息呢?我们点进去看看。
F5查看伪代码
发现背后是 main 函数,F5查看伪代码
_int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v3; // rbx
int v4; // eax
char v5; // bp
char v6; // al
const char *v7; // rdi
unsigned int v9; // [rsp+0h] [rbp-28h] BYREF
int v10[9]; // [rsp+4h] [rbp-24h] BYREF
v10[0] = 0;
v9 = 0;
puts("Input flag:");
scanf("%s", &s1);
if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 )
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v3 = 5LL;
if ( strlen(&s1) - 1 > 5 )
{
while ( 1 )
{
v4 = *(&s1 + v3);
v5 = 0;
if ( v4 > 78 )
{
if ( (unsigned __int8)v4 == 79 )
{
v6 = sub_400650(v10);
goto LABEL_14;
}
if ( (unsigned __int8)v4 == 111 )
{
v6 = sub_400660(v10);
goto LABEL_14;
}
}
else
{
if ( (unsigned __int8)v4 == 46 )
{
v6 = sub_400670(&v9);
goto LABEL_14;
}
if ( (unsigned __int8)v4 == 48 )
{
v6 = sub_400680(&v9);
LABEL_14:
v5 = v6;
goto LABEL_15;
}
}
LABEL_15:
if ( !(unsigned __int8)sub_400690(asc_601060, (unsigned int)v10[0], v9) )
goto LABEL_22;
if ( ++v3 >= strlen(&s1) - 1 )
{
if ( v5 )
break;
LABEL_20:
v7 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * v9 + v10[0]] != 35 )
goto LABEL_20;
v7 = "Congratulations!";
LABEL_21:
puts(v7);
return 0LL;
}
来看重点
puts("Input flag:");
scanf("%s", &s1);
if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 ){
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
我们输入的字符串为 s1,当此字符串的长度不为24或者 s1的开头五个字符不为 “ nctf{ ” 或者**最后一个字符不为 “ } ”**时(对照ascii码表,125对应字符 } ),跳转到 LABEL_22,并输出 Wrong flag! 这意味着,最终的 flag 的基本格式为 nctf{18个字符}
其次,循环中肉眼可见的四个判断语句
同样对照ascii码表,可得这几个字符分别为 :O、o、. 、0,不难猜测出这就是我们来控制上下左右走出迷宫的四个方向符了,来查看其对应的操作。
• sub_400650
bool __fastcall sub_400650(_DWORD *a1)
{
int v1; // eax
v1 = (*a1)--;
return v1 > 0;
}
• sub_400660
bool __fastcall sub_400660(int *a1)
{
int v1; // eax
v1 = *a1 + 1;
*a1 = v1;
return v1 < 8;
}
之后的sub_400670和sub_400650一样,sub_400680和sub_400660,分别执行减一加一的操作,这也验证了我们的猜想是代表走迷宫的上下左右移动。但我们仍然不知道哪个代表 x 轴的移动,哪个代表 y 轴的移动。同时两个函数中还包含着一个关键性的信息,return v1 > 0;
和 return v1 < 8;
猜测是代表迷宫的大小为 8*8。
所以究竟谁是 x 轴谁是 y 轴,还有起点在哪儿呢?继续观察上述代码,O和o对应的函数参数为 v10,而 . 和0对应的是 v9,回到参数定义的位置
unsigned int v9; // [rsp+0h] [rbp-28h] BYREF
int v10[9]; // [rsp+4h] [rbp-24h] BYREF
这边我没琢磨懂,看了亿眼别人的wp,发现他是这么说的:攻防世界 maze_别害怕我在的博客-CSDN博客_maze攻防世界
加4的就是 x 轴,不加4 的就是 y 轴。
…还是不太明白QAQ,不过个人感觉无非就是两种情况,都试一下问题应该也不大。同时回到main函数的汇编代码段,可见起点是(0,0)
画图获取flag
这样所有逻辑都理清了,即
flag 的基本格式为
nctf{18个字符}
地图是 8*8,将字符串分为此规格即可
O、o、. 、0 代表控制上下左右走出迷宫的四个方向符
O、o分别代表 x 轴左、右移动
. 、0分别代表 y 轴上、下移动
然后就是画图走迷宫了,可以手画也可以代码。这边量不大我就手画了
内容以及同步更新至 lbw的小窝