攻防世界 RE maze

攻防世界官网:https://adworld.xctf.org.cn/

源程序、IDA分析文件、hook.dll下载: http://file.eonew.cn/ctf/re/maze.zip

这题很早以前就做过了,但是却发现没有写博客,所以在这里补上。

分析

main

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

  v10 = 0LL;
  puts("Input flag:");
  scanf("%s", &input, 0LL);
  if ( strlen(&input) != 24 || (v3 = "nctf{", strncmp(&input, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != '}' )
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v4 = 5LL;
  if ( strlen(&input) - 1 > 5 )
  {
    while ( 1 )
    {
      v5 = *(&input + v4);
      v6 = 0;
      if ( v5 > 'N' )
      {
        v5 = (unsigned __int8)v5;
        if ( (unsigned __int8)v5 == 'O' )
        {
          v7 = sub_400650((_DWORD *)&v10 + 1);  // -1
          goto LABEL_14;
        }
        if ( v5 == 'o' )
        {
          v7 = sub_400660((int *)&v10 + 1);     // + 1
          goto LABEL_14;
        }
      }
      else
      {
        v5 = (unsigned __int8)v5;
        if ( (unsigned __int8)v5 == '.' )       // -8
        {
          v7 = sub_400670(&v10, v3);
          goto LABEL_14;
        }
        if ( v5 == '0' )                        // +8
        {
          v7 = sub_400680((int *)&v10);
LABEL_14:
          v6 = v7;
          goto LABEL_15;
        }
      }
LABEL_15:
      v3 = (const char *)HIDWORD(v10);
      if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v10), v10) )
        goto LABEL_22;
      if ( ++v4 >= strlen(&input) - 1 )
      {
        if ( v6 )
          break;
LABEL_20:
        v8 = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != '#' )
    goto LABEL_20;
  v8 = "Congratulations!";
LABEL_21:
  puts(v8);
  return 0LL;
}

迷宫就是asc_601060,通过IDA得到字符 ******* * **** * **** * *** *# *** *** *** *********

下面是它的一些限制:

if ( strlen(&input) != 24 
    || (v3 = "nctf{", strncmp(&input, "nctf{", 5uLL)) 
    || *(&byte_6010BF + 24) != '}' )

看以看出我们的除了那些固定的字符外,就是18个字符。而下面的代码标志了迷宫的出口。

if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != '#' )
  goto LABEL_20;
v8 = "Congratulations!";

也就是说,只要我们在最后一步走到'#'就可以了,

sub_400690

__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;
}

通过对照分析mainsub_400690,便能发现O-1o+1.-80+8

思路

标准做法是用深度优先遍历,鉴于这个迷宫很简单,所以手动走一遍就可以了,最后可以得到如下路径:

[+1, +8, +1, +1, +8, +8, -1, +8, +8, +8, +1, +1, +1, +1, -8, -8, -1, -1]

也就是o0oo00O000oooo..OO,所以我们的flag就是nctf{o0oo00O000oooo..OO}

运行实例

ex@Ex:~/test$ ./maze 
Input flag:
nctf{o0oo00O000oooo..OO}
Congratulations!

总结

算法也是逆向常考的内容之一。