4

攻防世界Reverse-maze

 1 year ago
source link: https://xdlbw.github.io/2022/05/12/%E6%94%BB%E9%98%B2%E4%B8%96%E7%95%8CReverse-maze/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

攻防世界Reverse-maze

2022-05-12
1.1k- 4m- 7

今天在云演平台上看reverse模块最后一节讲的是迷宫问题,觉得挺有意思。去攻防世界看了看,Reverse模块新手练习区的最后一题就是迷宫问题(maze),所以拿来练练手。

将附件下载下来之后,用 Exeinfo PE 分析,可见不是exe可执行文件,而是ELF。且此文件是64位,加壳与否信息未知,我们用IDA Pro64位进行静态分析。

image-20220512170725889

shift + F12查看字符串窗口

首先查看字符串窗口,发现最底下一串字符是由 * ,# 以及空格组成的,不难猜测出这应该就是迷宫了。其次,Congratulations代表恭喜,这里面是不是有 flag 的信息呢?我们点进去看看。

image-20220512170850061

F5查看伪代码

image-20220512171221304

发现背后是 main 函数,F5查看伪代码

_int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 v3; // rbx
  int v4; // 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", &s1);
  if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 )
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v3 = 5LL;
  if ( strlen(&s1) - 1 > 5 )
  {
    while ( 1 )
    {
      v4 = *(&s1 + v3);
      v5 = 0;
      if ( v4 > 78 )
      {
        if ( (unsigned __int8)v4 == 79 )
        {
          v6 = sub_400650(v10);
          goto LABEL_14;
        }
        if ( (unsigned __int8)v4 == 111 )
        {
          v6 = sub_400660(v10);
          goto LABEL_14;
        }
      }
      else
      {
        if ( (unsigned __int8)v4 == 46 )
        {
          v6 = sub_400670(&v9);
          goto LABEL_14;
        }
        if ( (unsigned __int8)v4 == 48 )
        {
          v6 = sub_400680(&v9);
LABEL_14:
          v5 = v6;
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)sub_400690(asc_601060, (unsigned int)v10[0], v9) )
        goto LABEL_22;
      if ( ++v3 >= strlen(&s1) - 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;
}
 puts("Input flag:");
 scanf("%s", &s1);
 if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 ){
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }

我们输入的字符串为 s1,当此字符串的长度不为24或者 s1的开头五个字符不为 “ nctf{ ” 或者最后一个字符不为 “ } ”时(对照ascii码表,125对应字符 } ),跳转到 LABEL_22,并输出 Wrong flag! 这意味着,最终的 flag 的基本格式为 nctf{18个字符}

其次,循环中肉眼可见的四个判断语句

image-20220512171955255

同样对照ascii码表,可得这几个字符分别为 :O、o、. 、0,不难猜测出这就是我们来控制上下左右走出迷宫的四个方向符了,来查看其对应的操作。

• sub_400650

bool __fastcall sub_400650(_DWORD *a1)
{
  int v1; // eax

  v1 = (*a1)--;
  return v1 > 0;
}

• sub_400660

bool __fastcall sub_400660(int *a1)
{
  int v1; // eax

  v1 = *a1 + 1;
  *a1 = v1;
  return v1 < 8;
}

之后的sub_400670和sub_400650一样,sub_400680和sub_400660,分别执行减一加一的操作,这也验证了我们的猜想是代表走迷宫的上下左右移动。但我们仍然不知道哪个代表 x 轴的移动,哪个代表 y 轴的移动。同时两个函数中还包含着一个关键性的信息,return v1 > 0;return v1 < 8;猜测是代表迷宫的大小为 8*8

所以究竟谁是 x 轴谁是 y 轴,还有起点在哪儿呢?继续观察上述代码,O和o对应的函数参数为 v10,而 . 和0对应的是 v9,回到参数定义的位置

unsigned int v9; // [rsp+0h] [rbp-28h] BYREF
int v10[9]; // [rsp+4h] [rbp-24h] BYREF

这边我没琢磨懂,看了亿眼别人的wp,发现他是这么说的(攻防世界 maze_别害怕我在的博客-CSDN博客_maze攻防世界

加4的就是 x 轴,不加4 的就是 y 轴。

…还是不太明白QAQ,不过个人感觉无非就是两种情况,都试一下问题应该也不大。同时回到main函数的汇编代码段,可见起点是(0,0)

image-20220512173846318

画图获取flag

这样所有逻辑都理清了,即

flag 的基本格式为 nctf{18个字符}

地图是 8*8,将字符串分为此规格即可

O、o、. 、0 代表控制上下左右走出迷宫的四个方向符

O、o分别代表 x 轴左、右移动

. 、0分别代表 y 轴上、下移动

然后就是画图走迷宫了,可以手画也可以代码。这边量不大我就手画了

image-20220512174333325

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK