__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 i; // rbx
int input_c; // 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", &input);
if ( strlen(&input) != 24 || strncmp(&input, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 )
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
i = 5LL;
if ( strlen(&input) - 1 > 5 )
{
while ( 1 )
{
input_c = *(&input + i);
v5 = 0;
if ( input_c > 78 )
{
if ( (unsigned __int8)input_c == 79 )
{
v6 = sub_400650(v10); // v10-- > 0
//
goto LABEL_14;
}
if ( (unsigned __int8)input_c == 111 )
{
v6 = sub_400660(v10); // v10++ < 8
goto LABEL_14;
}
}
else
{
if ( (unsigned __int8)input_c == 46 )
{
v6 = sub_400670(&v9); // v9-- > 0
goto LABEL_14;
}
if ( (unsigned __int8)input_c == 48 )
{
v6 = sub_400680((int *)&v9); // v9++ < 8
LABEL_14:
v5 = v6;
goto LABEL_15;
}
}
LABEL_15:
if ( !(unsigned __int8)sub_400690(asc_601060, (unsigned int)v10[0], v9) )// a1[v10[0]+8 * v9] == 32 || ==35
goto LABEL_22;
if ( ++i >= strlen(&input) - 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;
}
首先,根据下面的代码可知,flag是以“nctf{"开头,”}“结尾,长度是24,也就是我们要推理的字符串长度为24-5-1=18
if ( strlen(&input) != 24 || strncmp(&input, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 )
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
从下面的代码可知:当输入字符input_c=79-》v10--;input_c=111-》v10++,input_c=46-》v9--, input_c=48-》v9++,而且v9,v10的取值范围都是【0,8)
input_c = *(&input + i);
v5 = 0;
if ( input_c > 78 )
{
if ( (unsigned __int8)input_c == 79 )
{
v6 = sub_400650(v10); // v10-- > 0
//
goto LABEL_14;
}
if ( (unsigned __int8)input_c == 111 )
{
v6 = sub_400660(v10); // v10++ < 8
goto LABEL_14;
}
}
else
{
if ( (unsigned __int8)input_c == 46 )
{
v6 = sub_400670(&v9); // v9-- > 0
goto LABEL_14;
}
if ( (unsigned __int8)input_c == 48 )
{
v6 = sub_400680((int *)&v9); // v9++ < 8
LABEL_14:
v5 = v6;
goto LABEL_15;
}
只要用户输入的是【79,111,46,48】,LABEL_15一定会被执行。根据下面的代码:asc_601060[v10+v9*8]==35||32
LABEL_15:
if ( !(unsigned __int8)sub_400690(asc_601060, (unsigned int)v10[0], v9) )// a1[v10[0]+8 * v9] == 32 || ==35
goto LABEL_22;
if ( ++i >= strlen(&input) - 1 )
{
if ( v5 )
break;
#########################
__int64 __fastcall sub_400690(__int64 a1, int a2, int a3)
{
__int64 result; // rax
result = *(unsigned __int8 *)(a1 + a2 + 8LL * a3);
LOBYTE(result) = (_DWORD)result == 32 || (_DWORD)result == 35;
return result;
}
于是,我们可以找出asc_601060中所有等于32或35的位置:
def find_all_positions(lst, element):
positions = [i for i, x in enumerate(lst) if x == element]
return positions
asc_601060 = [ 32, 32, 42, 42, 42, 42, 42, 42, 42, 32,
32, 32, 42, 32, 32, 42, 42, 42, 42, 32,
42, 32, 42, 42, 42, 42, 32, 32, 42, 32,
42, 42, 42, 32, 32, 42, 35, 32, 32, 42,
42, 42, 32, 42, 42, 42, 32, 42, 42, 42,
32, 32, 32, 32, 32, 42, 42, 42, 42, 42,
42, 42, 42, 42]
i_35 = find_all_positions(asc_601060,35)
print(i_35)
i_32 = find_all_positions(asc_601060,32)
print(i_32)
结果:
if ( asc_601060[8 * v9 + v10[0]] != 35 )
goto LABEL_20;
v7 = "Congratulations!";
根据上面的代码我们可以知道:因为35在asc_601060的位置是36,所以我们可以知道循环体结束时候v9和v10的所有可能的取值(0,36),(1,28),(2,20),(3,12),(4,4),事实上仅有可能是(4,4),因为v9,v10的取值范围是【0,8)。而(v9,v10)的初始值是(0,0)
综上,我们可以写个程序获取v9和v10在循环的时候可能的取值:
c_values = [0, 1, 9, 10, 11, 13, 14, 19, 21, 26, 27, 29, 33, 34,36,37, 38, 42, 46, 50, 51, 52, 53, 54]
results = []
for c in c_values:
for b in range(0, 8):
a = c - 8*b
if a >= 0 and a < 8: # a是非负数
results.append((a, b))
print(results)
结果:
[(0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (5, 1), (6, 1), (3, 2), (5, 2), (2, 3), (3, 3), (5, 3), (1, 4), (2, 4), (4, 4), (5, 4), (6, 4), (2, 5), (6, 5), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6)]
用1表示可能,0表示不可能,于是有:
for i in range(8):
for j in range(8):
c = '0'
if (j,i) in results:
c = '1'
print(c, end='\t')
print('\n')
结果:
我们可以找到一条由(0,0)到(4,4)的通路,下面黄色数字组成,刚好是18个。
(v9,v10)的坐标是:
(0,0),(0,1)(1,1),(1,2),(1,3),(2,3),(3,3),(3,2),(4,2),(5,2),(6,2),(6,3),(6,4),(6,5),(6,6),(5,6),(4,6),(4,5),(4,4)
根据之前分析得到的:input_c=79-》v10--;input_c=111-》v10++,input_c=46-》v9--, input_c=48-》v9++。所以输入的字符是:
[111,48,111,111,48,48,79,48,48,48,111,111,111,111,46,46,79,79]
也就是
o0oo00O000oooo..OO
所以flag就是:nctf{o0oo00O000oooo..OO}