首页
论坛
课程
招聘
[原创] 第三题另辟蹊径,暴力破解
2022-5-15 16:15 5377

[原创] 第三题另辟蹊径,暴力破解

2022-5-15 16:15
5377

逆向逻辑

  1. 首先打开IDA找到MAIN函数地址,位于4027C0,然后进行X64DBG下断点
    IDA F5如下图:
    图片描述
  2. 使用X64DBG动态调试,单步至以下地方
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    00EB2868      | 68 A00F0000              | push FA0                             |
    00EB286D      | 8D95 40F0FFFF            | lea edx,dword ptr ss:[ebp-FC0]       |
    00EB2873      | 52                       | push edx                             |
    00EB2874      | FF15 88C1EB00            | call dword ptr ds:[<&gets_s>]        |
    00EB287A      | 83C4 08                  | add esp,8                            |
    00EB287D      | 3BF4                     | cmp esi,esp                          |
    00EB287F      | E8 F8E8FFFF              | call duplicity.EB117C                |
    00EB2884      | 8D85 40F0FFFF            | lea eax,dword ptr ss:[ebp-FC0]       |
    00EB288A      | 50                       | push eax                             |
    00EB288B      | E8 793E0000              | call <JMP.&strlen>                   |
    00EB2890      | 83C4 04                  | add esp,4                            |
    00EB2893      | 83F8 20                  | cmp eax,20                           | 20:' '
    00EB2896      | 74 14                    | je duplicity.EB28AC                  |
    00EB2898      | 68 608BEB00              | push duplicity.EB8B60                | EB8B60:"NO\n"
    00EB289D      | E8 95E7FFFF              | call duplicity.EB1037                |
    00EB28A2      | 83C4 04                  | add esp,4                            |
    00EB28A5      | 33C0                     | xor eax,eax                          |
    00EB28A7      | E9 86010000              | jmp duplicity.EB2A32                 |
    逻辑很清晰,就是输入字符串, 要求长度等于 0x20, 不等于就退出打印 NO
  3. 输入 12345678901234567890123456789012 满足上面的条件后进行往下,代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    00EB28B8      | 8B8D 08F0FFFF            | mov ecx,dword ptr ss:[ebp-FF8]       |
    00EB28BE      | 83C1 01                  | add ecx,1                            | ecx:"12345678901234567890123456789012"
    00EB28C1      | 898D 08F0FFFF            | mov dword ptr ss:[ebp-FF8],ecx       |
    00EB28C7      | 81BD 08F0FFFF 00020000   | cmp dword ptr ss:[ebp-FF8],200       |
    00EB28D1      | 7D 3A                    | jge duplicity.EB290D                 |
    00EB28D3      | C745 FC 00000000         | mov dword ptr ss:[ebp-4],0           |
    00EB28DA      | C785 04F0FFFF 00000000   | mov dword ptr ss:[ebp-FFC],0         |
    00EB28E4      | 8B95 04F0FFFF            | mov edx,dword ptr ss:[ebp-FFC]       |
    00EB28EA      | 8A85 08F0FFFF            | mov al,byte ptr ss:[ebp-FF8]         |
    00EB28F0      | 8802                     | mov byte ptr ds:[edx],al             |
    00EB28F2      | C745 FC FEFFFFFF         | mov dword ptr ss:[ebp-4],FFFFFFFE    |
    这里,发生了异常,异常处理后EIP指向0x28EB, 然后一直异常0x200次后满足条件继续向下走
  4. 查看SEH异常链,位于 0x3650, 使用IDA f5 查看没啥特殊的,只是通过不同的异常类型来处理,直接忽略对应的异常即可
    IDA 如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    int __cdecl _filter_x86_sse2_floating_point_exception_default(int a1)
    {
    __int16 v2; // [esp+4Ch] [ebp-8h]
    __int16 v3; // [esp+50h] [ebp-4h]
     
    if ( dword_40B940 < 1 )
     return a1;
    if ( a1 != -1073741132 && a1 != -1073741131 )
     return a1;
    v2 = _mm_getcsr();
    v3 = v2 ^ 0x3F;
    if ( (((unsigned __int8)v2 ^ 0x3F) & 0x81) == 0 )
     return -1073741680;
    if ( (v3 & 0x204) == 0 )
     return -1073741682;
    if ( (v3 & 0x102) == 0 )
     return -1073741680;
    if ( (v3 & 0x408) == 0 )
     return -1073741679;
    if ( (v3 & 0x810) == 0 )
     return -1073741677;
    if ( (v3 & 0x1020) != 0 )
     return a1;
    return -1073741681;
    }
  5. 继续向下,拷贝字符串,然后再次处理异常, 直接在下面下断点即可
    1
    2
    3
    4
    5
    6
    7
    00EB2983      | 8B95 C8EFFFFF            | mov edx,dword ptr ss:[ebp-1038]      |
    00EB2989      | 83C2 01                  | add edx,1                            |
    00EB298C      | 8995 C8EFFFFF            | mov dword ptr ss:[ebp-1038],edx      |
    00EB2992      | 81BD C8EFFFFF 00020000   | cmp dword ptr ss:[ebp-1038],200      |
    00EB299C      | 7D 23                    | jge duplicity.EB29C1                 |
    00EB299E      | C745 FC 01000000         | mov dword ptr ss:[ebp-4],1           |
    00EB29A5      | 6C                       | insb                                 |
  6. 来到第一个call, 如下
    1
    2
    3
    4
    5
    6
    7
    00EB29C1      | 8D85 D0EFFFFF            | lea eax,dword ptr ss:[ebp-1030]      |
    00EB29C7      | 50                       | push eax                             |
    00EB29C8      | 6A 10                    | push 10                              |
    00EB29CA      | 8D8D ECEFFFFF            | lea ecx,dword ptr ss:[ebp-1014]      |
    00EB29D0      | 51                       | push ecx                             | ecx:"Enj0y_1t_4_fuuuN"
    00EB29D1      | E8 33E7FFFF              | call duplicity.EB1109                |
    00EB29D6      | 83C4 0C                  | add esp,C                            |
    传入了字符串 Enj0y_1t_4_fuuuN 和缓存地址,调用后 查看地址 [ebp-1030], 如下
    2F 65 B1 FF 31 ED 86 D0 9A 28 5C 0F 40 48 05 9D
    多次运行,这个值不会改变,确认为哈希算法,固定即可
  7. 继续往下走,第二个CALL 来了,如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    00EB29D6      | 83C4 0C                  | add esp,C                            |
    00EB29D9      | 6A 20                    | push 20                              |
    00EB29DB      | 8D95 10F0FFFF            | lea edx,dword ptr ss:[ebp-FF0]       |
    00EB29E1      | 52                       | push edx                             |
    00EB29E2      | 8D85 40F0FFFF            | lea eax,dword ptr ss:[ebp-FC0]       |
    00EB29E8      | 50                       | push eax                             | eax:"12345678901234567890123456789012"
    00EB29E9      | 6A 10                    | push 10                              |
    00EB29EB      | 8D8D D0EFFFFF            | lea ecx,dword ptr ss:[ebp-1030]      |
    00EB29F1      | 51                       | push ecx                             |
    00EB29F2      | E8 0DE7FFFF              | call duplicity.EB1104                |
    00EB29F7      | 83C4 14                  | add esp,14                           |
    参数从右到左是 0x20, 缓存, 传入的ctf字符串, 0x10, 上面的哈希值
    这里设传入0x20字符串为 CTF, 缓存为 TMP, 哈希值为 KEY (大小为 0x10)
    调用完成后,TMP = 以下
    1
    2
    00FBE9F0  A7 6E 92 65 70 04 CD 9D 76 9B 11 3F 7F 9A 15 62  §n.ep.Í.v..?...b 
    00FBEA00  1C DE 02 0B 7D A4 69 5A 70 9A AA 0E 08 A2 37 DB  .Þ..}¤iZp.ª..¢7Û
  8. 继续往下走, 内容如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    00EB29FA      | 6A 20                    | push 20                              |
    00EB29FC      | 68 00B2EB00              | push duplicity.EBB200                |
    00EB2A01      | 8D95 10F0FFFF            | lea edx,dword ptr ss:[ebp-FF0]       |
    00EB2A07      | 52                       | push edx                             |
    00EB2A08      | E8 C63C0000              | call <JMP.&memcmp>                   |
    00EB2A0D      | 83C4 0C                  | add esp,C                            |
    00EB2A10      | 85C0                     | test eax,eax                         |
    00EB2A12      | 75 0F                    | jne duplicity.EB2A23                 |
    00EB2A14      | 68 788BEB00              | push duplicity.EB8B78                | EB8B78:"OK\n"
    00EB2A19      | E8 19E6FFFF              | call duplicity.EB1037                |
    其中 , EBB200 指向值(设置为 R)如下
    1
    2
    00EBB200  57 7C F5 6D 56 96 77 45 B0 BD A1 C7 89 A5 AB DC  W|õmV.wE°½¡Ç.¥«Ü 
    00EBB210  F4 F2 4B FE BE F5 F5 5C 4D 30 42 0F 2B 3B E6 CB  ôòKþ¾õõ\M0B.+;æË
    也就是 R == TMP 就通过了。

梳理

我们需要达到的目标就是传入的 0x2070 (函数设为 enc)
也就是 调用 enc(key, 0x10, ctf, tmp, 0x20) 后, memcmp(tmp, R, 0x20) == 0

 

首先,第一步, key是固定的,那么有没有可能是对称的算法,直接把 ctf替换成 R的值是不是就可以破解了,
替换后,结果如下

1
2
008FEEF0  C2 E4 92 FD 54 27 C1 91 7E D9 23 3D 59 00 C9 59  Âä.ýT'Á.~Ù#=Y.ÉY 
008FEF00  19 C2 D1 89 36 03 DE 0E 52 5E 36 81 01 C4 36 2B  .ÂÑ.6.Þ.R^6.6+

这一看就不是目标,那算法肯定不是对称的或者enc不是dec算法。那么再测试一下enc算法一些规律
比如 全是 0x00,结果如下

1
2
0039EB5C  CB 55 EE 73 C0 4B C7 25 ED 81 6A 0C 9C 53 DF 36  ËUîsÀKÇ%í.j..Sß6 
0039EB6C  CB 55 EE 73 C0 4B C7 25 ED 81 6A 0C 9C 53 DF 36  ËUîsÀKÇ%í.j..Sß6

比如 0x11 4 0x22 4 0x33 4 0x44 4

1
2
0073EC5C  44 72 91 09 04 44 E6 B2 1A 9F 4D 9F 78 5B 8E C9  Dr...Dæ²..M.x[.É 
0073EC6C  44 72 91 09 04 44 E6 B2 1A 9F 4D 9F 78 5B 8E C9  Dr...Dæ²..M.x[.É

暂时只能确认每0x10进行的加密

继续逆向 enc(0x2070) 算法

首先,用IDA F5看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
int __cdecl sub_402070(void *Src, size_t Size, int a3, int a4, int a5)
{
  int j; // [esp+4h] [ebp-1C8h]
  unsigned int i; // [esp+8h] [ebp-1C4h]
  int v8[6]; // [esp+10h] [ebp-1BCh] BYREF
  int v9[11]; // [esp+28h] [ebp-1A4h] BYREF
  char *v10; // [esp+54h] [ebp-178h]
  int v11; // [esp+58h] [ebp-174h]
  char v12[360]; // [esp+60h] [ebp-16Ch] BYREF
 
  v11 = a4;
  v10 = v12;
  memset(&v9[6], 0, 16);
  memset(v9, 0, 16);
  memset(v8, 0, 16);
  if ( !Src || !a3 || !a4 )
    return -1;
  if ( Size > 0x10 )
    return -1;
  if ( a5 % 0x10u )
    return -1;
  memcpy(v9, Src, Size);
  sub_4010BE(v9, 16, v12);
  for ( i = 0; i < a5; i += 16 )
  {
    sub_401145(v8, a3);
    sub_401186(v8, v10);
    for ( j = 1; j < 10; ++j )
    {
      v10 += 16;
      sub_401172(v8);
      sub_40122B(v8);
      sub_40100F(v8);
      sub_401186(v8, v10);
    }
    sub_401172(v8);
    sub_40122B(v8);
    sub_401186(v8, v10 + 16);
    sub_40125D(v8, v11);
    v11 += 16;
    a3 += 16;
    v10 = v12;
  }
  return 0;
}

简单分析就出来,sub_4010BE 是初始化KEY的,单步如下
生成表格如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
005DE838  FF B1 65 2F D0 86 ED 31 0F 5C 28 9A 9D 05 48 40  ÿ±e/Ð.í1.\(...H@ 
005DE848  F6 EF 0E 7C 26 69 E3 4D 29 35 CB D7 B4 30 83 97  öï.|&iãM)5Ë×´0.
005DE858  7E 62 0A 92 58 0B E9 DF 71 3E 22 08 C5 0E A1 9F  ~b..X.éßq>".Å.¡. 
005DE868  A5 C4 A1 A4 FD CF 48 7B 8C F1 6A 73 49 FF CB EC  ¥Ä¡¤ýÏH{.ñjsIÿËì 
005DE878  6B FF B7 B3 96 30 FF C8 1A C1 95 BB 53 3E 5E 57  kÿ·³.0ÿÈ.Á.»S>^W 
005DE888  30 12 05 FB A6 22 FA 33 BC E3 6F 88 EF DD 31 DF  0..û¦"ú3¼ão.ïÝ1ß 
005DE898  AE CD C4 1C 08 EF 3E 2F B4 0C 51 A7 5B D1 60 78  ®ÍÄ..ï>/´.Q§[Ñ`x 
005DE8A8  12 F4 FA 8C 1A 1B C4 A3 AE 17 95 04 F5 C6 F5 7C  .ôú...Ä£®...õÆõ| 
005DE8B8  02 12 4E EA 18 09 8A 49 B6 1E 1F 4D 43 D8 EA 31  ..Nê...I¶..MCØê1 
005DE8C8  C5 08 2F 76 DD 01 A5 3F 6B 1F BA 72 28 C7 50 43  Å./vÝ.¥?k.ºr(ÇPC 
005DE8D8  DF 3C E9 13 02 3D 4C 2C 69 22 F6 5E 41 E5 A6 1D  ß<é..=L,i"ö^Aå¦. 
005DE8E8  DF 3C E9 13 02 3D 4C 2C 69 22 F6 5E 41 E5 A6 1D  ß<é..=L,i"ö^Aå¦. 
005DE8F8  C5 08 2F 76 DD 01 A5 3F 6B 1F BA 72 28 C7 50 43  Å./vÝ.¥?k.ºr(ÇPC 
005DE908  02 12 4E EA 18 09 8A 49 B6 1E 1F 4D 43 D8 EA 31  ..Nê...I¶..MCØê1 
005DE918  12 F4 FA 8C 1A 1B C4 A3 AE 17 95 04 F5 C6 F5 7C  .ôú...Ä£®...õÆõ| 
005DE928  AE CD C4 1C 08 EF 3E 2F B4 0C 51 A7 5B D1 60 78  ®ÍÄ..ï>/´.Q§[Ñ`x 
005DE938  30 12 05 FB A6 22 FA 33 BC E3 6F 88 EF DD 31 DF  0..û¦"ú3¼ão.ïÝ1ß 
005DE948  6B FF B7 B3 96 30 FF C8 1A C1 95 BB 53 3E 5E 57  kÿ·³.0ÿÈ.Á.»S>^W 
005DE958  A5 C4 A1 A4 FD CF 48 7B 8C F1 6A 73 49 FF CB EC  ¥Ä¡¤ýÏH{.ñjsIÿËì 
005DE968  7E 62 0A 92 58 0B E9 DF 71 3E 22 08 C5 0E A1 9F  ~b..X.éßq>".Å.¡. 
005DE978  F6 EF 0E 7C 26 69 E3 4D 29 35 CB D7 B4 30 83 97  öï.|&iãM)5Ë×´0.
005DE988  FF B1 65 2F D0 86 ED 31 0F 5C 28 9A 9D 05 48 40  ÿ±e/Ð.í1.\(...H@

这个表定义为 sbox
那么 算法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void enc(key, tmp[0x20], ctf[0x20])
{
    byte t[0x10];
    byte *sbox = ;; //  from key, 固定不需要管
    for (int i = 0; i < 2; i++)
    {
        sub_401145(t, &ctf[i * 0x10]);
        sub_401186(t, sbox);
        for (int j = 1; j < 10; j++)
        {
            sub_401172(t);
            sub_40122B(t);
            sub_40100F(t);
            sub_401186(t, &sbox[j * 0x10]);
        }
 
        sub_401172(t);
        sub_40122B(t);
        sub_401186(t, &sbox[10 * 0x10]);
        /// copy
        sub_40125D(t, t);
        t += 0x10;
    }
    /// tmp from t;
}

从算法大概看,应该就是这些算法的逆算法就可以解密了, 直接撸逆算法

sub_401145

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl sub_401500(int a1, _BYTE *a2)
{
  int j; // [esp+0h] [ebp-8h]
  int i; // [esp+4h] [ebp-4h]
 
  for ( i = 0; i < 4; ++i )
  {
    for ( j = 0; j < 4; ++j )
      *(_BYTE *)(a1 + 4 * j + i) = *a2++;
  }
  return 0;
}

看了一下就是 新坐标 0, 4, 8, 12 -> 原坐标为 0, 1, 2, 3
比如 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16
变成 01, 05, 09, 13, 02, 06, 10, 14, 03, 07, 11, 15, 04, 08, 12, 16
再次调用就回来了,算法逆算法都是同一个

sub_401186

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl sub_401970(int a1, int a2)
{
  int j; // [esp+0h] [ebp-20h]
  int i; // [esp+4h] [ebp-1Ch]
  int v5[5]; // [esp+Ch] [ebp-14h] BYREF
 
  memset(v5, 204, sizeof(v5));
  for ( i = 0; i < 4; ++i )
  {
    for ( j = 0; j < 4; ++j )
    {
      *((_BYTE *)&v5[i] + j) = *(_DWORD *)(a2 + 4 * j) >> (8 * (3 - i));
      *(_BYTE *)(a1 + 4 * i + j) ^= *((_BYTE *)&v5[i] + j);
    }
  }
  return 0;
}

对称算法,固定即可

sub_40117

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl sub_401A60(int a1)
{
  int j; // [esp+0h] [ebp-8h]
  int i; // [esp+4h] [ebp-4h]
 
  for ( i = 0; i < 4; ++i )
  {
    for ( j = 0; j < 4; ++j )
      *(_BYTE *)(a1 + 4 * i + j) = byte_40B000[*(unsigned __int8 *)(a1 + 4 * i + j)];
  }
  return 0;
}

表置换,将表置换回来即可。
目标值为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
00EBB000  63 7C 77 7B F2 6B 6F C5 30 01 67 2B FE D7 AB 76  c|w{òkoÅ0.g+þ׫v 
00EBB010  CA 82 C9 7D FA 59 47 F0 AD D4 A2 AF 9C A4 72 C0  Ê.É}úYGð.Ô¢¯.¤rÀ 
00EBB020  B7 FD 93 26 36 3F F7 CC 34 A5 E5 F1 71 D8 31 15  ·ý.&6?÷Ì4¥åñqØ1. 
00EBB030  04 C7 23 C3 18 96 05 9A 07 12 80 E2 EB 27 B2 75  #Ã.......âë'²u 
00EBB040  09 83 2C 1A 1B 6E 5A A0 52 3B D6 B3 29 E3 2F 84  ..,..nZ R;Ö³)ã/
00EBB050  53 D1 00 ED 20 FC B1 5B 6A CB BE 39 4A 4C 58 CF  SÑ.í ü±[j˾9JLXÏ 
00EBB060  D0 EF AA FB 43 4D 33 85 45 F9 02 7F 50 3C 9F A8  ÐïªûCM3.Eù..P<.¨ 
00EBB070  51 0A 40 8F 92 9D 38 F5 BC B6 DA 21 10 FF F3 D2  Q.@...8õ¼¶Ú!.ÿóÒ 
00EBB080  CD 0C 13 EC 5F 97 44 17 C4 A7 7E 3D 64 5D 19 73  Í..ì_.D.ħ~=d].s 
00EBB090  60 81 4F DC 22 2A 90 88 46 EE B8 14 DE 5E 0B DB  `.OÜ"*..Fî¸.Þ^.Û 
00EBB0A0  E0 32 3A A3 49 06 24 5C C2 D3 AC 62 91 95 E4 79  à2:£I.$\ÂÓ¬b..äy 
00EBB0B0  E7 C8 37 6D 8D D5 4E A9 6C 56 F4 EA 65 7A AE 08  çÈ7m.ÕN©lVôêez®. 
00EBB0C0  BA 78 25 2E 1C A6 B4 C6 E8 DD 74 1F 4B BD 8B 8A  ºx%..¦´ÆèÝt.K½.. 
00EBB0D0  70 3E B5 66 48 03 F6 0E 61 35 57 B9 86 C1 1D 9E  p>µfH.ö.a5W¹.Á.. 
00EBB0E0  E1 F8 98 11 69 D9 8E 94 9B 1E 87 E9 CE 55 28 DF  áø..iÙ.....éÎU(ß 
00EBB0F0  8C A1 89 0D BF E6 42 68 41 99 2D 0F B0 54 BB 16  .¡..¿æBhA.-.°T».

得到置换表(循环遍历表,每个值就是新表坐标,当前坐标为值)如下:

1
2
for (int i = 0; i < 0x100; i++)
    cbox[dbox[i]] = i;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned char cbox[256] = {
    0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0x71, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
    0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
    0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
    0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
    0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
    0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
    0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
    0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
    0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
    0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
    0x47, 0xF1, 0x1A, 0xA3, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
    0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
    0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
    0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
    0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
    0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};

sub_40122B

无法F5, 单步即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
00EB1B5D      | 8B55 C8                  | mov edx,dword ptr ss:[ebp-38]                                                          |
00EB1B60      | 8B45 08                  | mov eax,dword ptr ss:[ebp+8]                                                           |
00EB1B63      | 8D0C90                   | lea ecx,dword ptr ds:[eax+edx*4]                                                       |
00EB1B66      | BA 01000000              | mov edx,1                                                                              |
00EB1B6B      | 6BC2 00                  | imul eax,edx,0                                                                         |
00EB1B6E      | 0FB60C01                 | movzx ecx,byte ptr ds:[ecx+eax]                                                        |
00EB1B72      | 81E1 FF000000            | and ecx,FF                                                                             |
00EB1B78      | C1E1 18                  | shl ecx,18                                                                             |
00EB1B7B      | 8B55 C8                  | mov edx,dword ptr ss:[ebp-38]                                                          |
00EB1B7E      | 8B45 08                  | mov eax,dword ptr ss:[ebp+8]                                                           |
00EB1B81      | 8D1490                   | lea edx,dword ptr ds:[eax+edx*4]                                                       |
00EB1B84      | B8 01000000              | mov eax,1                                                                              |
00EB1B89      | C1E0 00                  | shl eax,0                                                                              |
00EB1B8C      | 0FB61402                 | movzx edx,byte ptr ds:[edx+eax]                                                        |
00EB1B90      | 81E2 FF000000            | and edx,FF                                                                             |
00EB1B96      | C1E2 10                  | shl edx,10                                                                             |
00EB1B99      | 0BCA                     | or ecx,edx                                                                             |
00EB1B9B      | 8B45 C8                  | mov eax,dword ptr ss:[ebp-38]                                                          |
00EB1B9E      | 8B55 08                  | mov edx,dword ptr ss:[ebp+8]                                                           |
00EB1BA1      | 8D0482                   | lea eax,dword ptr ds:[edx+eax*4]                                                       |
00EB1BA4      | BA 01000000              | mov edx,1                                                                              |
00EB1BA9      | D1E2                     | shl edx,1                                                                              |
00EB1BAB      | 0FB60410                 | movzx eax,byte ptr ds:[eax+edx]                                                        |
00EB1BAF      | 25 FF000000              | and eax,FF                                                                             |
00EB1BB4      | C1E0 08                  | shl eax,8                                                                              |
00EB1BB7      | 0BC8                     | or ecx,eax                                                                             |
00EB1BB9      | 8B55 C8                  | mov edx,dword ptr ss:[ebp-38]                                                          |
00EB1BBC      | 8B45 08                  | mov eax,dword ptr ss:[ebp+8]                                                           |
00EB1BBF      | 8D1490                   | lea edx,dword ptr ds:[eax+edx*4]                                                       |
00EB1BC2      | B8 01000000              | mov eax,1                                                                              |
00EB1BC7      | 6BC0 03                  | imul eax,eax,3                                                                         |
00EB1BCA      | 0FB61402                 | movzx edx,byte ptr ds:[edx+eax]                                                        |
00EB1BCE      | 81E2 FF000000            | and edx,FF                                                                             |
00EB1BD4      | 0BCA                     | or ecx,edx                                                                             |
00EB1BD6      | 8B45 C8                  | mov eax,dword ptr ss:[ebp-38]                                                          |
00EB1BD9      | 894C85 D0                | mov dword ptr ss:[ebp+eax*4-30],ecx                                                    |
00EB1BDD      | 33C9                     | xor ecx,ecx                                                                            |

就是取每四个字节进行移动, 逆向算法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void sub_40122b_cc(unsigned char* a1)
{
    /// 0
    /// 1
    unsigned tmp = a1[4];
    for (int i = 0; i < 3; i++)
    {
        a1[4 + i] = a1[5 + i];
    }
    a1[7] = tmp;
    /// 2
    tmp = a1[8];
    a1[8] = a1[10];
    a1[10] = tmp;
    tmp = a1[9];
    a1[9] = a1[11];
    a1[11] = tmp;
    /// 3
    tmp = a1[15];
    for (int i = 0; i < 3; i++)
    {
        a1[15 - i] = a1[14 - i];
    }
    a1[12] = tmp;
}

sub_40100F

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
unsigned char __cdecl sub_401D50(unsigned __int8 a1, unsigned char a2)
{
    int v3; // [esp+10h] [ebp-24h]
    int i; // [esp+14h] [ebp-20h]
    unsigned char v5; // [esp+1Bh] [ebp-19h]
 
    v5 = 0;
    for (i = 0; i < 8; ++i)
    {
        if ((a1 & 1) != 0)
            v5 ^= a2;
        v3 = a2 & 0x80;
        a2 *= 2;
        if (v3)
            a2 ^= 0x1Bu;
        a1 >>= 1;
    }
    return v5;
}
void sub_40100f(unsigned char* a1)
{
    unsigned char v1; // bl
    unsigned char v2; // bl
    unsigned char v3; // bl
    unsigned char v4; // bl
    int m; // [esp+Ch] [ebp-40h]
    int k; // [esp+10h] [ebp-3Ch]
    int j; // [esp+14h] [ebp-38h]
    int i; // [esp+18h] [ebp-34h]
    unsigned char v9[44]; // [esp+20h] [ebp-2Ch] BYREF
 
    v9[0] = 2;
    v9[1] = 3;
    v9[2] = 1;
    v9[3] = 1;
    v9[4] = 1;
    v9[5] = 2;
    v9[6] = 3;
    v9[7] = 1;
    v9[8] = 1;
    v9[9] = 1;
    v9[10] = 2;
    v9[11] = 3;
    v9[12] = 3;
    v9[13] = 1;
    v9[14] = 1;
    v9[15] = 2;
    for (i = 0; i < 4; ++i)
    {
        for (j = 0; j < 4; ++j)
            v9[4 * i + 24 + j] = *(unsigned char*)(a1 + 4 * i + j);
    }
    for (k = 0; k < 4; ++k)
    {
        for (m = 0; m < 4; ++m)
        {
            v1 = sub_401D50(v9[4 * k], v9[m + 24]);
            v2 = sub_401D50(v9[4 * k + 1], v9[m + 28]) ^ v1;
            v3 = sub_401D50(v9[4 * k + 2], v9[m + 32]) ^ v2;
            v4 = sub_401D50(v9[4 * k + 3], v9[m + 36]) ^ v3;
            *(unsigned char*)(a1 + 4 * k + m) = v4;
        }
    }
}

这个就比较复杂了,首先拷贝到临时变量里面
然后就是使用 0x401d50计算得到 四组 dword值再异或为 新的 一个dword, 这样计算完成组成新的十六字节
其中 sub_401D50 设为 H
那么设 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16
v1 = H(2, 01)
v2 = H(3, 05)
v3 = H(1, 09)
v4 = H(1, 13)
新的值就是 H(2, 01) ^ H(3, 05) ^ H(1, 09) ^ H(1, 13)
下一个是 H(1, 02) ^ H(2, 06) ^ H(3, 10) ^ H(1, 14)
H(1, 03) ^ H(1, 07) ^ H(2, 11) ^ H(3, 15)
H(3, 04) ^ H(1, 08) ^ H(1, 12) ^ H(2, 16)

 

那如果结果是以下
17 0A 0B 14 03 2A 2B 34 23 18 19 12 29 38 39 3A
怎么推导以上结果呢,
17 H(2, 01) ^ H(3, 05) ^ H(1, 09) ^ H(1, 13)
03 H(1, 02) ^ H(2, 06) ^ H(3, 10) ^ H(1, 14)
23 H(1, 03) ^ H(1, 07) ^ H(2, 11) ^ H(3, 15)
29 H(3, 04) ^ H(1, 08) ^ H(1, 12) ^ H(2, 16)

 

这里面肯定可以通过H算法得到移位,然后得到逆算法,这里为了赶时间,直接写出来暴力算法,其中每一个4字节是独立的, 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
void guess(unsigned char in[4], unsigned char out[4])
{  
    unsigned char v9[16];
    v9[0] = 2;
    v9[1] = 3;
    v9[2] = 1;
    v9[3] = 1;
    v9[4] = 1;
    v9[5] = 2;
    v9[6] = 3;
    v9[7] = 1;
    v9[8] = 1;
    v9[9] = 1;
    v9[10] = 2;
    v9[11] = 3;
    v9[12] = 3;
    v9[13] = 1;
    v9[14] = 1;
    v9[15] = 2;
    for (int g1 = 0; g1 <= 256; g1++)
    {
        for (int g2 = 0; g2 <= 256; g2++)
        {
            for (int g3 = 0; g3 <= 256; g3++)
            {
                unsigned char p1 = g1;
                unsigned char p2 = g2;
                unsigned char p3 = g3;
                bool show = false;
 
                //if (p1 == 0xf2 && p2 == 0x5b && p3 == 0x04)
                //    show = true;
                unsigned char p4 = sub_401D50(2, p1) ^ sub_401D50(3, p2) ^ sub_401D50(1, p3) ^ in[0];
                //if (show)
                //    printf("p4: %.2x\n", p4);
                unsigned char p5 = p1 ^ p2 ^ sub_401D50(2, p3) ^ sub_401D50(3, p4);
                //if (show)
                //    printf("p5: %.2x\n", p5);
                if (p5 != in[2])
                    continue;
 
                unsigned char p6 = sub_401D50(3, p1) ^ p2 ^ p3 ^ sub_401D50(2, p4);
                //if (show)
                //    printf("p6: %.2x\n", p6);
                if (p6 != in[3])
                    continue;
 
                unsigned char p7 = p1 ^ sub_401D50(2, p2) ^ sub_401D50(3, p3) ^ p4;
                //if (show)
                //    printf("p7: %.2x\n", p7);
                if (p7 != in[1])
                    continue;
                out[0] = p1;
                out[1] = p2;
                out[2] = p3;
                out[3] = p4;
 
                return;
            }
        }
    }
}

完整的十六字节计算如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void guess16(unsigned char* buf)
{
    unsigned char buf2[4];
    unsigned char buf3[4];
    unsigned char buf1[16];
    memcpy(buf1, buf, 16);
 
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
            buf2[j] = buf[j * 4 + i];
 
        guess(buf2, buf3);
 
        for (int j = 0; j < 4; j++)
            buf[j * 4 + i] = buf3[j];
    }
}

sub_40125D

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl sub_401570(int a1, _BYTE *a2)
{
  int j; // [esp+0h] [ebp-8h]
  int i; // [esp+4h] [ebp-4h]
 
  for ( i = 0; i < 4; ++i )
  {
    for ( j = 0; j < 4; ++j )
      *a2++ = *(_BYTE *)(a1 + 4 * j + i);
  }
  return 0;
}

和 sub_401500 一样

汇总

逆算法就是将所有算法反着跑一遍就出来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
for (int i = 0; i < 2; i++)
{
   unsigned char* psbox = sbox + 0x10 * 10;
   memcpy(buf, ctf + i * 16, 0x10);
   printf("check: %d\n", __LINE__);
   print_hex(buf, 16);
   sub_40125d_cc(buf);
   printf("check: %d\n", __LINE__);
   print_hex(buf, 16);
   sub_401186(buf, psbox);
   printf("+ sbox\n");
   print_hex(psbox, 0x10);
   printf("check: %d\n", __LINE__);
   print_hex(buf, 16);
   sub_40122b_cc(buf);
   printf("check: %d\n", __LINE__);
   print_hex(buf, 16);
   sub_401172_cc(buf);
   printf("check: %d\n", __LINE__);
   print_hex(buf, 16);
   for (int j = 1; j < 10; j++)
   {
       psbox -= 0x10;
       sub_401186(buf, psbox);
       printf("1186: %d\n", __LINE__);
       print_hex(buf, 16);
       guess16(buf);
       printf("guess: %d\n", j);
       print_hex(buf, 16);
       sub_40122b_cc(buf);
       printf("122b: %d\n", __LINE__);
       print_hex(buf, 16);
       sub_401172_cc(buf);
       printf("1172: %d\n", __LINE__);
       print_hex(buf, 16);
   }
   psbox -= 0x10;
   sub_401186(buf, psbox);
   print_hex(buf, 0x10);
   printf("ctf: %s\n", buf);
}

最后得到结果: "f{cdld6fabaeg58c4c96d5840590e69}";
然后调整一下位置:

1
2
3
4
5
6
unsigned char last1[] = "f{cdld6fabaeg58c4c96d5840590e69}";
 
for (int i = 0; i < 2; i++)
    sub_40125d_cc(last1 + i * 16);
 
printf("%s\n", last1);

看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

上传的附件:
收藏
点赞4
打赏
分享
最新回复 (4)
雪    币: 2300
活跃值: 活跃值 (2504)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
blck四 活跃值 1 2022-5-16 00:18
2
0
学习了
雪    币: 997
活跃值: 活跃值 (395)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
shun其自然 活跃值 2022-5-16 08:58
3
0
支持
雪    币: 3033
活跃值: 活跃值 (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qj111111 活跃值 2022-5-16 18:50
4
0
大佬好,样本在哪里下载
雪    币: 204
活跃值: 活跃值 (140)
能力值: ( LV3,RANK:32 )
在线值:
发帖
回帖
粉丝
dead.ash 活跃值 2022-6-2 14:09
5
0
qj111111 大佬好,样本在哪里下载
https://ctf.pediy.com/game-season_fight-206.htm
游客
登录 | 注册 方可回帖
返回