天天看點

BUUCTF Reverse/[ACTF新生賽2020]Oruga

BUUCTF Reverse/[ACTF新生賽2020]Oruga

BUUCTF Reverse/[ACTF新生賽2020]Oruga
先看檔案資訊:沒有加殼
BUUCTF Reverse/[ACTF新生賽2020]Oruga
IDA64位打開,分析代碼
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 result; // rax
  int i; // [rsp+0h] [rbp-40h]
  char s1[6]; // [rsp+4h] [rbp-3Ch] BYREF
  char s2[6]; // [rsp+Ah] [rbp-36h] BYREF
  char s[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+38h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  memset(s, 0, 25uLL);
  printf("Tell me the flag:");
  scanf("%s", s);
  strcpy(s2, "actf{");
  for ( i = 0; i <= 4; ++i )
    s1[i] = s[i];
  s1[5] = 0;
  if ( !strcmp(s1, s2) )
  {
    if ( sub_78A((__int64)s) )
      printf("That's True Flag!");
    else
      printf("don't stop trying...");
    result = 0LL;
  }
  else
  {
    printf("Format false!");
    result = 0LL;
  }
  return result;
}
           
重點是if語句中的條件

if ( sub_78A((__int64)s) )

,跟進檢視
_BOOL8 __fastcall sub_78A(__int64 a1)
{
  int v2; // [rsp+Ch] [rbp-Ch]
  int v3; // [rsp+10h] [rbp-8h]
  int v4; // [rsp+14h] [rbp-4h]

  v2 = 0;
  v3 = 5;
  v4 = 0;
  while ( byte_201020[v2] != 0x21 )
  {
    v2 -= v4;
    if ( *(_BYTE *)(v3 + a1) != 'W' || v4 == -16 )
    {
      if ( *(_BYTE *)(v3 + a1) != 'E' || v4 == 1 )
      {
        if ( *(_BYTE *)(v3 + a1) != 'M' || v4 == 16 )
        {
          if ( *(_BYTE *)(v3 + a1) != 'J' || v4 == -1 )
            return 0LL;
          v4 = -1;
        }
        else
        {
          v4 = 16;
        }
      }
      else
      {
        v4 = 1;
      }
    }
    else
    {
      v4 = -16;
    }
    ++v3;
    while ( !byte_201020[v2] )
    {
      if ( v4 == -1 && (v2 & 0xF) == 0 )
        return 0LL;
      if ( v4 == 1 && v2 % 16 == 15 )
        return 0LL;
      if ( v4 == 16 && (unsigned int)(v2 - 240) <= 0xF )
        return 0LL;
      if ( v4 == -16 && (unsigned int)(v2 + 15) <= 0x1E )
        return 0LL;
      v2 += v4;
    }
  }
  return *(_BYTE *)(v3 + a1) == '}';
}
           
跟進byte_201020,看到老長一串,轉到hex表
BUUCTF Reverse/[ACTF新生賽2020]Oruga
轉成10進制
BUUCTF Reverse/[ACTF新生賽2020]Oruga
把空格替換為逗号
BUUCTF Reverse/[ACTF新生賽2020]Oruga
得到
0,0,0,0,35,0,0,0, 0,0,0,0,35,35,35,35,
0,0,0,35,35,0,0,0,79,79,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,79,79,0,80,80,0,0,0,
0,0,0,76,0,79,79,0,79,79,0,80,80,0,0,0,
0,0,0,76,0,79,79,0,79,79,0,80,0,0,0,0,
0,0,76,76,0,79,79,0, 0,0,0,80,0,0,0,0,
0,0,0,0,0,79,79,0, 0,0,0,80,0,0,0,0,
35,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,35,0,0,0,
0,0,0,0,0,0,77,77,77,0,0,0,35,0,0,0,
0,0,0,0,0,0,0,77,77,77,0,0,0,0,69,69,
0,0,0,48,0,77,0,77, 0,77,0,0,0,0,69,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,69,69,
84,84,84,73,0,77,0,77, 0,77,0,0,0,0,69,0,
0,84,0,73,0,77,0,77, 0,77,0,0,0,0,69,0,
0,84,0,73,0,77,0,77, 0,77,33,0,0,0,69,69,
           
然後我看代碼看了半天,半天沒有思路,,,看了大佬的wp才知道這玩意原來是個迷宮。。。
寫個腳本輸出一下
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int v2 = 0;
int v4 = 0;


int main()
{
    int i,j;
    char maze[] = {0,0,0,0,35,0,0,0, 0,0,0,0,35,35,35,35,
              0,0,0,35,35,0,0,0,79,79,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,79,79,0,80,80,0,0,0,
0,0,0,76,0,79,79,0,79,79,0,80,80,0,0,0,
0,0,0,76,0,79,79,0,79,79,0,80,0,0,0,0,
0,0,76,76,0,79,79,0, 0,0,0,80,0,0,0,0,
0,0,0,0,0,79,79,0, 0,0,0,80,0,0,0,0,
35,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,35,0,0,0,
0,0,0,0,0,0,77,77,77,0,0,0,35,0,0,0,
0,0,0,0,0,0,0,77,77,77,0,0,0,0,69,69,
0,0,0,48,0,77,0,77, 0,77,0,0,0,0,69,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,69,69,
84,84,84,73,0,77,0,77, 0,77,0,0,0,0,69,0,
0,84,0,73,0,77,0,77, 0,77,0,0,0,0,69,0,
0,84,0,73,0,77,0,77, 0,77,33,0,0,0,69,69};

   for(i = 0 ; i < 16 ;i++ )
   {

       for(j = 0 ; j < 16 ; j++)
       {
           if(maze[i * 16 + j] == 0)
              printf(" ");
           else if(maze[i * 16 + j] == 33)
              printf("#");
           else printf("*");
       }
       printf("\n");
   }

   return 0;
}

           
得到迷宮地圖,起始點在左上角 I ,終點是#
I   *       ****
   **   **
        ** **
   * ** ** **
   * ** ** *
  ** **    *
     **    *
*
            *
      ***   *
       ***    **
   * * * *    *
              **
**** * * *    *
 * * * * *    *
 * * * * *#   **
           
然後這個在空格的位置可以随便走,但是一定要碰到障礙物才能停下來,像塊肥皂一樣。

根據這個,可以推出

M是下

W是上

J是左

E是右

while ( !byte_201020[v2] )       //在空格的地方一直走,直到撞到障礙物
    {
      if ( v4 == -1 && (v2 & 0xF) == 0 )
        return 0LL;
      if ( v4 == 1 && v2 % 16 == 15 )
        return 0LL;
      if ( v4 == 16 && (unsigned int)(v2 - 240) <= 0xF )    //加減16相當于上下,最終是以v2的值決定決定是否結束
        return 0LL;
      if ( v4 == -16 && (unsigned int)(v2 + 15) <= 0x1E )
        return 0LL;
      v2 += v4;
    }
           
然後就照着迷宮寫出路徑得到MEWEMEWJMEWJM
flag : flag{MEWEMEWJMEWJM}