BUUCTF Reverse/[GUET-CTF2019]number_game

BUUCTF Reverse/[GUET-CTF2019]number_game

BUUCTF Reverse/[GUET-CTF2019]number_game

先看文件信息

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;
}

BUUCTF Reverse/[GUET-CTF2019]number_game

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

BUUCTF Reverse/[GUET-CTF2019]number_game

右键转到hex表查看

BUUCTF Reverse/[GUET-CTF2019]number_game

按5个一组划分,要使每个数在该行和该列都要唯一,所填的数为0到4,这不就是个简单的数独题么

			   14#23
               30#1#
               0#23#
               #3##0
               42##1

数独很简单,有手就行

BUUCTF Reverse/[GUET-CTF2019]number_game

得到中序遍历的结果0421421430,然后参照二叉树中序遍历的三种方法,加上树是按照顺序来创建的,画出这个树就行

BUUCTF Reverse/[GUET-CTF2019]number_game

画出来的二叉树

BUUCTF Reverse/[GUET-CTF2019]number_game

结果就是1134240024了,输入原来的程序验证一下

BUUCTF Reverse/[GUET-CTF2019]number_game

flag{1134240024}

上一篇:KMP匹配算法C语言版


下一篇:python刷题