maze writeup

maze writeup

  攻防世界的一道迷宫题,第一次接触这样的题,个人感觉很有意思,收获也挺多,做一篇笔记记录一下。

程序分析

__int64 sub_4006B0()
{
  signed __int64 v0; // rbx
  signed int v1; // eax
  bool v2; // bp
  bool v3; // al
  const char *v4; // rdi
  __int64 v6; // [rsp+0h] [rbp-28h]

  v6 = 0LL;
  puts("Input flag:");
  scanf("%s", &s1, 0LL);
  if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 )// flag长度为24字节,前五个字节为"nctf{",最后一个字节要是"}"
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v0 = 5LL;
  if ( strlen(&s1) - 1 > 5 )
  {
    while ( 1 )
    {
      v1 = *(&s1 + v0);                         // 对每一位进行判断
      v2 = 0;
      if ( v1 > 78 )
      {
        v1 = (unsigned __int8)v1;
        if ( (unsigned __int8)v1 == 'O' )       // "O"表示向左移动
        {
          v3 = sub_400650((__int64)&v6 + 4);
          goto LABEL_14;
        }
        if ( v1 == 'o' )                        // "o"表示向右移动
        {
          v3 = sub_400660((__int64)&v6 + 4);
          goto LABEL_14;
        }
      }
      else
      {
        v1 = (unsigned __int8)v1;
        if ( (unsigned __int8)v1 == '.' )       // "."表示向上移动
        {
          v3 = sub_400670((__int64)&v6);
          goto LABEL_14;
        }
        if ( v1 == '0' )                        // "0"表示向下移动
        {
          v3 = sub_400680((__int64)&v6);
LABEL_14:
          v2 = v3;
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v6), v6) )// asc_601060是字符串首地址
        goto LABEL_22;
      if ( ++v0 >= strlen(&s1) - 1 )
      {
        if ( v2 )
          break;
LABEL_20:
        v4 = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( asc_601060[8 * (signed int)v6 + SHIDWORD(v6)] != '#' )
    goto LABEL_20;
  v4 = "Congratulations!";
LABEL_21:
  puts(v4);
  return 0LL;
}

  主函数如上所示。我开始看的时候没有看明白,后来发现给出了四种操作符,对应上下左右四种移动,给出的字符串要想象成一个二维图像,相当于要用一个二维数组表示出来。

  flag的格式已经给我们规定好了:nctf{......}。

__int64 __fastcall sub_400690(__int64 a1, int a2, int a3)
{
  __int64 result; // rax

  result = *(unsigned __int8 *)(a1 + a2 + 8LL * a3);
  LOBYTE(result) = (_DWORD)result == 32 || (_DWORD)result == 35;
  return result;
}
if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v6), v6) )// asc_601060是字符串首地址
        goto LABEL_22;

  sub_400690函数这里拉出来看一下,SHIDWORD这里是一个宏定义,定义如下:

#define SHIDWORD(x)  (*((int32*)&(x)+1))

  对字符串如何取值或者对二级指针理解还不清楚的,可以尝试敲一下下面的测试代码:

#include<stdio.h>
#include<string.h>

int main()
{
    __int64 v6;
    v6=1LL;char* a="abcdefghjk";
    printf("%p
",a);
    printf("%p
",*(&a));
    printf("%p
",&a);
    printf("%c
",*a);
    printf("%c",*(a+1)); 
    return 0;
}

  宏定义和四种操作符理解不了,尝试下面的测试代码:

#include<stdio.h>
#include<string.h>

#define SHIDWORD(x) (*((__int32*)&(x)+1))
int main()
{
    __int64 v6;
    v6=1LL;
    char* a="abcdefghjk";
    printf("%p
",&v6);
    printf("%p
",(__int64)&v6);
    printf("%p
",&v6+4);
    printf("%p
",(__int64)&v6+4);
    printf("%p",&(SHIDWORD(v6)));
    return 0;
}

  sub_400690中,v6是行数,即y坐标,SHIDWORD(v6)是列数,即x坐标,(__int64)asc_601060是字符串首地址。后面的判断表示走的时候,只能走“#”和空格。

  我们先把字符串转换成一个二维的迷宫

maze="  *******   *  **** * ****  * ***  *#  *** *** ***     *********"
x=""                                                                   
New_maze=""                                                            
for a in maze:                                                         
   if a==" ":                                                          
       New_maze+="0"                                                   
   elif a=="*":                                                        
       New_maze+="1"                                                   
   else:                                                               
       New_maze+=a                                                     
x=""                                                                   
for i in range(len(New_maze)):                                         
    x+=New_maze[i]                                                     
    if (i+1)%8==0:                                                     
        print(x)                                                       
        x=""                                                           

   然后从头开始,“O”表示向左移动,“o”表示向右移动,“.”表示向上移动,“0”表示向下移动(上下这里要注意,容易搞错)。四种操作符看不懂,就好好看一下上面给出的测试代码。

  最后得到flag:nctf{o0oo00O000oooo..OO}。

 

原文地址:https://www.cnblogs.com/L0g4n-blog/p/13358438.html