BUUCTF Reverse/[GUET-CTF2019]number_game
先看文件信息
IDA64位打开
unsigned __int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v4; // [rsp+8h] [rbp-38h]
__int64 v5; // [rsp+10h] [rbp-30h] BYREF
__int16 v6; // [rsp+18h] [rbp-28h]
__int64 v7; // [rsp+20h] [rbp-20h] BYREF
__int16 v8; // [rsp+28h] [rbp-18h]
char v9; // [rsp+2Ah] [rbp-16h]
unsigned __int64 v10; // [rsp+38h] [rbp-8h]
v10 = __readfsqword(0x28u);
v5 = 0LL;
v6 = 0;
v7 = 0LL;
v8 = 0;
v9 = 0;
__isoc99_scanf("%s", &v5);
if ( (unsigned int)sub_4006D6(&v5) ) //检测是否字符是否符合要求
{
v4 = sub_400758(&v5, 0LL, 10LL); //构建二叉树
sub_400807(v4, &v7); //中序遍历
v9 = 0;
sub_400881(&v7); //将遍历的结果插入数组中
if ( (unsigned int)sub_400917() )
{
puts("TQL!");
printf("flag{");
printf("%s", (const char *)&v5);
puts("}");
}
else
{
puts("your are cxk!!");
}
}
return __readfsqword(0x28u) ^ v10;
}
跟进sub_4006D6
if ( (unsigned int)sub_4006D6(&v5) )
得到flag的长度为10且每个字符的ascii码要大于47小于等于52,对应过来的字符就是0到4,转成16进制就是0x30到0x34
__int64 __fastcall sub_4006D6(const char *a1)
{
__int64 result; // rax
int i; // [rsp+1Ch] [rbp-4h]
if ( strlen(a1) == 10 )
{
for ( i = 0; i <= 9; ++i )
{
if ( a1[i] > 52 || a1[i] <= 47 )
goto LABEL_2;
}
result = 1LL;
}
else
{
LABEL_2:
puts("Wrong!");
result = 0LL;
}
return result;
}
v4 = sub_400758(&v5, 0LL, 10LL);
这个函数是将输入的10个数按顺序构建树的,详情可以看二叉树的创建
_QWORD *__fastcall sub_400758(__int64 a1, int a2, unsigned int a3)
{
char v5; // [rsp+1Fh] [rbp-11h]
_QWORD *v6; // [rsp+28h] [rbp-8h]
v5 = *(_BYTE *)(a2 + a1);
if ( v5 == ' ' || v5 == '\n' || a2 >= (int)a3 )// 构建树
return 0LL;
v6 = malloc(0x18uLL);
*(_BYTE *)v6 = v5;
v6[1] = sub_400758(a1, 2 * a2 + 1, a3);
v6[2] = sub_400758(a1, 2 * (a2 + 1), a3);
return v6;
}
sub_400807(v4, &v7);
,这个函数是进行中序遍历
__int64 __fastcall sub_400807(__int64 a1, __int64 a2)
{
__int64 result; // rax
result = a1;
if ( a1 )
{
sub_400807(*(_QWORD *)(a1 + 8), a2); // 中序遍历
*(_BYTE *)(a2 + dword_601080++) = *(_BYTE *)a1;
result = sub_400807(*(_QWORD *)(a1 + 16), a2);
}
return result;
}
这个函数是将中序遍历的结果插入数组中
sub_400881(&v7)
__int64 __fastcall sub_400881(char *a1)
{
__int64 result; // rax
byte_601062 = *a1;
byte_601067 = a1[1];
byte_601069 = a1[2];
byte_60106B = a1[3];
byte_60106E = a1[4];
byte_60106F = a1[5];
byte_601071 = a1[6];
byte_601072 = a1[7];
byte_601076 = a1[8];
result = (unsigned __int8)a1[9];
byte_601077 = a1[9];
return result;
}
最后一个为比较函数,这里可以看成是一个二位数组,要使每一个数在行与列都是唯一的
if ( (unsigned int)sub_400917() )
__int64 sub_400917()
{
unsigned int v1; // [rsp+0h] [rbp-10h]
int i; // [rsp+4h] [rbp-Ch]
int j; // [rsp+8h] [rbp-8h]
int k; // [rsp+Ch] [rbp-4h]
v1 = 1;
for ( i = 0; i <= 4; ++i )
{
for ( j = 0; j <= 4; ++j )
{
for ( k = j + 1; k <= 4; ++k )
{
if ( *((_BYTE *)&unk_601060 + 5 * i + j) == *((_BYTE *)&unk_601060 + 5 * i + k) )
v1 = 0;
if ( *((_BYTE *)&unk_601060 + 5 * j + i) == *((_BYTE *)&unk_601060 + 5 * k + i) )
v1 = 0;
}
}
}
return v1;
}
跟进查看unk_601060
右键转到hex表查看
按5个一组划分,要使每个数在该行和该列都要唯一,所填的数为0到4,这不就是个简单的数独题么
14#23
30#1#
0#23#
#3##0
42##1
数独很简单,有手就行
得到中序遍历的结果0421421430,然后参照二叉树中序遍历的三种方法,加上树是按照顺序来创建的,画出这个树就行
画出来的二叉树
结果就是1134240024了,输入原来的程序验证一下
flag{1134240024}