https://buuoj.cn/challenges#[GUET-CTF2019]number_game
64 elf
unsigned __int64 __fastcall main(int a1, char **a2, char **a3)
{
_QWORD *v4; // [rsp+8h] [rbp-38h]
char *input; // [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);
input = 0LL;
v6 = 0;
v7 = 0LL;
v8 = 0;
v9 = 0;
__isoc99_scanf("%s", &input);
if ( (unsigned int)sub_4006D6(&input) )
{
v4 = trans((__int64)&input, 0, 10);
trans2((__int64)v4, (__int64)&v7);
v9 = 0;
store((char *)&v7);
if ( (unsigned int)check() )
{
puts("TQL!");
printf("flag{");
printf("%s", (const char *)&input);
puts("}");
}
else
{
puts("your are cxk!!");
}
}
return __readfsqword(0x28u) ^ v10;
}
__int64 __fastcall sub_4006D6(const char *a1)
{
int i; // [rsp+1Ch] [rbp-4h]
if ( strlen(a1) == 10 )
{
for ( i = 0; i <= 9; ++i )
{
if ( a1[i] > 52 || a1[i] <= '/' ) // 48~52 0 1 2 3 4
goto LABEL_2;
}
return 1LL;
}
else
{
LABEL_2:
puts("Wrong!");
return 0LL;
}
}
在 0 到 4 之间
输入 0 到 4 的十个数字
_QWORD *__fastcall build_tree(char *ptr, int a2, signed int edge)
{
char v5; // [rsp+1Fh] [rbp-11h]
_QWORD *v6; // [rsp+28h] [rbp-8h]
v5 = ptr[a2];
if ( v5 == ' ' || v5 == '\n' || a2 >= edge )
return 0LL;
v6 = malloc(0x18uLL);
*(_BYTE *)v6 = v5; // store data
v6[1] = build_tree(ptr, 2 * a2 + 1, edge);
v6[2] = build_tree(ptr, 2 * (a2 + 1), edge);
return v6;
}
递归建立全二叉树
更改数据结构
struct node
{
_BYTE data;
_QWORD *p1;
_QWORD p2;
};
node *__fastcall build_tree(char *ptr, int a2, signed int edge)
{
char v5; // [rsp+1Fh] [rbp-11h]
node *v6; // [rsp+28h] [rbp-8h]
v5 = ptr[a2];
if ( v5 == ' ' || v5 == '\n' || a2 >= edge )
return 0LL;
v6 = (node *)malloc(0x18uLL);
v6->data = v5; // store data
v6->p1 = build_tree(ptr, 2 * a2 + 1, edge);
v6->p2 = build_tree(ptr, 2 * (a2 + 1), edge);
return v6;
}
分析下一个函数
node *__fastcall trans2(node *now, __int64 a2)
{
node *result; // rax
result = now;
if ( now )
{
trans2((node *)now->p1, a2);
*(_BYTE *)(a2 + dword_601080++) = now->data;
return trans2((node *)now->p2, a2);
}
return result;
}
发现又是两个递归,有点像中序输出
从后面的数据流看出,这里的目标是存储到 a2 里面,所以把 a2 看成是数组
node *__fastcall trans2(node *now, char *res)
{
node *result; // rax
result = now;
if ( now )
{
trans2((node *)now->p1, res);
res[index++] = now->data;
return trans2((node *)now->p2, res);
}
return result;
}
回到主函数,发现 v8 v9 都没有用,推测输入的是存在栈上的数组
unsigned __int64 __fastcall main(int a1, char **a2, char **a3)
{
node *root; // [rsp+8h] [rbp-38h]
char input[10]; // [rsp+10h] [rbp-30h] BYREF
char res[11]; // [rsp+20h] [rbp-20h] BYREF
unsigned __int64 v7; // [rsp+38h] [rbp-8h]
v7 = __readfsqword(0x28u);
memset(input, 0, sizeof(input));
memset(res, 0, sizeof(res));
__isoc99_scanf("%s", input);
if ( (unsigned int)input_filter(input) )
{
root = build_tree(input, 0, 10);
mid_spell(root, res);
res[10] = 0;
store(res);
if ( (unsigned int)check() )
{
puts("TQL!");
printf("flag{");
printf("%s", input);
puts("}");
}
else
{
puts("your are cxk!!");
}
}
return __readfsqword(0x28u) ^ v7;
}
整理一下数据结构
__int64 __fastcall store(char *res)
{
__int64 result; // rax
dump[2] = *res;
dump[7] = res[1]; // 14#2330#1#0#23##3##042##1
dump[9] = res[2];
dump[11] = res[3];
dump[14] = res[4];
dump[15] = res[5];
dump[17] = res[6];
dump[18] = res[7];
dump[22] = res[8];
result = (unsigned __int8)res[9];
dump[23] = res[9];
return result;
}
__int64 check()
{
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 ( dump[5 * i + j] == dump[5 * i + k] )
v1 = 0;
if ( dump[5 * j + i] == dump[5 * k + i] )
v1 = 0;
}
}
}
return v1;
}
用脚本推回去 dump 里所有元素,再对应到树上,根据中序输出和确定个数的完全二叉树推出前序就能做出来
但是从更高角度去理解,当出现循环嵌套的时候,要及时意识到这可能是二维的东西,是一个用一维数值实现二维操作的 trick
就比如说这题,就是 5x5 的表要求行和列上的元素互不相同的意思,其实就是一个另类的数独
14#23
30#1#
0#23#
#3##0
42##1
---
14023
30412
01234
23140
42301
0421421430
知道是中序转前序,用动调输入 0123456789 得到变换 7381940526 (set IP)
flag = list("0421421430")
flag1= [' ']*len(flag)
seq = [7, 3, 8, 1, 9, 4, 0, 5, 2, 6]
for i in range(len(seq)):
flag1[seq[i]]=flag[i]
print("".join(flag1))
1134240024