首页
论坛
课程
招聘
[原创]KCTF2022春季赛第3题 石像病毒
2022-5-15 11:03 3256

[原创]KCTF2022春季赛第3题 石像病毒

2022-5-15 11:03
3256

SEH 相关题目,我这次主要采取静态分析方法解题,核心是人脑修复 SEH 的控制流跳转,从而让 IDA 可以 F5。
main 函数中的异常处理并没有什么特别的地方,大多是内存的初始化。关键引起我注意的是这么几个地方:

1
2
3
4
5
......
strcpy((char *)&v8[9], "Enj0y_1t_4_fuuuN");
......
sub_401109(&v8[9], 0x10u, (int)&v8[2]);
sub_401104(&v8[2], 0x10u, (int)&v8[30], (int)&v8[18], 32);

使用 IDA findcrypt 插件可以发现,sub_401109sub_401104 分别是 MD5 和 aesEncrypt。首先根据特征找到作者使用的 github 上的开源实现:

但还不能肯定没有魔改。首先人工修复一下 SEH 的异常处理:主要思路是把触发异常的语句 patch 为 jmp 到 except filter,并且把 retn 改成 nop 让执行流顺序执行到 except 块,然后跳转回 try 块中触发异常的下一条指令,最后再跳出来。以 MD5 函数中的这个为例:

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
.text:00402D13 ;   __try { // __except at loc_402D34
.text:00402D13                 mov     [ebp+ms_exc.registration.TryLevel], 0
.text:00402D1A                 xor     ebx, ebx
.text:00402D1C                 jmp     short loc_402D27 ; [Keypatch] modified this from:
.text:00402D1C ;   } // starts at 402D13               ;   div ebx
.text:00402D1E ; ---------------------------------------------------------------------------
.text:00402D1E
.text:00402D1E loc_402D1E:                             ; CODE XREF: sub_402CE0+57↓j
.text:00402D1E                 mov     [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
.text:00402D25                 jmp     short loc_402D3E
.text:00402D27 ; ---------------------------------------------------------------------------
.text:00402D27
.text:00402D27 loc_402D27:                             ; CODE XREF: sub_402CE0+3C↑j
.text:00402D27                                         ; DATA XREF: .rdata:stru_40A080↓o
.text:00402D27 ;   __except filter // owned by 402D13
.text:00402D27                 mov     eax, [ebp+ms_exc.exc_ptr]
.text:00402D2A                 push    eax
.text:00402D2B                 call    sub_4010FA
.text:00402D30                 add     esp, 4
.text:00402D33                 nop                     ; [Keypatch] modified this from:
.text:00402D33                                         ;   retn
.text:00402D34
.text:00402D34 loc_402D34:                             ; DATA XREF: .rdata:stru_40A080↓o
.text:00402D34 ;   __except(loc_402D27) // owned by 402D13
.text:00402D34                 mov     esp, [ebp+ms_exc.old_esp]
.text:00402D37                 jmp     short loc_402D1E ; [Keypatch] modified this from:
.text:00402D37                                         ;   mov [ebp+ms_exc.registration.TryLevel], 0FFFFFFFEh
.text:00402D37                                         ; [Keypatch] padded NOP to next boundary: 5 bytes
.text:00402D39 ; ---------------------------------------------------------------------------
.text:00402D39                 nop
.text:00402D3A                 nop
.text:00402D3B                 nop
.text:00402D3C                 nop
.text:00402D3D                 nop
.text:00402D3E
.text:00402D3E loc_402D3E:                             ; CODE XREF: sub_402CE0+45↑j
.text:00402D3E                 mov     ecx, 1

同样,AES 中的密钥扩展、行移位和列混淆中也有几处。
修复完阅读可以发现,作者在下面几处地方做了魔改:

  • shiftRows 改成了 invShiftRows:
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
int sub_401AE0()
{
  int *v0; // ebp
  int v1; // ecx
  int v3; // [esp+10h] [ebp-38h]
  int v4; // [esp+14h] [ebp-34h]
  int v5; // [esp+18h] [ebp-30h]
  int v6; // [esp+1Ch] [ebp-2Ch]
  int v7; // [esp+20h] [ebp-28h]
  int v8; // [esp+24h] [ebp-24h]
  int v9; // [esp+28h] [ebp-20h]
  int v10; // [esp+2Ch] [ebp-1Ch]
  int savedregs; // [esp+48h] [ebp+0h] BYREF
 
  v0 = &savedregs;
  v4 = -858993460;
  v9 = -858993460;
  v10 = -858993460;
  v5 = 0;
  v6 = 0;
  v7 = 0;
  v8 = 0;
  v3 = 0;
  while ( *(v0 - 14) < 4 )
  {
    v0[*(v0 - 14) - 12] = _byteswap_ulong(*(_DWORD *)(v0[2] + 4 * *(v0 - 14)));
    *(v0 - 1) = 0;
    v0 = (int *)((char *)v0 - 1);
    v1 = *(v0 - 14);
    v0[v1 - 12] = __ROR4__(v0[v1 - 12], 8 * v1);
    v0[*(v0 - 14) - 12] = ((unsigned int)v0[*(v0 - 14) - 12] >> (32 - 8 * *((_BYTE *)v0 - 56))) | (v0[*(v0 - 14) - 12] << v1);
    *(v0 - 1) = -2;
    *(_BYTE *)(v0[2] + 4 * *(v0 - 14)) = HIBYTE(v0[*(v0 - 14) - 12]);
    *(_BYTE *)(v0[2] + 4 * *(v0 - 14) + 1) = BYTE2(v0[*(v0 - 14) - 12]);
    *(_BYTE *)(v0[2] + 4 * *(v0 - 14) + 2) = BYTE1(v0[*(v0 - 14) - 12]);
    *(_BYTE *)(v0[2] + 4 * *(v0 - 14) + 3) = v0[*(v0 - 14) - 12];
    ++*(v0 - 14);
  }
  return 0;
}
  • 密钥扩展处更改了 sbox,即交换 sbox[113] 和 sbox[163]
  • 列混淆中的 GMul 函数将密文 cipher[16] 和 cipher[17] 交换顺序
  • 还有上文中提到的 MD5 函数代码中把 MD5 常数 k[42] 改成了 0xD4AF3085。

最后去解密就好,拿到 flag{db5c6a8dfec4d0ec5569899640}


2022 KCTF春季赛【最佳人气奖】火热评选中!快来投票吧~

最后于 2022-5-15 11:09 被trackL编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回