攻防世界maze 题目讲解

首先打开题目看一下提示
攻防世界maze 题目讲解_第1张图片在这里我们看到题目上说到有“迷宫“二字”,先记下来。
查壳后,发现没有加壳
放到ida里面看

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed __int64 v3; // rbx
  signed int v4; // eax
  bool v5; // bp
  bool v6; // al
  const char *v7; // rdi
  __int64 v9; // [rsp+0h] [rbp-28h]

  v9 = 0LL;
  puts("Input flag:");
  scanf("%s", &s1, 0LL);
  if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )// s1为24位且前五位为nctf{
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v3 = 5LL;
  if ( strlen(&s1) - 1 > 5 )
  {
    while ( 1 )
    {
      v4 = *(&s1 + v3);                         // v5取第nctf{后面的字符
      v5 = 0;
      if ( v4 > 'N' )
      {
        v4 = (unsigned __int8)v4;
        if ( (unsigned __int8)v4 == 'O' )       // 列减一
        {
          v6 = sub_400650((_DWORD *)&v9 + 1);
          goto LABEL_14;
        }
        if ( v4 == 'o' )                        // 列加一
        {
          v6 = sub_400660((int *)&v9 + 1);
          goto LABEL_14;
        }
      }
      else
      {
        v4 = (unsigned __int8)v4;
        if ( (unsigned __int8)v4 == '.' )
        {
          v6 = sub_400670(&v9);                 // 行减一
          goto LABEL_14;
        }
        if ( v4 == '0' )
        {
          v6 = sub_400680((int *)&v9);          // 行加一
LABEL_14:
          v5 = v6;                              // 将v6传给v5,v5就是判断边界的条件
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v9), v9) )// 在ida中 #define HIDWORD(x)  (*((_DWORD*)&(x)+1))
                                                // 这里sub_400690的第二个参数就是列数
                                                // 如果返回为0,执行goto LABEL_22,程序退出
        goto LABEL_22;
      if ( ++v3 >= strlen(&s1) - 1 )
      {
        if ( v5 )
          break;
LABEL_20:
        v7 = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( asc_601060[8 * (signed int)v9 + SHIDWORD(v9)] != '#' )// v9指向的字符为‘#’时,程序完成
    goto LABEL_20;
  v7 = "Congratulations!";
LABEL_21:
  puts(v7);
  return 0LL;
}

首先我们看到
攻防世界maze 题目讲解_第2张图片这里将输入的字符给了s1,并且s1长度为24,s1的前5位为‘nctf{’,最后一位为‘}’,如果不满足就退出
再往下看
攻防世界maze 题目讲解_第3张图片(这里先不要关注我图片里的注释)
v4首先取s1中的第6个字符,然后依据条件进行比较,按照条件不同会进去到六个函数里面
进入这些函数我们看到
攻防世界maze 题目讲解_第4张图片
攻防世界maze 题目讲解_第5张图片函数里执行的是数值的加减,和判断(这里注意到判断是否大于0和小于8)
回到主函数后,会goto LABEL_14

(注:这里的v9在你的ida里面第一次可能是v10,其中有些函数传入的值也会与我图上的不同,没关系。你双击点进去这些函数,再退出来,v10就会变成v9了,条件也会与我的相同)

这里前两个函数传进去的是:&v9+1
后两个函数传进去 的是:&v9
于是可以认为四个函数之间两两相关

重点:我们再往先下看
在这里插入图片描述
注:这个函数中SHIDWORD是ida中的宏定义,就相当于#define SHIDWORD(x) (((int32*)&(x)+1),其实就是&v9+1*
进入函数
攻防世界maze 题目讲解_第6张图片
我们看到:a1 + a2 + 8LL * a3,注意这个8,想起来之前函数的判断条件,和‘’迷宫’,于是想到:v9应该是个存放迷宫内坐标的二维数组,一维表示列,二维表示行
那么,根据之前那四个函数的内容,我的注释应该你也看的懂了

字符==‘O’ 列-1,左
字符==‘o’ 列+1,右
字符==‘.’ 行-1,上
字符==‘0’ 行+1,下

这个迷宫的规格为8*8,代码中的v5是判断是否超过这个迷宫的界限

找到asc_601060的数据:’ ******* * **** * **** * *** *# *** *** *** ********
根据8
8,我们画出这个迷宫

00******
*000*00*
***0*0**
**00*0**
*00*#00*
**0***0*
**00000*
********

现在我们就差一个判断条件,来确定我们走到什么地方才成功
在这里插入图片描述最后几行可以得知:当走到‘#’时,就完成了
(我们初始位置为左上角,由下图可知在这里插入图片描述

于是我们的路径就是:
右下右右下下左下下下右右右右上上左左
就是:
o0oo00O000oooo…OO
包上nctf{},完成

这道题的难点是如何想到这个8*8的迷宫,而在题目中没有明确指出v9相当于一个二维数组

你可能感兴趣的:(ctf,攻防世界,逆向,算法,经验分享)