• 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}。

     

  • 相关阅读:
    设计模式
    Junit单元测试
    数组存储和链表存储
    java新特型
    List&&Set
    Map
    File文件
    1588. 所有奇数长度子数组的和
    2秒后跳转到某页面
    图片轮播/倒计时--windows对象(setInterval)
  • 原文地址:https://www.cnblogs.com/L0g4n-blog/p/13358438.html
Copyright © 2020-2023  润新知