首先打开题目看一下提示
在这里我们看到题目上说到有“迷宫“二字”,先记下来。
查壳后,发现没有加壳
放到ida里面看
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
signed __int64 v3; // rbx
signed int v4; // eax
bool v5; // bp
bool v6; // al
const char *v7; // rdi
__int64 v9; // [rsp+0h] [rbp-28h]
v9 = 0LL;
puts("Input flag:");
scanf("%s", &s1, 0LL);
if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )// s1为24位且前五位为nctf{
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v3 = 5LL;
if ( strlen(&s1) - 1 > 5 )
{
while ( 1 )
{
v4 = *(&s1 + v3); // v5取第nctf{后面的字符
v5 = 0;
if ( v4 > 'N' )
{
v4 = (unsigned __int8)v4;
if ( (unsigned __int8)v4 == 'O' ) // 列减一
{
v6 = sub_400650((_DWORD *)&v9 + 1);
goto LABEL_14;
}
if ( v4 == 'o' ) // 列加一
{
v6 = sub_400660((int *)&v9 + 1);
goto LABEL_14;
}
}
else
{
v4 = (unsigned __int8)v4;
if ( (unsigned __int8)v4 == '.' )
{
v6 = sub_400670(&v9); // 行减一
goto LABEL_14;
}
if ( v4 == '0' )
{
v6 = sub_400680((int *)&v9); // 行加一
LABEL_14:
v5 = v6; // 将v6传给v5,v5就是判断边界的条件
goto LABEL_15;
}
}
LABEL_15:
if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v9), v9) )// 在ida中 #define HIDWORD(x) (*((_DWORD*)&(x)+1))
// 这里sub_400690的第二个参数就是列数
// 如果返回为0,执行goto LABEL_22,程序退出
goto LABEL_22;
if ( ++v3 >= strlen(&s1) - 1 )
{
if ( v5 )
break;
LABEL_20:
v7 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * (signed int)v9 + SHIDWORD(v9)] != '#' )// v9指向的字符为‘#’时,程序完成
goto LABEL_20;
v7 = "Congratulations!";
LABEL_21:
puts(v7);
return 0LL;
}
首先我们看到
这里将输入的字符给了s1,并且s1长度为24,s1的前5位为‘nctf{’,最后一位为‘}’,如果不满足就退出
再往下看
(这里先不要关注我图片里的注释)
v4首先取s1中的第6个字符,然后依据条件进行比较,按照条件不同会进去到六个函数里面
进入这些函数我们看到
函数里执行的是数值的加减,和判断(这里注意到判断是否大于0和小于8)
回到主函数后,会goto LABEL_14
(注:这里的v9在你的ida里面第一次可能是v10,其中有些函数传入的值也会与我图上的不同,没关系。你双击点进去这些函数,再退出来,v10就会变成v9了,条件也会与我的相同)
这里前两个函数传进去的是:&v9+1
后两个函数传进去 的是:&v9
于是可以认为四个函数之间两两相关
重点:我们再往先下看
注:这个函数中SHIDWORD是ida中的宏定义,就相当于#define SHIDWORD(x) (((int32*)&(x)+1),其实就是&v9+1*
进入函数
我们看到:a1 + a2 + 8LL * a3,注意这个8,想起来之前函数的判断条件,和‘’迷宫’,于是想到:v9应该是个存放迷宫内坐标的二维数组,一维表示列,二维表示行
那么,根据之前那四个函数的内容,我的注释应该你也看的懂了
字符==‘O’ 列-1,左
字符==‘o’ 列+1,右
字符==‘.’ 行-1,上
字符==‘0’ 行+1,下
这个迷宫的规格为8*8,代码中的v5是判断是否超过这个迷宫的界限
找到asc_601060的数据:’ ******* * **** * **** * *** *# *** *** *** ********’
根据88,我们画出这个迷宫
00******
*000*00*
***0*0**
**00*0**
*00*#00*
**0***0*
**00000*
********
现在我们就差一个判断条件,来确定我们走到什么地方才成功
最后几行可以得知:当走到‘#’时,就完成了
(我们初始位置为左上角,由下图可知
)
于是我们的路径就是:
右下右右下下左下下下右右右右上上左左
就是:
o0oo00O000oooo…OO
包上nctf{},完成
这道题的难点是如何想到这个8*8的迷宫,而在题目中没有明确指出v9相当于一个二维数组