BUUCTF--crackMe

测试文件:https://www.lanzous.com/iaxqvbg

代码分析

 1 int __usercall wmain@<eax>(int a1@<ebx>)
 2 {
 3   FILE *v1; // eax
 4   FILE *v2; // eax
 5   char v4; // [esp+3h] [ebp-405h]
 6   char v5; // [esp+4h] [ebp-404h]
 7   char v6; // [esp+5h] [ebp-403h]
 8   char v7; // [esp+104h] [ebp-304h]
 9   char v8; // [esp+105h] [ebp-303h]
10   char v9; // [esp+204h] [ebp-204h]
11   char v10; // [esp+205h] [ebp-203h]
12   char v11; // [esp+304h] [ebp-104h]
13   char v12; // [esp+305h] [ebp-103h]
14 
15   printf("Come one! Crack Me~~~\n");
16   v11 = 0;                                      // user
17   memset(&v12, 0, 0xFFu);
18   v9 = 0;                                       // password
19   memset(&v10, 0, 0xFFu);
20   while ( 1 )
21   {
22     do
23     {
24       do
25       {
26         printf("user(6-16 letters or numbers):");
27         scanf("%s", &v11);
28         v1 = (FILE *)file_ptr();                // 文件流指针
29         fflush(v1);                             // 更新缓存
30       }
31       while ( !check_len_str(&v11) );           // 判断输入长度和类型是否符合要求
32       printf("password(6-16 letters or numbers):");
33       scanf("%s", &v9);
34       v2 = (FILE *)file_ptr();
35       fflush(v2);
36     }
37     while ( !check_len_str(&v9) );
38     sub_401090(&v11);
39     v7 = 0;
40     memset(&v8, 0, 0xFFu);
41     v5 = 0;
42     memset(&v6, 0, 0xFFu);
43     v4 = ((int (__cdecl *)(char *, char *))loc_4011A0)(&v7, &v5);
44     if ( sub_401830(a1, (int)&v11, &v9) )
45     {
46       if ( v4 )
47         break;
48     }
49     printf(&v5);
50   }
51   printf(&v7);
52   return 0;
53 }

前面的代码不需要说什么,主要分析sub_401830函数,应该是需要我们返回True的

 1 bool __usercall sub_401830@<al>(int ebx0@<ebx>, int a1, const char *a2)
 2 {
 3   int v4; // [esp+18h] [ebp-22Ch]
 4   signed int v5; // [esp+1Ch] [ebp-228h]
 5   signed int v6; // [esp+28h] [ebp-21Ch]
 6   unsigned int v7; // [esp+30h] [ebp-214h]
 7   char v8; // [esp+36h] [ebp-20Eh]
 8   char v9; // [esp+37h] [ebp-20Dh]
 9   char v10; // [esp+38h] [ebp-20Ch]
10   unsigned __int8 v11; // [esp+39h] [ebp-20Bh]
11   unsigned __int8 v12; // [esp+3Ah] [ebp-20Ah]
12   char v13; // [esp+3Bh] [ebp-209h]
13   int v14; // [esp+3Ch] [ebp-208h]
14   char v15; // [esp+40h] [ebp-204h]
15   char v16; // [esp+41h] [ebp-203h]
16   char v17; // [esp+140h] [ebp-104h]
17   char v18; // [esp+141h] [ebp-103h]
18 
19   v5 = 0;
20   v6 = 0;
21   v12 = 0;
22   v11 = 0;
23   v17 = 0;
24   memset(&v18, 0, 0xFFu);
25   v15 = 0;
26   memset(&v16, 0, 0xFFu);
27   v10 = 0;
28   v7 = 0;
29   v4 = 0;
30   while ( v7 < strlen(a2) )
31   {
32     if ( isdigit(a2[v7]) )                      // 判断密码是不是数字
33     {
34       v9 = a2[v7] - 48;                         // 字符转整型
35     }
36     else if ( isxdigit(a2[v7]) )                // 检测是否为16进制数字
37     {
38       if ( *(_DWORD *)(*(_DWORD *)(__readfsdword(0x30u) + 24) + 12) != 2 )
39         a2[v7] = 34;
40       v9 = (a2[v7] | 0x20) - 87;                // 转为整型数字
41     }
42     else
43     {
44       v9 = ((a2[v7] | 0x20) - 97) % 6 + 10;     // 按照字母次序,6个一组,对应10~15
45     }
46     v10 = v9 + 16 * v10;
47     if ( !((signed int)(v7 + 1) % 2) )
48     {
49       *(&v15 + v4++) = v10;                     // 存储a2偶数位变换后v9的值
50       ebx0 = v4;
51       v10 = 0;
52     }
53     ++v7;
54   }
55   while ( v6 < 8 )                              // 进行某种变换
56   {
57     v11 += byte_416050[++v12];
58     v13 = byte_416050[v12];
59     v8 = byte_416050[v11];
60     byte_416050[v11] = v13;
61     byte_416050[v12] = v8;
62     if ( *(_DWORD *)(__readfsdword(0x30u) + 104) & 0x70 )
63       v13 = v11 + v12;
64     *(&v17 + v6) = byte_416050[(unsigned __int8)(v8 + v13)] ^ *(&v15 + v5);// v17的生成,通过byte_416050和v15异或
65     if ( *(_DWORD *)(__readfsdword(0x30u) + 2) & 0xFF )
66     {
67       v11 = -83;
68       v12 = 43;
69     }
70     sub_401710((int)&v17, (const char *)a1, v6++);
71     v5 = v6;
72     if ( v6 >= (unsigned int)(&v15 + strlen(&v15) + 1 - &v16) )
73       v5 = 0;
74   }
75   v14 = 0;
76   sub_401470(ebx0, &v17, &v14);
77   return v14 == 43924;
78 }

整体这个函数我们可以分成三部分

  1. 代码第30~54行,将字符串密码转换为两两组合的整型。
  2. 代码第55~74行,生成v17数组
  3. 代码第75~77行,传入v17数组和v14=0,返回的v14需要等于43924

第三部分

我们能够反过来推倒,首先查看sub_401470函数

_DWORD *__usercall sub_401470@<eax>(int a1@<ebx>, _BYTE *a2, _DWORD *a3)
{
  int v3; // ST28_4
  int v4; // ecx
  _DWORD *_EAX; // eax
  int v6; // edx
  int v8; // ST20_4
  int v9; // eax
  int v10; // edi
  int v11; // ST1C_4
  int v12; // edx
  char v13; // di
  int v14; // ST18_4
  int v15; // eax
  int v16; // ST14_4
  int v17; // edx
  char v18; // al
  int v19; // ST10_4
  int v20; // ecx
  char _AL; // al
  int v23; // ST0C_4
  int v24; // eax
  _DWORD *result; // eax
  int v26; // edx

  if ( *a2 == 'd' )
  {
    *a3 |= 4u;
    v4 = *a3;
  }
  else
  {
    *a3 ^= 3u;
  }
  v3 = *a3;
  if ( a2[1] == 'b' )
  {
    _EAX = a3;
    *a3 |= 0x14u;
    v6 = *a3;
  }
  else
  {
    *a3 &= 0x61u;
    _EAX = (_DWORD *)*a3;
  }
  __asm { aam }
  if ( a2[2] == 'a' )
  {
    *a3 |= 0x84u;
    v9 = *a3;
  }
  else
  {
    *a3 &= 0xAu;
  }
  v8 = *a3;
  v10 = ~(a1 >> -91);
  if ( a2[3] == 'p' )
  {
    *a3 |= 0x114u;
    v12 = *a3;
  }
  else
  {
    *a3 >>= 7;
  }
  v11 = *a3;
  v13 = v10 - 1;
  if ( a2[4] == 'p' )
  {
    *a3 |= 0x380u;
    v15 = *a3;
  }
  else
  {
    *a3 *= 2;
  }
  v14 = *a3;
  if ( *(_DWORD *)(*(_DWORD *)(__readfsdword(0x30u) + 24) + 12) != 2 )
  {
    if ( a2[5] == 'f' )
    {
      *a3 |= 0x2DCu;
      v17 = *a3;
    }
    else
    {
      *a3 |= 0x21u;
    }
    v16 = *a3;
  }
  if ( a2[5] == 's' )
  {
    *a3 |= 0xA04u;
    v18 = (char)a3;
    v20 = *a3;
  }
  else
  {
    v18 = (char)a3;
    *a3 ^= 0x1ADu;
  }
  v19 = *a3;
  _AL = v18 - v13;
  __asm { daa }
  if ( a2[6] == 'e' )
  {
    *a3 |= 0x2310u;
    v24 = *a3;
  }
  else
  {
    *a3 |= 0x4Au;
  }
  v23 = *a3;
  if ( a2[7] == 'c' )
  {
    result = a3;
    *a3 |= 0x8A10u;
    v26 = *a3;
  }
  else
  {
    *a3 &= 0x3A3u;
    result = (_DWORD *)*a3;
  }
  return result;
}

应该是需要我们满足其中的每一个条件,因此得到v17的值"dbappsec"

第二部分

有了v17的值,我们知道第二部分代码第64行,通过byte_416050与变换后的密码异或得到v17。我们已知账号为welcomebeijing,求密码。因此我们需要通过动态调试,获取byte_416050的值

记录下byte_416050的值为

0x2a, 0xd7, 0x92, 0xe9, 0x53, 0xe2, 0xc4, 0xcd

第一部分

变换后的密码格式为两两组成的十六进制

脚本

# -*- coding:utf-8 -*-
import hashlib

box = [0x2a, 0xd7, 0x92, 0xe9, 0x53, 0xe2, 0xc4, 0xcd]
s = "dbappsec"

secret = []

for i in range(len(s)):
    secret.append(hex(ord(s[i])^box[i]).replace("0x",''))
flag = ''.join(secret)
md = hashlib.md5()
md.update(flag.encode('utf-8'))
print ("flag{"+md.hexdigest()+"}")

get flag!

flag{d2be2981b84f2a905669995873d6a36c}

猜你喜欢

转载自www.cnblogs.com/Mayfly-nymph/p/12624018.html