-
-
[原创]看雪2016 第十八题 CrackMe逆向分析
-
发表于: 2016-12-8 16:05 2965
-
此题比16题要难,因为大部分算法都在虚拟机中运行,而且算法复杂度远远大于16题的异或,理论上必须将虚拟机9成以上指令分析出来才能完全掌握算法。虽然虚拟机还是一如既往的简陋,可以说是手动的定制化“虚拟机”。
OD中Ctrl+N 找到 GetDlgItemTextA 来到
004010AE |. FF15 A0804000 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004010B4 |. 3BF4 cmp esi, esp
004010B6 |. E8 B1310000 call 0040426C
004010BB |. 8D4D 98 lea ecx, dword ptr [ebp-68]
004010BE |. 51 push ecx
004010BF |. 8B55 08 mov edx, dword ptr [ebp+8]
004010C2 |. 52 push edx
004010C3 |. E8 58000000 call 00401120 ; 此处为序列号操作
004010C8 |. 83C4 08 add esp, 8
004010CB |> 8B45 10 mov eax, dword ptr [ebp+10]
关键函数为 call 00401120
004011AC |. 8D05 AC114000 lea eax, dword ptr [4011AC]
004011B2 |. 83C0 10 add eax, 10
004011B5 |. 50 push eax
004011B6 \. C3 retn
该函数分为两部分,第一部分为ret跳转,跳到第二段代码,如下:
004011CA . 8B45 F8 mov eax, dword ptr [ebp-8]
004011CD . 8945 E4 mov dword ptr [ebp-1C], eax ; Crackme.004080C0
004011D0 . 8B45 E4 mov eax, dword ptr [ebp-1C]
004011D3 . 8945 E0 mov dword ptr [ebp-20], eax
004011D6 . 8B4D DC mov ecx, dword ptr [ebp-24]
004011D9 . 8B55 E0 mov edx, dword ptr [ebp-20]
可疑地址为 004080C0,通过后面的分析,发现是异常处理地址表
下面是sn异或-41操作,前9个字符
0040127B . 8955 B0 mov dword ptr [ebp-50], edx
0040127E > 837D B0 08 cmp dword ptr [ebp-50], 8 ; sn1 - sn9
00401282 . 7F 1F jg short 004012A3
00401284 . 8B45 0C mov eax, dword ptr [ebp+C]
00401287 . 0345 B0 add eax, dword ptr [ebp-50]
0040128A . 0FBE08 movsx ecx, byte ptr [eax]
0040128D . 8B55 B0 mov edx, dword ptr [ebp-50]
00401290 . 0FBE4415 9C movsx eax, byte ptr [ebp+edx-64]
00401295 . 33C8 xor ecx, eax ; sn ^ t2[i]
00401297 . 83E9 41 sub ecx, 41 ; - 41
0040129A . 8B55 B0 mov edx, dword ptr [ebp-50]
0040129D . 894C95 B8 mov dword ptr [ebp+edx*4-48], ecx
004012A1 .^ EB D2 jmp short 00401275
t2 =
0019F76C 33 21 22 21 35 7C 62 65 6E 00 CC CC 01 00 00 00 3!"!5|ben.烫...
下面是对结果比较大小,共9个int类型
004012BF . 8945 B0 mov dword ptr [ebp-50], eax
004012C2 > 837D B0 08 cmp dword ptr [ebp-50], 8
004012C6 . 7D 1B jge short 004012E3
004012C8 . 8B4D B0 mov ecx, dword ptr [ebp-50]
004012CB . 8B55 B0 mov edx, dword ptr [ebp-50]
004012CE . 8B448D B8 mov eax, dword ptr [ebp+ecx*4-48]
004012D2 . 3B4495 BC cmp eax, dword ptr [ebp+edx*4-44]
004012D6 . 7C 09 jl short 004012E1
004012D8 . C745 AC 01000>mov dword ptr [ebp-54], 1
004012DF . EB 02 jmp short 004012E3
t1[0] > 1
t1[0] < t1[1] < t1[2] ....
对t1做乘法,结果为x
004012F9 > /8B4D B0 mov ecx, dword ptr [ebp-50]
004012FC . |83C1 01 add ecx, 1
004012FF . |894D B0 mov dword ptr [ebp-50], ecx
00401302 > |837D B0 09 cmp dword ptr [ebp-50], 9
00401306 . |7D 10 jge short 00401318
00401308 . |8B55 B0 mov edx, dword ptr [ebp-50]
0040130B . |8B45 A8 mov eax, dword ptr [ebp-58]
0040130E . |0FAF4495 B8 imul eax, dword ptr [ebp+edx*4-48]
00401313 . |8945 A8 mov dword ptr [ebp-58], eax
00401316 .^\EB E1 jmp short 004012F9
x= t2[0] * t2[1] ...
x = 64/(0D4C2086-x) 需要触发异常 x == 0D4C2086
00401318 > \B9 86204C0D mov ecx, 0D4C2086
0040131D . 2B4D A8 sub ecx, dword ptr [ebp-58]
00401320 . B8 64000000 mov eax, 64
00401325 . 99 cdq
00401326 . F7F9 idiv ecx
00401328 . 8945 A8 mov dword ptr [ebp-58], eax
如果x不为0D4C2086,则不会进入 call 004013B0,MessageBox 就在这个函数中,所以...
先不管这些(逆法后面给出),直接造个除法异常,进入 004013B0 继续跟踪
初步分析004013B0是个手动构造的vm,其vm_loop如下:
00404220 . 8995 60FDFEFF mov dword ptr [ebp+FFFEFD60], edx
00404226 . 8B45 FC mov eax, dword ptr [ebp-4]
00404229 . 66:8B48 04 mov cx, word ptr [eax+4]
0040422D . 66:83C1 01 add cx, 1
00404231 . 8B55 FC mov edx, dword ptr [ebp-4]
00404234 . 66:894A 04 mov word ptr [edx+4], cx
00404238 . 8B85 60FDFEFF mov eax, dword ptr [ebp+FFFEFD60]
0040423E . FFA485 6CFEFE>jmp dword ptr [ebp+eax*4+FFFEFE6C]
vm_code 如下:
00195701 01 00 02 00 03
00195711 00 96 00 20 21 0A 00 29 01 2B 01 27 F6 FF 81 14 .? !..)+'??
00195721 21 04 00 00 01 2E 12 00 80 01 63 02 09 8B 00 20 !....€c.?
00195731 21 04 00 00 01 6F 2A 01 8B 00 20 21 04 00 00 2A !..o*? !..*
00195741 01 8B 00 20 21 04 00 00 01 6C 2A 01 8B 00 20 21 ? !..l*? !
00195751 04 00 00 01 2E 03 01 14 00 80 01 31 2A 01 8B 00 ....€1*?
00195761 20 21 04 00 00 0B 00 20 29 D0 08 45 45 1B 2A 01 !... )?EE*
00195771 0B 00 20 29 D0 08 45 45 1B 2A 01 0B 00 20 29 D0 . )?EE*. )?
00195781 08 45 45 1D 2D 1D 2D 1B 02 0D 0B 00 20 29 D0 41 EE--.. )蠥
00195791 64 2A 01 11 00 20 2B D0 43 0A 2D 2A 01 11 00 20 d*. +蠧.-*.
001957A1 2B D0 2D 1D 85 21 04 00 00 01 2E 03 02 14 00 80 +??....€
001957B1 2A 01 0B 00 20 29 D0 41 0A 2A 01 11 00 20 2B D0 *. )蠥.*. +?
具体的vm_hander逆向结果如下:
81 14
21 04 00 00
01 2E
12 00 80
01 63 c
02 09
8B 00 20 cmp(sn9, c)
21 04 00 00
01 6F o
2A 01
8B 00 20 cmp(sn10, o)
21 04 00 00
2A 01 o
8B 00 20 cmp(sn11, o)
21 04 00 00
01 6C l
2A 01
8B 00 20 cmp(sn12, l)
21 04 00 00
sn9 - 12 为:
cool
01 2E
03 01
14 00 80
01 31 1
2A 01
8B 00 20 cmp(sn13, 1)
21 04 00 00
0B 00 20 load(sn13)
29 D0 add(d0)
08 copy(stk)
45 mul
45 mul
1B pop_mem
2A 01 next
0B 00 20 load(sn14)
29 D0 add(d0)
08 copy(stk)
45 mul
45 mul
1B pop_mem
2A 01 next
0B 00 20 load(sn)
29 D0
08
45
45
1D push_mem
2D add_stk
1D push_mem
2D add_stk
1B pop_mem(03)
02 0D load_imm8(sn13)
0B 00 20 load(sn13)
29 D0 add(d0)
41 64 imul(64)
2A 01 next
11 00 20 load[1](sn14)
2B D0 add[1](d0)
43 0A imul[1](0A)
2D add_stk
2A 01
11 00 20 load[1](sn15)
2B D0 add[1](d0)
2D add_stk
1D push_mem
85 sub
21 04 00 00 (6f == 03)
算法为:1^3+x^3+y^3=1xy(理解为10进制)
01 2E
03 02 load[1](02)
14 00 80
2A 01
0B 00 20 load(sn16)
29 D0 add(d0)
41 0A imul(0a)
2A 01 next
11 00 20 load[1](sn17)
2B D0 add[1](d0)
2D add_stk
1B pop_mem(03)
2A 01
11 00 20 load[1](sn18)
2B D0 add[1](d0)
43 0A imul[1](0A)
2A 01
0B 00 20 load(sn19)
29 D0 add(d0)
30 add[1](stk) v2
1E load_mem0 v1
04 copy_[0]_v
2D add_stk_v[1]
42 04 imul[0](04)v1
43 02 imul[1](02)v2
2F add[0]([1])
81 23 cmp(23)
26 12 00 jcc
82 5E cmp[0](5e)
26 0D 00 jcc
此处算法为:
sn16*0A + sn17 = v1
sn18*0A + sn19 = v2
v1 + v2 = 23
v1*4+v2*2 = 5E
01 2E
03 03 load[1](03)
14 00 80
27 04 00 00
02 00 load0(00)
01 00 load(00)
03 2E load[1](2e)
此处检查4个 2e
98 00 80
26 05 00 jcc
29 01 add(01)
2A 01
82 04 cmp0(04)
26 F4 FF jcc
81 04 cmp(04)
26 04 00 jcc
99 00 ->ok
逆向算法如下
OD中Ctrl+N 找到 GetDlgItemTextA 来到
004010AE |. FF15 A0804000 call dword ptr [<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004010B4 |. 3BF4 cmp esi, esp
004010B6 |. E8 B1310000 call 0040426C
004010BB |. 8D4D 98 lea ecx, dword ptr [ebp-68]
004010BE |. 51 push ecx
004010BF |. 8B55 08 mov edx, dword ptr [ebp+8]
004010C2 |. 52 push edx
004010C3 |. E8 58000000 call 00401120 ; 此处为序列号操作
004010C8 |. 83C4 08 add esp, 8
004010CB |> 8B45 10 mov eax, dword ptr [ebp+10]
关键函数为 call 00401120
004011AC |. 8D05 AC114000 lea eax, dword ptr [4011AC]
004011B2 |. 83C0 10 add eax, 10
004011B5 |. 50 push eax
004011B6 \. C3 retn
该函数分为两部分,第一部分为ret跳转,跳到第二段代码,如下:
004011CA . 8B45 F8 mov eax, dword ptr [ebp-8]
004011CD . 8945 E4 mov dword ptr [ebp-1C], eax ; Crackme.004080C0
004011D0 . 8B45 E4 mov eax, dword ptr [ebp-1C]
004011D3 . 8945 E0 mov dword ptr [ebp-20], eax
004011D6 . 8B4D DC mov ecx, dword ptr [ebp-24]
004011D9 . 8B55 E0 mov edx, dword ptr [ebp-20]
可疑地址为 004080C0,通过后面的分析,发现是异常处理地址表
下面是sn异或-41操作,前9个字符
0040127B . 8955 B0 mov dword ptr [ebp-50], edx
0040127E > 837D B0 08 cmp dword ptr [ebp-50], 8 ; sn1 - sn9
00401282 . 7F 1F jg short 004012A3
00401284 . 8B45 0C mov eax, dword ptr [ebp+C]
00401287 . 0345 B0 add eax, dword ptr [ebp-50]
0040128A . 0FBE08 movsx ecx, byte ptr [eax]
0040128D . 8B55 B0 mov edx, dword ptr [ebp-50]
00401290 . 0FBE4415 9C movsx eax, byte ptr [ebp+edx-64]
00401295 . 33C8 xor ecx, eax ; sn ^ t2[i]
00401297 . 83E9 41 sub ecx, 41 ; - 41
0040129A . 8B55 B0 mov edx, dword ptr [ebp-50]
0040129D . 894C95 B8 mov dword ptr [ebp+edx*4-48], ecx
004012A1 .^ EB D2 jmp short 00401275
t2 =
0019F76C 33 21 22 21 35 7C 62 65 6E 00 CC CC 01 00 00 00 3!"!5|ben.烫...
下面是对结果比较大小,共9个int类型
004012BF . 8945 B0 mov dword ptr [ebp-50], eax
004012C2 > 837D B0 08 cmp dword ptr [ebp-50], 8
004012C6 . 7D 1B jge short 004012E3
004012C8 . 8B4D B0 mov ecx, dword ptr [ebp-50]
004012CB . 8B55 B0 mov edx, dword ptr [ebp-50]
004012CE . 8B448D B8 mov eax, dword ptr [ebp+ecx*4-48]
004012D2 . 3B4495 BC cmp eax, dword ptr [ebp+edx*4-44]
004012D6 . 7C 09 jl short 004012E1
004012D8 . C745 AC 01000>mov dword ptr [ebp-54], 1
004012DF . EB 02 jmp short 004012E3
t1[0] > 1
t1[0] < t1[1] < t1[2] ....
对t1做乘法,结果为x
004012F9 > /8B4D B0 mov ecx, dword ptr [ebp-50]
004012FC . |83C1 01 add ecx, 1
004012FF . |894D B0 mov dword ptr [ebp-50], ecx
00401302 > |837D B0 09 cmp dword ptr [ebp-50], 9
00401306 . |7D 10 jge short 00401318
00401308 . |8B55 B0 mov edx, dword ptr [ebp-50]
0040130B . |8B45 A8 mov eax, dword ptr [ebp-58]
0040130E . |0FAF4495 B8 imul eax, dword ptr [ebp+edx*4-48]
00401313 . |8945 A8 mov dword ptr [ebp-58], eax
00401316 .^\EB E1 jmp short 004012F9
x= t2[0] * t2[1] ...
x = 64/(0D4C2086-x) 需要触发异常 x == 0D4C2086
00401318 > \B9 86204C0D mov ecx, 0D4C2086
0040131D . 2B4D A8 sub ecx, dword ptr [ebp-58]
00401320 . B8 64000000 mov eax, 64
00401325 . 99 cdq
00401326 . F7F9 idiv ecx
00401328 . 8945 A8 mov dword ptr [ebp-58], eax
如果x不为0D4C2086,则不会进入 call 004013B0,MessageBox 就在这个函数中,所以...
先不管这些(逆法后面给出),直接造个除法异常,进入 004013B0 继续跟踪
初步分析004013B0是个手动构造的vm,其vm_loop如下:
00404220 . 8995 60FDFEFF mov dword ptr [ebp+FFFEFD60], edx
00404226 . 8B45 FC mov eax, dword ptr [ebp-4]
00404229 . 66:8B48 04 mov cx, word ptr [eax+4]
0040422D . 66:83C1 01 add cx, 1
00404231 . 8B55 FC mov edx, dword ptr [ebp-4]
00404234 . 66:894A 04 mov word ptr [edx+4], cx
00404238 . 8B85 60FDFEFF mov eax, dword ptr [ebp+FFFEFD60]
0040423E . FFA485 6CFEFE>jmp dword ptr [ebp+eax*4+FFFEFE6C]
vm_code 如下:
00195701 01 00 02 00 03
00195711 00 96 00 20 21 0A 00 29 01 2B 01 27 F6 FF 81 14 .? !..)+'??
00195721 21 04 00 00 01 2E 12 00 80 01 63 02 09 8B 00 20 !....€c.?
00195731 21 04 00 00 01 6F 2A 01 8B 00 20 21 04 00 00 2A !..o*? !..*
00195741 01 8B 00 20 21 04 00 00 01 6C 2A 01 8B 00 20 21 ? !..l*? !
00195751 04 00 00 01 2E 03 01 14 00 80 01 31 2A 01 8B 00 ....€1*?
00195761 20 21 04 00 00 0B 00 20 29 D0 08 45 45 1B 2A 01 !... )?EE*
00195771 0B 00 20 29 D0 08 45 45 1B 2A 01 0B 00 20 29 D0 . )?EE*. )?
00195781 08 45 45 1D 2D 1D 2D 1B 02 0D 0B 00 20 29 D0 41 EE--.. )蠥
00195791 64 2A 01 11 00 20 2B D0 43 0A 2D 2A 01 11 00 20 d*. +蠧.-*.
001957A1 2B D0 2D 1D 85 21 04 00 00 01 2E 03 02 14 00 80 +??....€
001957B1 2A 01 0B 00 20 29 D0 41 0A 2A 01 11 00 20 2B D0 *. )蠥.*. +?
具体的vm_hander逆向结果如下:
81 14
21 04 00 00
01 2E
12 00 80
01 63 c
02 09
8B 00 20 cmp(sn9, c)
21 04 00 00
01 6F o
2A 01
8B 00 20 cmp(sn10, o)
21 04 00 00
2A 01 o
8B 00 20 cmp(sn11, o)
21 04 00 00
01 6C l
2A 01
8B 00 20 cmp(sn12, l)
21 04 00 00
sn9 - 12 为:
cool
01 2E
03 01
14 00 80
01 31 1
2A 01
8B 00 20 cmp(sn13, 1)
21 04 00 00
0B 00 20 load(sn13)
29 D0 add(d0)
08 copy(stk)
45 mul
45 mul
1B pop_mem
2A 01 next
0B 00 20 load(sn14)
29 D0 add(d0)
08 copy(stk)
45 mul
45 mul
1B pop_mem
2A 01 next
0B 00 20 load(sn)
29 D0
08
45
45
1D push_mem
2D add_stk
1D push_mem
2D add_stk
1B pop_mem(03)
02 0D load_imm8(sn13)
0B 00 20 load(sn13)
29 D0 add(d0)
41 64 imul(64)
2A 01 next
11 00 20 load[1](sn14)
2B D0 add[1](d0)
43 0A imul[1](0A)
2D add_stk
2A 01
11 00 20 load[1](sn15)
2B D0 add[1](d0)
2D add_stk
1D push_mem
85 sub
21 04 00 00 (6f == 03)
算法为:1^3+x^3+y^3=1xy(理解为10进制)
01 2E
03 02 load[1](02)
14 00 80
2A 01
0B 00 20 load(sn16)
29 D0 add(d0)
41 0A imul(0a)
2A 01 next
11 00 20 load[1](sn17)
2B D0 add[1](d0)
2D add_stk
1B pop_mem(03)
2A 01
11 00 20 load[1](sn18)
2B D0 add[1](d0)
43 0A imul[1](0A)
2A 01
0B 00 20 load(sn19)
29 D0 add(d0)
30 add[1](stk) v2
1E load_mem0 v1
04 copy_[0]_v
2D add_stk_v[1]
42 04 imul[0](04)v1
43 02 imul[1](02)v2
2F add[0]([1])
81 23 cmp(23)
26 12 00 jcc
82 5E cmp[0](5e)
26 0D 00 jcc
此处算法为:
sn16*0A + sn17 = v1
sn18*0A + sn19 = v2
v1 + v2 = 23
v1*4+v2*2 = 5E
01 2E
03 03 load[1](03)
14 00 80
27 04 00 00
02 00 load0(00)
01 00 load(00)
03 2E load[1](2e)
此处检查4个 2e
98 00 80
26 05 00 jcc
29 01 add(01)
2A 01
82 04 cmp0(04)
26 F4 FF jcc
81 04 cmp(04)
26 04 00 jcc
99 00 ->ok
逆向算法如下
#include "stdafx.h" unsigned char cch[] = { "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" }; unsigned char t2[] = { 0x33, 0x21, 0x22, 0x21, 0x35, 0x7C, 0x62, 0x65, 0x6E }; int is_ch(unsigned char c) { for (int i = 0; i < sizeof(cch) - 1; i++) { if (c == cch[i]) return 1; } return 0; } int test(int n, int v, int k, char *ptr) { if (v < 0) return 0; if (n > 8) { if (v == 1) printf("%s\n", ptr); } for (int i = k+1; i < 0xFF-0x40; i++) { if (v%i) continue; unsigned char ch = (i + 0x41) ^ t2[n]; if (!is_ch(ch)) continue; ptr[n] = ch; test(n + 1, v / i, i, ptr); } return 0; } int _tmain(int argc, _TCHAR* argv[]) { char ptr[10] = { 0 }; test(0, 0x0D4C2086, 1, ptr); for (int i = 1; i < 16; i++) { for (int j = 1; j < 16; j++) { int v = i*i*i + j*j*j+1; if (v > 256) break; if (v / 100 == 1) { int v1 = v % 100; if ((v1 / 10 == i) && (v1%10 == j)) { printf("%d + %d = %d\n", i, j, v); } } } } int v2 = (0x23 * 4 - 0x5e) / 2; int v1 = 0x23 - v2; printf("v1 = %d, v2 = %d\n", v1, v2); return 0; }
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
- [原创]C++类成员指针调用 4493
- [原创]VMP3.2授权分析 55214
- [原创]看雪CTF2017 第十二题分析 5292
- [原创]看雪CTF2017 第十一题分析 6395
- [原创]看雪CTF2017 第十题分析 6090
赞赏
雪币:
留言: