XCTF攻防世界-Reverse新手区WP

open-source

题目附件为一段C语言代码

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

int main(int argc, char *argv[]) {
    if (argc != 4) {
    	printf("what?\n");
    	exit(1);
    }

    unsigned int first = atoi(argv[1]);
    if (first != 0xcafe) {
    	printf("you are wrong, sorry.\n");
    	exit(2);
    }

    unsigned int second = atoi(argv[2]);
    if (second % 5 == 3 || second % 17 != 8) {
    	printf("ha, you won't get it!\n");
    	exit(3);
    }

    if (strcmp("h4cky0u", argv[3])) {
    	printf("so close, dude!\n");
    	exit(4);
    }

    printf("Brr wrrr grr\n");

    unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;

    printf("Get your key: ");
    printf("%x\n", hash);
    return 0;
}

对代码稍作分析,计算key的关键语句为:unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;

又根据之前的多个if语句可以判断:first = 0xcafe,second % 17 = 8, argv[3] = “h4cky0u”

知道了这些参数,就能够计算最后的hash值

根据分析对代码稍作修改,如下:

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

int main() {
    long long int hash = 0xcafe * 31337 + (8) * 11 + 7 - 1615810207;
    printf("Get your key: ");
    printf("%x\n", hash);
    return 0;
}

运行,输出结果即为flag

c0ffee

insanity

Shift+F12打开字符串窗口,找到flag

在这里插入图片描述

9447{This_is_a_flag}

getit

用IDA64打开

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v3; // al
  __int64 v5; // [rsp+0h] [rbp-40h]
  int i; // [rsp+4h] [rbp-3Ch]
  FILE *stream; // [rsp+8h] [rbp-38h]
  char filename[8]; // [rsp+10h] [rbp-30h]
  unsigned __int64 v9; // [rsp+28h] [rbp-18h]

  v9 = __readfsqword(0x28u);
  LODWORD(v5) = 0;
  while ( (signed int)v5 < strlen(s) )
  {
    if ( v5 & 1 )
      v3 = 1;
    else
      v3 = -1;
    *(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3;
    LODWORD(v5) = v5 + 1;
  }
  strcpy(filename, "/tmp/flag.txt");
  stream = fopen(filename, "w");
  fprintf(stream, "%s\n", u, v5);
  for ( i = 0; i < strlen(&t); ++i )
  {
    fseek(stream, p[i], 0);
    fputc(*(&t + p[i]), stream);
    fseek(stream, 0LL, 0);
    fprintf(stream, "%s\n", u);
  }
  fclose(stream);
  remove(filename);
  return 0;
}

这段代码前半部分是生成flag的逻辑,后半部分只是将flag写进flag.txt而已。flag其实就是经过while循环处理的t字符串。

.data:00000000006010A0                 public s
.data:00000000006010A0 ; char s[]
.data:00000000006010A0 s               db 'c61b68366edeb7bdce3c6820314b7498',0
.data:00000000006010A0                                         ; DATA XREF: main+25↑o
.data:00000000006010A0                                         ; main+3F↑r
.data:00000000006010C1                 align 20h
.data:00000000006010E0                 public t
.data:00000000006010E0 ; char t
.data:00000000006010E0 t               db 53h                  ; DATA XREF: main+65↑w
.data:00000000006010E0                                         ; main+C9↑o ...
.data:00000000006010E1 aHarifctf       db 'harifCTF{????????????????????????????????}',0
.data:000000000060110C                 align 20h
.data:0000000000601120                 public u
.data:0000000000601120 u               db '*******************************************',0
.data:0000000000601120                                         ; DATA XREF: main+A5↑o
.data:0000000000601120                                         ; main+13F↑o

这里要注意的是,字符串t参数应为53h+'harifCTF{????????????????????????????????}',53h即大写字母S,因此flag格式应为:SharifCTF{????????????????????????????????}

按照C伪代码生成flag的逻辑写python脚本:

s = 'c61b68366edeb7bdce3c6820314b7498'
flag = ''
for i in range(len(s)):
    if(i & 1):
        v3 = 1
    else:
        v3 = -1
    flag += chr(ord(s[i])+v3)
print(flag)

运行即可得到{}括号内的内容

在这里插入图片描述

完整flag:SharifCTF{b70c59275fcfa8aebf2d5911223c6589}

Hello, CTF

IDA打开,找到主函数F5反编译成C伪代码如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  signed int v3; // ebx
  char v4; // al
  int result; // eax
  int v6; // [esp+0h] [ebp-70h]
  int v7; // [esp+0h] [ebp-70h]
  char v8; // [esp+12h] [ebp-5Eh]
  char v9[20]; // [esp+14h] [ebp-5Ch]
  char v10; // [esp+28h] [ebp-48h]
  __int16 v11; // [esp+48h] [ebp-28h]
  char v12; // [esp+4Ah] [ebp-26h]
  char v13; // [esp+4Ch] [ebp-24h]

  strcpy(&v13, "437261636b4d654a757374466f7246756e");
  while ( 1 )
  {
    memset(&v10, 0, 32u);                       // v10字符串清空
    v11 = 0;
    v12 = 0;
    sub_40134B((int)aPleaseInputYou, v6);       // please input your serial:
    scanf(aS, v9);
    if ( strlen(v9) > 17 )                      // 输入字串长度大于17 就退出
      break;
    v3 = 0;
    do
    {
      v4 = v9[v3];
      if ( !v4 )
        break;
      sprintf(&v8, asc_408044, v4);   // sprintf(&v8,%x,v4); v8存放输入字符ascii码值的十六进制
      strcat(&v10, &v8);
      ++v3;
    }
    while ( v3 < 17 );					//flag长度为17
    if ( !strcmp(&v10, &v13) )
      sub_40134B((int)aSuccess, v7);	//处理后的flag即v13字串
    else
      sub_40134B((int)aWrong, v7);
  }
  sub_40134B((int)aWrong, v7);
  result = stru_408090._cnt-- - 1;
  if ( stru_408090._cnt < 0 )
    return _filbuf(&stru_408090);
  ++stru_408090._ptr;
  return result;
}

分析以上代码可知,flag长度为17,程序中给出的 v13字符串为输入的flag各个字符的ASCII码的十六进制数拼接而成的。

编写Python脚本:

S = '437261636b4d654a757374466f7246756e'
flag = ''
l = []
i = 0
while(i<34):
    a = '0x'
    a += S[i]
    a += S[i+1]
    l.append(int(a, 16))
    i+=2
    
for i in range(len(l)):
    flag += chr(l[i])
    
print(flag)

运行即得flag

CrackMeJustForFun

simple-unpack

ExeInfo打开查壳,为upx壳

在这里插入图片描述

使用upx加壳脱壳软件脱壳

upx -d 文件路径

在这里插入图片描述

用IDA64打开,shift+F12打开字符串窗口,在最底下找到flag

在这里插入图片描述

flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}

python-trade

文件为pyc文件,可通过uncompyle工具将.pyc文件反编译成.py文件。

在cmd输入pip intall uncompyle即可安装

在文件下载路径打开命令行,输入反编译命令即可

uncompyle6 pyc文件名 > py文件名

本题反编译出的py文件如下:

# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)]
# Embedded file name: 1.py
# Compiled at: 2017-06-03 10:20:43
import base64

def encode(message):
    s = ''
    for i in message:
        x = ord(i) ^ 32
        x = x + 16
        s += chr(x)

    return base64.b64encode(s)


correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
    print 'correct'
else:
    print 'wrong'
# okay decompiling f417c0d03b0344eb9969ed0e1f772091.pyc

将correct字符串进行base64解码,解码后的各个字符编码值-16再与32异或即最终flag。

本来是想用python自带的base64解码的,虽然能解码,但是转成数值时会报错,最后还是选择了有各个字符值的在线解码:

在这里插入图片描述

a = [0X5E, 0X53, 0X64, 0X56, 0X6B, 0X54, 0X23, 0X53, 0X20, 0X5D, 0X60, 
    0X59, 0X5C, 0X21, 0X5E, 0X29, 0X8F, 0X80, 0X69, 0X73, 0X6D]
flag = ''
for i in range(len(a)):
    b = a[i] - 16
    b ^= 32
    flag += chr(b)
print(flag)

运行即得flag

nctf{d3c0mpil1n9_PyC}

re1

IDA打开

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  __int128 v5; // [esp+0h] [ebp-44h]
  __int64 v6; // [esp+10h] [ebp-34h]
  int v7; // [esp+18h] [ebp-2Ch]
  __int16 v8; // [esp+1Ch] [ebp-28h]
  char v9; // [esp+20h] [ebp-24h]

  _mm_storeu_si128((__m128i *)&v5, _mm_loadu_si128((const __m128i *)&xmmword_413E34));
  v7 = 0;
  v6 = qword_413E44;
  v8 = 0;
  printf("欢迎来到DUTCTF呦\n");
  printf("这是一道很可爱很简单的逆向题呦\n");
  printf("输入flag吧:");
  scanf("%s", &v9);
  v3 = strcmp((const char *)&v5, &v9);          // v3大于零程序继续
  if ( v3 )
    v3 = -(v3 < 0) | 1;
  if ( v3 )
    printf(aFlag_0);                            // flag错误
  else
    printf((const char *)&unk_413E90);          // flag get√
  system("pause");
  return 0;
}

程序逻辑就是输入flag与内置flag字符串比对,找到字符串参数xmmword如下图(程序内反向显示)

在这里插入图片描述

a = '}FTCTUD0tem0c1eW{FTCTUD'
flag = a[::-1]
print(flag)

写个小脚本把它反转:

DUTCTF{We1c0met0DUTCTF}

game

与bugku-reverse-游戏过关为同一道题,之前已写过wp,
点此进
zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}

logmein

IDA64打开,反编译

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  size_t v3; // rsi
  int i; // [rsp+3Ch] [rbp-54h]
  char s[36]; // [rsp+40h] [rbp-50h]
  int v6; // [rsp+64h] [rbp-2Ch]
  __int64 v7; // [rsp+68h] [rbp-28h]
  char v8[8]; // [rsp+70h] [rbp-20h]
  int v9; // [rsp+8Ch] [rbp-4h]

  v9 = 0;
  strcpy(v8, ":\"AL_RT^L*.?+6/46");
  v7 = 'harambe'; 
  v6 = 7;
  printf("Welcome to the RC3 secure password guesser.\n", a2, a3);
  printf("To continue, you must enter the correct password.\n");
  printf("Enter your guess: ");
  __isoc99_scanf((__int64)"%32s", (__int64)s);
  v3 = strlen(s);
  if ( v3 < strlen(v8) )                        // 输入的密码长度大于等于v8长度
    sub_4007C0();
  for ( i = 0; i < strlen(s); ++i )
  {
    if ( i >= strlen(v8) )
      sub_4007C0();                             // flag长度等于v8长度
    if ( s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )// flag算法逻辑
      sub_4007C0();
  }
  sub_4007F0();
}

其中sub_4007C0()返回密码错误提示,sub_4007F0()返回密码正确。IDA一开始显示的v7是长串数字,需要转成字符串(可以根据最后if条件的BYTE看出)。IDA内右键可转换数值类型:

在这里插入图片描述

但是数值转字符串类型在IDA内结果是反向的,为‘ebmarah’,需要反转成’harambe’。

根据伪代码中的算法逻辑写脚本就行了,必要的v7, v6, v8 几个参数很直接的在代码中给出了。

a = 'harambe'
b = 7
c = ':\"AL_RT^L*.?+6/46'
flag = ''
for i in range(len(c)):
    flag += chr((ord(a[i%b])) ^ ord(c[i]))

print(flag)

运行得到最后的flag:

RC3-2016-XORISGUD

no-strings-attached

IDA打开,反编译主函数main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  setlocale(6, &locale); 	//locale = 0
  banner();
  prompt_authentication();
  authenticate();
  return 0;
}

其中各个函数如下

int banner()
{
  unsigned int v0; // eax

  v0 = time(0);
  srand(v0);
  wprintf(&unk_80488B0);	 //Welcome to cyber malware control software.
  rand();
  return wprintf(&unk_8048960);	  //Currently tracking %d bots worldwide
/*-----------------------------------------------------*/
int prompt_authentication()
{
  return wprintf(&unk_80489F8);	   //Please enter authentication details:
}
/*------------------------------------------------------*/
void authenticate()
{
  wchar_t ws[8192];// [esp+1Ch] [ebp-800Ch]
  wchar_t *s2;// [esp+801Ch] [ebp-Ch]

  s2 = (wchar_t *)decrypt(&s, &dword_8048A90); 			//s2由decrypt函数加密而来
  if ( fgetws(ws, 0x2000, stdin) )				//输入字符串ws
  {
    ws[wcslen(ws) - 1] = 0;
    if ( !wcscmp(ws, s2) )				//字符串ws和s2比较 s2为flag
      wprintf(&unk_8048B44);//Sucess! Welcome back!
    else
      wprintf(&unk_8048BA4);//Access dinied!
  }
  free(s2);
}
/*--------------------------------------------------*/
wchar_t *__cdecl decrypt(wchar_t *s, wchar_t *a2)
{
  size_t v2; // eax
  signed int v4; // [esp+1Ch] [ebp-1Ch]
  signed int i; // [esp+20h] [ebp-18h]
  signed int v6; // [esp+24h] [ebp-14h]
  signed int v7; // [esp+28h] [ebp-10h]
  wchar_t *dest; // [esp+2Ch] [ebp-Ch]

  v6 = wcslen(s);
  v7 = wcslen(a2);
  v2 = wcslen(s);
  dest = (wchar_t *)malloc(v2 + 1);
  wcscpy(dest, s);
  while ( v4 < v6 )
  {
    for ( i = 0; i < v7 && v4 < v6; ++i )
      dest[v4++] -= a2[i];
  }
  return dest;	//这里的返回值dest就是s2的值,即flag
}

有两种方法可以获得flag,一种是分析decrypt()函数计算flag,另一种是动态调试。

这里使用动态调试的方法。

查看decrypt函数的汇编代码

text:08048658 ; int __cdecl decrypt(wchar_t *s, wchar_t *)
.text:08048658                 public decrypt
.text:08048658 decrypt         proc near               ; CODE XREF: authenticate+18↓p
.text:08048658
.text:08048658 var_1C          = dword ptr -1Ch
.text:08048658 var_18          = dword ptr -18h
.text:08048658 var_14          = dword ptr -14h
.text:08048658 var_10          = dword ptr -10h
.text:08048658 dest            = dword ptr -0Ch
.text:08048658 s               = dword ptr  8
.text:08048658 arg_4           = dword ptr  0Ch
.text:08048658
.text:08048658 ; __unwind {
.text:08048658                 push    ebp
.text:08048659                 mov     ebp, esp
.text:0804865B                 push    ebx
.text:0804865C                 sub     esp, 34h
.text:0804865F                 mov     eax, [ebp+s]
.text:08048662                 mov     [esp], eax      ; s
.text:08048665                 call    _wcslen
.text:0804866A                 mov     [ebp+var_14], eax
.text:0804866D                 mov     eax, [ebp+arg_4]
.text:08048670                 mov     [esp], eax      ; s
.text:08048673                 call    _wcslen
.text:08048678                 mov     [ebp+var_10], eax
.text:0804867B                 mov     ebx, [ebp+s]
.text:0804867E                 mov     eax, [ebp+s]
.text:08048681                 mov     [esp], eax      ; s
.text:08048684                 call    _wcslen
.text:08048689                 add     eax, 1
.text:0804868C                 mov     [esp], eax      ; size
.text:0804868F                 call    _malloc
.text:08048694                 mov     [ebp+dest], eax
.text:08048697                 mov     [esp+4], ebx    ; src
.text:0804869B                 mov     eax, [ebp+dest]				#这里可以看到,dest值是传进了寄存器eax
.text:0804869E                 mov     [esp], eax      ; dest
.text:080486A1                 call    _wcscpy
.text:080486A6                 mov     [ebp+var_18], 0
.text:080486AD                 jmp     short loc_80486F7

因为文件是ELF格式,所以需要使用到Linux系统内的gdb调试指令。

pwndbg插件安装使用方法可参考教程

友情提示:要在root权限下使用gdb,如果是非root用户的话就有可能会像我一样在试图查看寄存器内容的时候疯狂报错“Cannot access memory at address XXXXX”(到现在还是没明白什么原因报的错,用的是ubuntu18.04虚拟机,差点搞到要重装系统= =)

root设置参考博客
以下为gdb调试指令:

(gdb) file 11					# file命令 读取文件(文件名为我随便重命名的11)
Reading symbols from 11...(no debugging symbols found)...done.
(gdb) b decrypt					# b 在decrypt处设置断点
Breakpoint 1 at 0x804865c
(gdb) r								# r 运行程序(run) 显示在断点处停止
Starting program: /home/terra/11 
Welcome to cyber malware control software.
Currently tracking 1092326991 bots worldwide

Breakpoint 1, 0x0804865c in decrypt ()
(gdb) n								# n 单步步入
Single stepping until exit from function decrypt,
which has no line number information.
0x08048725 in authenticate ()
(gdb) x/5sw $eax	# x就是查看内存内容 5表示查看的单元个数 s是以字符串形式 w是按字单元(word) $eax表示查看eax寄存器内容 
0x804cfd0:	U"9447{you_are_an_international_mystery}"
0x804d06c:	U""
0x804d070:	U""
0x804d074:	U""
0x804d078:	U""

直接可以看到flag: 9447{you_are_an_international_mystery}

csaw2013reversing2

运行程序,会弹出一个标题为Flag的窗口,内容是乱码。

拖入IDA进行简单分析

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // ecx
  CHAR *lpMem; // [esp+8h] [ebp-Ch]
  HANDLE hHeap; // [esp+10h] [ebp-4h]

  hHeap = HeapCreate(0x40000u, 0, 0);
  lpMem = (CHAR *)HeapAlloc(hHeap, 8u, MaxCount + 1);
  memcpy_s(lpMem, MaxCount, &unk_409B10, MaxCount);
  if ( sub_40102A() || IsDebuggerPresent() )
  {
    __debugbreak();							//暂停执行 进入调试
    sub_401000(v3 + 4, (int)lpMem);			//对lpMem操作 猜测为flag加密函数
    ExitProcess(0xFFFFFFFF);				//终止程序
  }
  MessageBoxA(0, lpMem + 1, "Flag", 2u);	//弹窗函数 由此看出lpMem+1为flag内容
  HeapFree(hHeap, 0, lpMem);
  HeapDestroy(hHeap);
  ExitProcess(0);
}

if条件内的第一个函数sub_40102A()如下,它的返回值为0:

int sub_40102A()
{
  char v0; // t1

  v0 = *(_BYTE *)(*(_DWORD *)(__readfsdword(0x18u) + 48) + 2);
  return 0;
}

而if条件内的第二个函数IsDebuggerPresent()定义如下:

IsDebuggerPresent是确定调用进程是否由用户模式的调试器调试。

如果当前进程运行在调试器的上下文,返回值为非零值。

如果当前进程没有运行在调试器的上下文,返回值是零。

因此实际运行源程序时,很有可能为:if判断条件值为0(假),不执行if语句内的内容,跳过 if 内的函数直接弹窗而造成了乱码。

如果 if条件判断为真,程序虽然执行了加密函数sub_401000,紧接着就会被ExitProcess结束进程,不会执行之后的弹窗操作。

因此要得到最终flag有几个关键点:执行sub_401000加密函数,以及 绕过ExitProcess的中断。

将程序用OllyDBG打开,通过搜索“Flag”可以定位到弹窗位置:

在这里插入图片描述

可以看到,程序未执行IsDebuggerPresent后 if条件的内容,而是直接跳转到了弹窗地址008510B9

将图中 je 跳转语句修改跳转到0085109B位置(函数sub_401000的前一个位置),这样绕过了中间的 int3 断点。

再将函数sub_401000后的 jmp 跳转改为跳转至弹窗处008510B9,就能绕过ExitProcess的终止程序从而输出flag。

在这里插入图片描述

flag{reversing_is_not_that_hard!}"

maze

根据题目描述可知这是一道迷宫题。

用IDA64打开,F5将主函数main反编译成C伪代码:

__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) != '}' )
  {                                             // flag长度为24 并且由nctf{}包裹
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v3 = 5LL;
  if ( strlen(&s1) - 1 > 5 )
  {
    while ( 1 )
    {
      v4 = *(&s1 + v3);                         // 从flag花括号内的第一个字符开始比对
      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;
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v9), v9) )	// 检测是否发生碰撞 只有' '和'#'是可行走的 
        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)] != '#' ) //循环结束判断 是否到达迷宫终点'#'
    goto LABEL_20;
  v7 = "Congratulations!";
LABEL_21:
  puts(v7);
  return 0LL;
}

其中 SHIDWORD(v9)&v9 + 1 ( 常见IDA宏定义参考博客 )

迷宫字符串asc_601060[]如下,长度为64:

  *******   *  **** * ****  * ***  *#  *** *** ***     *********

根据以下代码能够判断出 &v9 为纵坐标(所在行), &v9+1为横坐标(所在列),迷宫是8*8规格的。

if ( asc_601060[8 * (signed int)v9 + SHIDWORD(v9)] != '#' )		//判断是否到达迷宫终点'#'

其中逻辑为:

当前位置 = 8(迷宫横长) * 当前纵坐标(所在行) + 当前纵坐标(所在列)

其中横纵坐标由0开始算。

又根据伪代码中四个 if判断中的函数判断移动四个方向:

bool __fastcall sub_400650(_DWORD *a1) 		// a1为 &v9+1(横坐标)
{						// v4 = 'O'
  int v1; 
  v1 = (*a1)--;			// 横坐标-1 向左移动
  return v1 > 0;		// 是否超出边界
}

bool __fastcall sub_400660(int *a1)			// a1为 &v9+1
{						// v4 = 'o'
  int v1; 
  v1 = *a1 + 1;			// 横坐标+1 向右移动
  *a1 = v1;
  return v1 < 8;
}

bool __fastcall sub_400670(_DWORD *a1)		// a1为 v9(纵坐标)
{						// v4 = '.'
  int v1;
  v1 = (*a1)--;			// 纵坐标-1 向上移动
  return v1 > 0;		// 超界判断
}

bool __fastcall sub_400680(int *a1)			// a1为 v9
{
  int v1; 				// v4 = '0'
  v1 = *a1 + 1;			// 纵坐标+1 向下移动
  *a1 = v1;
  return v1 < 8;
}

将迷宫字符串以8*8格式打印出来(起点在左上角,终点为#)

  ******		
*   *  *
*** * **
**  * **
*  *#  *
** *** *
**     *
********

走出迷宫方式为:右下右右下下左下下下右右右右上上左左

对应flag字符串:o0oo00O000oooo…OO

字符串长度刚好也对应为程序开头的判断(18+6=24)

在Linux虚拟机内运行验证也正确。

在这里插入图片描述

nctf{o0oo00O000oooo..OO}


总算完成了 撒花✿✿ヽ(°▽°)ノ✿

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值