BUUCTF reverse:刮开有奖

1.查壳
BUUCTF reverse:刮开有奖_第1张图片无壳
32位文件
2.IDA分析
找到关键的函数,然后F5反编译
在这里插入图片描述

BOOL __userpurge DialogFunc@<eax>(int a1@<edi>, int a2@<esi>, HWND hDlg, UINT a4, WPARAM a5, LPARAM a6)
{
  const char *v6; // esi
  const char *v7; // edi
  int v9; // [esp+4h] [ebp-20030h]
  int v10; // [esp+8h] [ebp-2002Ch]
  int v11; // [esp+Ch] [ebp-20028h]
  int v12; // [esp+10h] [ebp-20024h]
  int v13; // [esp+14h] [ebp-20020h]
  int v14; // [esp+18h] [ebp-2001Ch]
  int v15; // [esp+1Ch] [ebp-20018h]
  int v16; // [esp+20h] [ebp-20014h]
  int v17; // [esp+24h] [ebp-20010h]
  int v18; // [esp+28h] [ebp-2000Ch]
  int v19; // [esp+2Ch] [ebp-20008h]
  CHAR String; // [esp+30h] [ebp-20004h]
  char v21; // [esp+31h] [ebp-20003h]
  char v22; // [esp+32h] [ebp-20002h]
  char v23; // [esp+33h] [ebp-20001h]
  char v24; // [esp+34h] [ebp-20000h]
  char v25; // [esp+10030h] [ebp-10004h]
  char v26; // [esp+10031h] [ebp-10003h]
  char v27; // [esp+10032h] [ebp-10002h]
  int v28; // [esp+20028h] [ebp-Ch]
  int v29; // [esp+2002Ch] [ebp-8h]

  __alloca_probe();
  if ( a4 == 272 )
    return 1;
  v29 = a2;
  v28 = a1;
  if ( a4 != 273 )
    return 0;
  if ( (_WORD)a5 == 1001 )
  {
    memset(&String, 0, 0xFFFFu);
    GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);
    if ( strlen(&String) == 8 )
    {
      v9 = 90;
      v10 = 74;
      v11 = 83;
      v12 = 69;
      v13 = 67;
      v14 = 97;
      v15 = 78;
      v16 = 72;
      v17 = 51;
      v18 = 110;
      v19 = 103;
      sub_4010F0(&v9, 0, 10);
      memset(&v25, 0, 0xFFFFu);
      v6 = (const char *)sub_401000(&v25, strlen(&v25));
      memset(&v25, 0, 0xFFFFu);
      v26 = v23;
      v25 = v22;
      v27 = v24;
      v7 = (const char *)sub_401000(&v25, strlen(&v25));
      if ( String == v9 + 34
        && v21 == v13
        && 4 * v22 - 141 == 3 * v11
        && v23 / 4 == 2 * (v16 / 9)
        && !strcmp(v6, "ak1w")
        && !strcmp(v7, "V1Ax") )
      {
        MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
      }
    }
    return 0;
  }
  if ( (_WORD)a5 != 1 && (_WORD)a5 != 2 )
    return 0;
  EndDialog(hDlg, (unsigned __int16)a5);
  return 1;
}
GetDlgItemTextA(hDlg, 1000, &String, 0xFFFF);

这一行接收我们输入的flag

 sub_4010F0(&v9, 0, 10);

这一行对v9-v19做某种处理,双击sub_4010F0查看函数

int __cdecl sub_4010F0(int a1, int a2, int a3)
{
  int result; // eax
  int i; // esi
  int v5; // ecx
  int v6; // edx

  result = a3;
  for ( i = a2; i <= a3; a2 = i )
  {
    v5 = 4 * i;
    v6 = *(_DWORD *)(4 * i + a1);
    if ( a2 < result && i < result )
    {
      do
      {
        if ( v6 > *(_DWORD *)(a1 + 4 * result) )
        {
          if ( i >= result )
            break;
          ++i;
          *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
          if ( i >= result )
            break;
          while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
          {
            if ( ++i >= result )
              goto LABEL_13;
          }
          if ( i >= result )
            break;
          v5 = 4 * i;
          *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
        }
        --result;
      }
      while ( i < result );
    }
LABEL_13:
    *(_DWORD *)(a1 + 4 * result) = v6;
    sub_4010F0(a1, a2, i - 1);
    result = a3;
    ++i;
  }
  return result;
}

为了知道这个函数对v9-v19做出了怎样的处理,我们需要修改伪代码,使其变成可执行的代码

#include 
#include 
int  sub_4010F0(char*a1, int a2, int a3)
{
  int result; // eax
  int i; // esi
  int v5; // ecx
  int v6; // edx

  result = a3;
  for ( i = a2; i <= a3; a2 = i )
  {
    v5 = i;
    v6 = a1[i];
    if ( a2 < result && i < result )
    {
      do
      {
        if ( v6 > a1[result] )
        {
          if ( i >= result )
            break;
          ++i;
          a1[v5]= a1[result];
          if ( i >= result )
            break;
          while ( a1[i] <= v6 )
          {
            if ( ++i >= result )
              goto LABEL_13;
          }
          if ( i >= result )
            break;
          v5 = i;
          a1[result] = a1[i];
        }
        --result;
      }
      while ( i < result );
    }
   LABEL_13:
    a1[result]= v6;
    sub_4010F0(a1, a2, i - 1);
    result = a3;
    ++i;
  }
  return result;
}
int main()
{
    char s[]="ZJSECaNH3ng";
    printf("%s",s\n);
    sub_4010F0(s,0,10);
    printf("%s",s);
    return 0;
}

运行结果为:

ZJSECaNH3ng
3CEHJNSZagn

分析完sub_4010F0函数后,继续往下分析代码

v6 = (const char *)sub_401000(&v25, strlen(&v25));

我们又发现了sub_401000函数,双击进入查看

_BYTE *__cdecl sub_401000(int a1, int a2)
{
  int v2; // eax
  int v3; // esi
  size_t v4; // ebx
  _BYTE *v5; // eax
  _BYTE *v6; // edi
  int v7; // eax
  _BYTE *v8; // ebx
  int v9; // edi
  signed int v10; // edx
  int v11; // edi
  signed int v12; // eax
  signed int v13; // esi
  _BYTE *result; // eax
  _BYTE *v15; // [esp+Ch] [ebp-10h]
  _BYTE *v16; // [esp+10h] [ebp-Ch]
  int v17; // [esp+14h] [ebp-8h]
  int v18; // [esp+18h] [ebp-4h]

  v2 = a2 / 3;
  v3 = 0;
  if ( a2 % 3 > 0 )
    ++v2;
  v4 = 4 * v2 + 1;
  v5 = malloc(v4);
  v6 = v5;
  v15 = v5;
  if ( !v5 )
    exit(0);
  memset(v5, 0, v4);
  v7 = a2;
  v8 = v6;
  v16 = v6;
  if ( a2 > 0 )
  {
    while ( 1 )
    {
      v9 = 0;
      v10 = 0;
      v18 = 0;
      do
      {
        if ( v3 >= v7 )
          break;
        ++v10;
        v9 = *(unsigned __int8 *)(v3++ + a1) | (v9 << 8);
      }
      while ( v10 < 3 );
      v11 = v9 << 8 * (3 - v10);
      v12 = 0;
      v17 = v3;
      v13 = 18;
      do
      {
        if ( v10 >= v12 )
        {
          *((_BYTE *)&v18 + v12) = (v11 >> v13) & 0x3F;
          v8 = v16;
        }
        else
        {
          *((_BYTE *)&v18 + v12) = 64;
        }
        *v8++ = byte_407830[*((char *)&v18 + v12)];
        v13 -= 6;
        ++v12;
        v16 = v8;
      }
      while ( v13 > -6 );
      v3 = v17;
      if ( v17 >= a2 )
        break;
      v7 = a2;
    }
    v6 = v15;
  }
  result = v6;
  *v8 = 0;
  return result;
}

又是巨大的代码量,令人头大
发现了一个数据byte_407830,双击进入
在这里插入图片描述
看到这熟悉的字符,立刻联想到base64编码

if ( String == v9 + 34
        && v21 == v13
        && 4 * v22 - 141 == 3 * v11
        && v23 / 4 == 2 * (v16 / 9)
        && !strcmp(v6, "ak1w")
        && !strcmp(v7, "V1Ax") )

这一块代码是对于flag的值的判断
v6要与"ak1w"相等,v7要与"V1Ax"相等

v6 = (const char *)sub_401000(&v25, strlen(&v25));
v7 = (const char *)sub_401000(&v25, strlen(&v25));

v6和v7都是经过base64编码后的字符串,所以我们分别对ak1wV1Ax进行解码即可,分别为jMpWP1

.text:0040123D                 mov     [ebp+var_20030], 'Z'
.text:00401247                 mov     [ebp+var_2002C], 'J'
.text:00401251                 mov     [ebp+var_20028], 'S'
.text:0040125B                 mov     [ebp+var_20024], 'E'
.text:00401265                 mov     [ebp+var_20020], 'C'
.text:0040126F                 mov     [ebp+var_2001C], 'a'
.text:00401279                 mov     [ebp+var_20018], 'N'
.text:00401283                 mov     [ebp+var_20014], 'H'
.text:0040128D                 mov     [ebp+var_20010], '3'
.text:00401297                 mov     [ebp+var_2000C], 'n'
.text:004012A1                 mov     [ebp+var_20008], 'g'
.text:004012AB                 call    sub_4010F0
.text:004012B0                 push    0FFFFh          ; size_t
.text:004012B5                 lea     edx, [ebp+var_10004]
.text:004012BB                 push    0               ; int
.text:004012BD                 push    edx             ; void *
.text:004012BE                 call    _memset
**.text:004012C3                 mov     al, [ebp+var_1FFFF]
**.text:004012C9                 mov     dl, [ebp+var_1FFFD]**
**.text:004012CF                 mov     cl, [ebp+var_1FFFE]****
.text:004012D5                 mov     [ebp+var_10004], al
.text:004012DB                 lea     eax, [ebp+var_10004]
.text:004012E1                 mov     [ebp+var_10002], dl
.text:004012E7                 add     esp, 18h
.text:004012EA                 mov     [ebp+var_10003], cl
.text:004012F0                 lea     edx, [eax+1]
.text:004012F3
.text:004012F3 loc_4012F3:                             ; CODE XREF: DialogFunc+158↓j
.text:004012F3                 mov     cl, [eax]
.text:004012F5                 inc     eax
.text:004012F6                 test    cl, cl
.text:004012F8                 jnz     short loc_4012F3
.text:004012FA                 sub     eax, edx
.text:004012FC                 push    eax
.text:004012FD                 lea     eax, [ebp+var_10004]
.text:00401303                 push    eax
.text:00401304                 call    sub_401000
.text:00401309                 push    0FFFFh          ; size_t
.text:0040130E                 lea     ecx, [ebp+var_10004]
.text:00401314                 push    0               ; int
.text:00401316                 push    ecx             ; void *
.text:00401317                 mov     esi, eax
.text:00401319                 call    _memset
**.text:0040131E                 mov     al, [ebp+var_20001]**
**.text:00401324                 mov     dl, [ebp+var_20002]**
**.text:0040132A                 mov     cl, [ebp+var_20000]**
.text:00401330                 mov     [ebp+var_10003], al
.text:00401336                 lea     eax, [ebp+var_10004]
.text:0040133C                 mov     [ebp+var_10004], dl
.text:00401342                 add     esp, 14h
.text:00401345                 mov     [ebp+var_10002], cl
.text:0040134B                 lea     edx, [eax+1]
.text:0040134E                 mov     edi, edi

并且可以从我打*号的代码看出,v6调用的是flag的678位,v7调用的是flag的345位

-00020004 String          db ?
-00020003 var_20003       db ?                    ; v21
-00020002 var_20002       db ?                    ; v22
-00020001 var_20001       db ?                    ; v23
-00020000 var_20000       db ?                    ; v24
-0001FFFF var_1FFFF       db ?
-0001FFFE var_1FFFE       db ?
-0001FFFD var_1FFFD       db ?
String == v9 + 34

flag的第一位要等于v9的首位加34,为U

v21 == v13

即v21为J
所以完整的flag应该为UJWP1jMp

你可能感兴趣的:(CTF)