0x01
拿到题目,放到IDA中静态分析,发现main函数中就是关键代码,如图:
__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 )
{
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 )
{
v7 = sub_400650((_DWORD *)&v10 + 1);
goto LABEL_14;
}
if ( v5 == 111 )
{
v7 = sub_400660((int *)&v10 + 1);
goto LABEL_14;
}
}
else //对行进行操作
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 46 ) //45对应'.'
{
v7 = sub_400670(&v10, v3); //对i行进行操作,向上代表'.'
goto LABEL_14;
}
if ( v5 == 48 ) //48对应0
{
v7 = sub_400680(&v10, v3); //对i行进行操作,向下代表0
LABEL_14:
v6 = v7;
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;
}
那么这道题其实就是分析代码,然后得到flag
0x02
一、
接下来我们来看看代码
if ( strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125 )
这句的意思是在对我们输入的字符进行比较,所以通过这里我们知道falg的前5位是nctf{ 第24位为},所以这里我们就需要对{}中的内容进行分析
二、
while ( 1 )
{
v5 = *(&s1 + v4); //表示从输入的第五位开始
v6 = 0;
if ( v5 > 78 ) //对列进行操作
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 79 ) //79对应'O'
{
v7 = sub_400650((_DWORD *)&v10 + 1); //对j列进行操作,向左对应'O'
goto LABEL_14;
}
这段代码就是说如果我们要向左走,那么就对应一个'O'字母
三、
if ( v5 == 111 ) //111 就是'o'
{
v7 = sub_400660((int *)&v10 + 1); //对j列进行操作,向右代表'o'
goto LABEL_14;
}
这段代码就是表明,向左运动一次,则代表一个字母'o'
四、
else //对行进行操作
{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 46 ) //45对应'.'
{
v7 = sub_400670(&v10, v3); //对i行进行操作,向上代表'.'
goto LABEL_14;
}
if ( v5 == 48 ) //48对应0
{
v7 = sub_400680(&v10, v3); //对i行进行操作,向下代表0
LABEL_14:
这里就是和上面对应的对行的操作,向上向下分别对应不同的值
五、
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;
这段代码就是要画出这个迷宫的样子应进行的操作
那么这段代码的意思就是,构造一个8*8的矩阵,然后,用
’******* * **** * **** * *** *# *** *** *** *********‘
填充矩阵。
那么这个矩阵就需要我们把它画出来
六、
if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != 35 ) //35代表#
goto LABEL_20;
v8 = "Congratulations!";
这段代码就是说如果最后v10的值等于35(即#)则成功,所以这里,我们最后通过移动v8的位置,要让v8最后处于矩阵中#的位置。
0x03
通过上面的代码分析,我们知道了,这应该是个迷宫,我们通过迷宫的形状,找出应该走的路径,然后将走的路径替换为相应的值,最后得到的值即为我们的flag,那么下面我们应该做的第一步就是,画出这个迷宫!
画迷宫:
import numpy as ny
q='nctf{'
h='}'
asc=' ******* * **** * **** * *** *# *** *** *** *********'
a=ny.array(list(asc))
print(str(a.reshape(int(len(asc)/8),8)).replace('\'',''))
结果:
[[ * * * * * *]
[* * *]
[* * * * * *]
[* * * * *]
[* * # *]
[* * * * * *]
[* * *]
[* * * * * * * *]]
所以我们如何能走到#呢?那么我们得到路径为下:
右下右右下下左下下下右右右右上上左左
然后我们将‘右’替换为‘O’,将‘左’替换为‘o’,将‘上’替换为‘.’,将下替换为0,即可得到flag
lujing='右下右右下下左下下下右右右右上上左左'.replace('上','.').replace('下','0').replace('左','O').replace('右','o')
print('nctf{'+lujing+'}')
运行结果:
nctf{o0oo00O000oooo..OO}