maze - wp
分析题目附件:
先拖入Exeinfo PE中:
ELF文件,64位。
拖入ida64,找main函数按F5(Fn+F5)查看伪代码:
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
const char *v3; // rsi
signed __int64 v4; // rbx
signed int v5; // eax
char v6; // bp
char v7; // al
const char *v8; // rdi
__int64 v10; // [rsp+0h] [rbp-28h]
v10 = 0LL;
puts("Input flag:");
scanf("%s", &s1, 0LL);
if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 ) //输入字符串s1长度为24,并且前5个字符为 "nctf{" , 最后一个字符为125= '}' ,所以中间数据为填充部分
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v4 = 5LL;
if ( strlen(&s1) - 1 > 5 )
{
while ( 1 )
{
v5 = *(&s1 + v4);
v6 = 0;
if ( v5 > 78 )
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 79 ) //79='O',表示左移
{
v7 = sub_400650((char *)&v10 + 4, v3); v10--,表示位置的列数-1,v7判断是否越界
goto LABEL_14;
}
if ( v5 == 111 ) // 111='o',表示右移
{
v7 = sub_400660((char *)&v10 + 4, v3); //v10++,表示位置的列数+1,
goto LABEL_14;
}
}
else
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 46 ) // 46='.',表示上移
{
v7 = sub_400670(&v10, v3); //v10--,表示位置的行数-1
goto LABEL_14;
}
if ( v5 == 48 ) // 48='0',表示下移
{
v7 = sub_400680(&v10, v3); //v10++, 表示位置的行数+1
LABEL_14:
v6 = v7; //赋值给v6,判断走迷宫时,是否越界
goto LABEL_15;
}
}
LABEL_15:
v3 = (const char *)HIDWORD(v10);
if ( !(unsigned __int8)sub_400690(asc_601060, HIDWORD(v10), (unsigned int)v10) ) //判断该位置的字符是' ', '#'或者'*',如果是'*',则返回再次寻路
goto LABEL_22;
if ( ++v4 >= strlen(&s1) - 1 )
{
if ( v6 ) //判断是否越界
break;
LABEL_20:
v8 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != 35 ) //'#'是迷宫出口,判断是否到达'#'处,没有到达,继续循环,进行移动
goto LABEL_20;
v8 = "Congratulations!";
LABEL_21:
puts(v8);
return 0LL;
}
分析伪代码发现v5的ASCII码值为79,111,46,48时分别执行四个函数
v5=79
bool __fastcall sub_400650(_DWORD *a1)
{
int v1; // eax
v1 = (*a1)--; // 横坐标-1 向左移动
return v1 > 0; // 判断是否超出边界
}
v5=111
bool __fastcall sub_400660(int *a1)
{
int v1; // eax
v1 = *a1 + 1; // 横坐标+1 向右移动
*a1 = v1;
return v1 < 8;
}
v5=46
bool __fastcall sub_400670(_DWORD *a1)
{
int v1; // eax
v1 = (*a1)--; // 纵坐标-1 向上移动
return v1 > 0;
}
v5=48
bool __fastcall sub_400680(int *a1)
{
int v1; // eax
v1 = *a1 + 1; // 纵坐标+1 向下移动
*a1 = v1;
return v1 < 8;
}
迷宫终点判断:
__int64 __fastcall sub_400690(__int64 a1, int a2, int a3)
{
__int64 result; // rax
result = *(unsigned __int8 *)(a1 + a2 + 8LL * a3); //a1是迷宫,a2是列,a3是行。通过行列计算迷宫对应位置的字符
LOBYTE(result) = (_DWORD)result == 32 || (_DWORD)result == 35; //如果是' '或者'#‘返回TRUE,是'*’返回FALSE
return result;
}
综合以上分析,’O’ ‘o’ ‘.’ ‘0’ 时分别表示左 右 上 下的移动。
另外我们还发现了类似迷宫的字符串asc_601060:
.data:0000000000601060 asc_601060 db ' ******* * **** * **** * *** *# *** *** *** *********',0
共有64位,猜测可能是8x8的迷宫,将字符串分隔:
******
* * *
*** * **
** * **
* *# *
** *** *
** *
********
对应的走迷宫方式位:
o 0 oo 00 O 000 oooo .. OO
左 下 左左 下下 右 下下下 左左左左 上上 右右
合起来就是:o0oo00O000oooo…OO
则 flag = nctf{o0oo00O000oooo…OO} 。