天天看点

攻防世界逆向新手区

Hello, CTF

攻防世界逆向新手区

查看伪代码

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

  strcpy(v13, "437261636b4d654a757374466f7246756e");
  while ( 1 )
  {
    memset(v10, 0, sizeof(v10));
    v11 = 0;
    v12 = 0;
    sub_40134B(aPleaseInputYou, v6);
    scanf("%s", v9);
    if ( strlen(v9) > 0x11 )
      break;
    for ( i = 0; i < 17; ++i )
    {
      v4 = v9[i];
      if ( !v4 )
        break;
      sprintf(Buffer, "%x", v4);  // Buffer就是16进制形式的flag
      strcat(v10, Buffer);
    }
    if ( !strcmp(v10, v13) )  // 16进制形式flag和v13比较
      sub_40134B(aSuccess, v7);
    else
      sub_40134B(aWrong, v7);
  }
  sub_40134B(aWrong, v7);
  result = --Stream._cnt;
  if ( Stream._cnt < 0 )
    return _filbuf(&Stream);
  ++Stream._ptr;
  return result;
}
           

所以直接将

437261636b4d654a757374466f7246756e

转字符串就能得到flag

攻防世界逆向新手区
攻防世界逆向新手区

insanity

用Notepad++搜索关键字

flag

攻防世界逆向新手区

或者用IDA搜索字符串

攻防世界逆向新手区

python-trade

附件为pyc后缀的文件,可以在线反编译得到源代码

python反编译

import base64

def encode(message):
    s = ''
    for i in message:
        x = ord(i) ^ 32
        x = x + 16
        s += chr(x)
    
    return base64.b64encode(s)  # base64加密后返回

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
    print 'correct'
else:
    print 'wrong'
           

exp

import base64

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
s = base64.b64decode(correct)
flag = ''
for i in s:
    flag += chr(i - 16 ^ 32)
print(flag)
           

re1

攻防世界逆向新手区

查看伪代码

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

  v5 = _mm_loadu_si128((const __m128i *)&xmmword_413E34);
  v7 = 0;
  v6 = 0x7D465443545544i64;
  v8 = 0;
  printf("欢迎来到DUTCTF呦\n");
  printf("这是一道很可爱很简单的逆向题呦\n");
  printf("输入flag吧:");
  scanf("%s", v9);
  v3 = strcmp(v5.m128i_i8, v9);  // v5与xmmword_413E34有关
  if ( v3 )
    v3 = v3 < 0 ? -1 : 1;
  if ( v3 )
    printf(aFlag_0);
  else
    printf(aFlagGet);
  system("pause");
  return 0;
}
           

查看

xmmword_413E34

攻防世界逆向新手区

R

键转字符串,因为是小段存储,所以是逆序的

攻防世界逆向新手区

OD搜索字符串可以直接得到flag

攻防世界逆向新手区
攻防世界逆向新手区

game

直接得出

按顺序输入1到8或8到1,flag就会出现

攻防世界逆向新手区

静态分析

查看伪代码,找到判断处的关键函数

攻防世界逆向新手区

进入查看是打印flag的函数

int sub_45E940()
{
  int i; // [esp+D0h] [ebp-94h]
  char v2[22]; // [esp+DCh] [ebp-88h]
  char v3[32]; // [esp+F2h] [ebp-72h] BYREF
  char v4[4]; // [esp+112h] [ebp-52h] BYREF
  char v5[64]; // [esp+120h] [ebp-44h]

  sub_45A7BE("done!!! the flag is ");
  v5[0] = 18;
  v5[1] = 64;
  v5[2] = 98;
  v5[3] = 5;
  v5[4] = 2;
  v5[5] = 4;
  v5[6] = 6;
  v5[7] = 3;
  v5[8] = 6;
  v5[9] = 48;
  v5[10] = 49;
  v5[11] = 65;
  v5[12] = 32;
  v5[13] = 12;
  v5[14] = 48;
  v5[15] = 65;
  v5[16] = 31;
  v5[17] = 78;
  v5[18] = 62;
  v5[19] = 32;
  v5[20] = 49;
  v5[21] = 32;
  v5[22] = 1;
  v5[23] = 57;
  v5[24] = 96;
  v5[25] = 3;
  v5[26] = 21;
  v5[27] = 9;
  v5[28] = 4;
  v5[29] = 62;
  v5[30] = 3;
  v5[31] = 5;
  v5[32] = 4;
  v5[33] = 1;
  v5[34] = 2;
  v5[35] = 3;
  v5[36] = 44;
  v5[37] = 65;
  v5[38] = 78;
  v5[39] = 32;
  v5[40] = 16;
  v5[41] = 97;
  v5[42] = 54;
  v5[43] = 16;
  v5[44] = 44;
  v5[45] = 52;
  v5[46] = 32;
  v5[47] = 64;
  v5[48] = 89;
  v5[49] = 45;
  v5[50] = 32;
  v5[51] = 65;
  v5[52] = 15;
  v5[53] = 34;
  v5[54] = 18;
  v5[55] = 16;
  v5[56] = 0;
  v2[0] = 123;
  v2[1] = 32;
  v2[2] = 18;
  v2[3] = 98;
  v2[4] = 119;
  v2[5] = 108;
  v2[6] = 65;
  v2[7] = 41;
  v2[8] = 124;
  v2[9] = 80;
  v2[10] = 125;
  v2[11] = 38;
  v2[12] = 124;
  v2[13] = 111;
  v2[14] = 74;
  v2[15] = 49;
  v2[16] = 83;
  v2[17] = 108;
  v2[18] = 94;
  v2[19] = 108;
  v2[20] = 84;
  v2[21] = 6;
  qmemcpy(v3, "`S,yhn _uec{", 12);
  v3[12] = 127;
  v3[13] = 119;
  v3[14] = 96;
  v3[15] = 48;
  v3[16] = 107;
  v3[17] = 71;
  v3[18] = 92;
  v3[19] = 29;
  v3[20] = 81;
  v3[21] = 107;
  v3[22] = 90;
  v3[23] = 85;
  v3[24] = 64;
  v3[25] = 12;
  v3[26] = 43;
  v3[27] = 76;
  v3[28] = 86;
  v3[29] = 13;
  v3[30] = 114;
  v3[31] = 1;
  strcpy(v4, "u~");
  for ( i = 0; i < 56; ++i )
  {
    v2[i] ^= v5[i];
    v2[i] ^= 0x13u;
  }
  return sub_45A7BE("%s\n");
}
           

exp

v2 = [123, 32, 18, 98, 119, 108, 65, 41, 124, 80, 125, 38, 124, 111,
      74, 49, 83, 108, 94, 108, 84, 6, 96, 83, 44, 121, 104, 110,
      32, 95, 117, 101, 99, 123, 127, 119, 96, 48, 107, 71, 92,
      29, 81, 107, 90, 85, 64, 12, 43, 76, 86, 13, 114, 1, 117, 126]
v5 = [18, 64, 98, 5, 2, 4, 6, 3, 6, 48, 49, 65, 32, 12,
      48, 65, 31, 78, 62, 32, 49, 32, 1, 57, 96, 3, 21, 9,
      4, 62, 3, 5, 4, 1, 2, 3, 44, 65, 78, 32, 16, 97,
      54, 16, 44, 52, 32, 64, 89, 45, 32, 65, 15, 34, 18, 16]
for i in range(56):
    v2[i] ^= v5[i]
    v2[i] ^= 0x13
print(''.join(map(chr, v2)))
           

动态调试

OD搜索字符串,来到打印flag函数处

攻防世界逆向新手区

再次搜索字符串,在输入前寻找一处跳转

攻防世界逆向新手区

修改跳转为无条件跳转到打印flag函数处

攻防世界逆向新手区

修改后直接F9运行,即可得到flag

攻防世界逆向新手区

open-source

查看源代码

#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) {  // first = 0xcafe
    	printf("you are wrong, sorry.\n");
    	exit(2);
    }

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

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

    printf("Brr wrrr grr\n");

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

    printf("Get your key: ");
    printf("%x\n", hash);  // 以16进制形式输出
    return 0;
}
           

exp

first = 0xcafe
second = 25
argv3 = 'h4cky0u'
hash = first * 31337 + (second % 17) * 11 + len(argv3) - 1615810207
print(hex(hash))
           

simple-unpack

攻防世界逆向新手区

查壳发现有UPX壳,脱壳后IDA,直接发现flag

攻防世界逆向新手区
攻防世界逆向新手区

logmein

查看main函数

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

  v9 = 0;
  strcpy(v8, ":\"AL_RT^L*.?+6/46");
  v7 = 0x65626D61726168LL;  // 小端存储,转字符串后取反,即'harambe'
  v6 = 7;
  printf("Welcome to the RC3 secure password guesser.\n");
  printf("To continue, you must enter the correct password.\n");
  printf("Enter your guess: ");
  __isoc99_scanf("%32s", s);
  v3 = strlen(s);
  if ( v3 < strlen(v8) )
    sub_4007C0();
  for ( i = 0; i < strlen(s); ++i )
  {
    if ( i >= strlen(v8) )
      sub_4007C0();
    if ( s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )  // 异或加密
      sub_4007C0();
  }
  sub_4007F0();
}
           

exp

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

no-strings-attached

静态分析

查看伪代码

void authenticate()
{
  wchar_t ws[8192]; // [esp+1Ch] [ebp-800Ch] BYREF
  wchar_t *s2; // [esp+801Ch] [ebp-Ch]

  s2 = decrypt((wchar_t *)&s, (wchar_t *)&dword_8048A90);
  if ( fgetws(ws, 0x2000, stdin) )
  {
    ws[wcslen(ws) - 1] = 0;
    if ( !wcscmp(ws, s2) )
      wprintf(&unk_8048B44);
    else
      wprintf(&unk_8048BA4);
  }
  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;  // 加密后返回flag
}
           

可以用idapy打印出两个参数

addr = 0x8048A90 # 数组地址
arr = []
for i in range(6):
    arr.append(Dword(addr + 4 * i))
print(arr)
           

另一个参数也是一样打印

exp

dword_8048A90 = [5121, 5122, 5123, 5124, 5125]
dest = [5178, 5174, 5175, 5179, 5248, 5242, 5233, 5240, 5219, 5222, 5235, 5223, 5218, 5221, 5235, 5216, 5227, 5233, 5240,
        5226, 5235, 5232, 5220, 5240, 5230, 5232, 5232, 5220, 5232, 5220, 5230, 5243, 5238, 5240, 5226, 5235, 5243, 5248]
for i in range(len(dest)):
    dest[i] -= dword_8048A90[i % 5]
print(''.join(map(chr, dest)))
           

动态调试

查看

authenticate()

的汇编代码

0x8048708                 push    ebp
0x8048709                 mov     ebp, esp
0x804870B                 sub     esp, 8028h
0x8048711                 mov     dword ptr [esp+4], offset dword_8048A90
0x8048719                 mov     dword ptr [esp], offset s
0x8048720                 call    decrypt
0x8048725                 mov     [ebp+s2], eax
           

用gdb调试,在返回flag后处断点,打印存放flag的eax值

chmod +x 文件名
gdb 文件名
b *0x8048725
r
x/50wx $eax
           
攻防世界逆向新手区

得到

393434377b796f755f6172655f616e5f696e7465726e6174696f6e616c5f6d7973746572797d

转字符串后即可得到flag

getit

静态分析

反编译代码

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

  v9 = __readfsqword(0x28u);
  for ( i = 0; i < strlen(s); ++i )  // 对s进行加密作为flag一部分
  {
    if ( (i & 1) != 0 )
      v3 = 1;
    else
      v3 = -1;
    *(&t + i + 10) = s[i] + v3;
  }
  strcpy(filename, "/tmp/flag.txt");
  stream = fopen(filename, "w");
  fprintf(stream, "%s\n", u);
  for ( j = 0; j < strlen(&t); ++j )  // 加密后存放在文件中
  {
    fseek(stream, p[j], 0);
    fputc(*(&t + p[j]), stream);
    fseek(stream, 0LL, 0);
    fprintf(stream, "%s\n", u);
  }
  fclose(stream);
  remove(filename);  // 删掉文件
  return 0;
}
           
攻防世界逆向新手区

exp

s = 'c61b68366edeb7bdce3c6820314b7498'
flag = 'SharifCTF{'

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

动态调试

这个程序大意是在/tmp/flag.txt里写flag,然后又删掉了,我们可以通过gdb把它断住,然后查看flag

在0x400832处下断点然后执行

攻防世界逆向新手区

csaw2013reversing2

打开程序是乱码,查看反编译代码

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, SourceSize + 1);
  memcpy_s(lpMem, SourceSize, &unk_409B10, SourceSize);
  if ( !sub_40102A() && !IsDebuggerPresent() )
  {
    MessageBoxA(0, lpMem + 1, "Flag", 2u);
    HeapFree(hHeap, 0, lpMem);
    HeapDestroy(hHeap);
    ExitProcess(0);
  }
  __debugbreak();  // 中断程序
  sub_401000(v3 + 4, (int)lpMem);  // 解码flag
  ExitProcess(0xFFFFFFFF);
}
           
攻防世界逆向新手区

flag需要经过解码后才能显现

用OD执行程序到断点,nop掉中断

攻防世界逆向新手区

继续执行,在接下来一个跳转修改跳转到解码函数

攻防世界逆向新手区

修改后执行,flag出现

攻防世界逆向新手区

maze

反编译代码

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

  v10[0] = 0;  // 起点
  v9 = 0;
  puts("Input flag:");
  scanf("%s", &s1);
  if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v3 = 5LL;
  if ( strlen(&s1) - 1 > 5 )
  {
    while ( 1 )
    {
      v4 = *(&s1 + v3);
      v5 = 0;
      if ( v4 > 'N' )
      {
        if ( (unsigned __int8)v4 == 'O' )
        {
          v6 = sub_400650(v10);
          goto LABEL_14;
        }
        if ( (unsigned __int8)v4 == 'o' )
        {
          v6 = sub_400660(v10);
          goto LABEL_14;
        }
      }
      else
      {
        if ( (unsigned __int8)v4 == '.' )
        {
          v6 = sub_400670(&v9);
          goto LABEL_14;
        }
        if ( (unsigned __int8)v4 == '0' )
        {
          v6 = sub_400680(&v9);
LABEL_14:
          v5 = v6;
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)sub_400690((__int64)asc_601060, v10[0], v9) )  // 必须走' '
        goto LABEL_22;
      if ( ++v3 >= strlen(&s1) - 1 )
      {
        if ( v5 )
          break;
LABEL_20:
        v7 = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( asc_601060[8 * v9 + v10[0]] != '#' )  // 当走到'#'算走出迷宫
    goto LABEL_20;
  v7 = "Congratulations!";
LABEL_21:
  puts(v7);
  return 0LL;
}
           
攻防世界逆向新手区

迷宫是一个8x8的二维数组

打印迷宫

a = '  *******   *  **** * ****  * ***  *#  *** *** ***     *********'
for i in range(8):
    for j in range(8):
        print(a[8 * i + j], end='')
    print('')
           
攻防世界逆向新手区
  • ⬅️:O
  • ➡️:o
  • ⬆️:.
  • ⬇️:0

迷宫顺序:➡️⬇️➡️➡️⬇️⬇️⬅️⬇️⬇️⬇️➡️➡️➡️➡️⬆️⬆️⬅️⬅️

对应的值:

o0oo00O000oooo..OO

flag:

nctf{o0oo00O000oooo..OO}