-
-
[原创]第十六题 CrackMe逆向分析
-
发表于: 2016-12-6 12:48 3054
-
首先说明一下,还原虚拟机需要一套复杂的流程和巨大的工作量,具体还原程度视目标而定。
由于该题有反调试措施,所以使用OD附加过掉反调试还是比较方便的。另外作者提供了32位修补bug的方法,在32位下使用SOD也可以过掉反调试。
Crackme除了采用虚拟机外还使用了自修改SMC技术,只有跑过壳的shellcode才能见识到真正有用的代码。
虚拟机为栈式虚拟机,下面是虚拟机的结构
EDI 指向 cpu context
ESI 指向 vm_code
EBP 指向 vm_stack
vm_handler表在 42271B,且没有加密
vm_code 没有加密
主要逆向流程如下:
输入序列号后来到程序空间,如下:
0040140D /. 55 push ebp
0040140E |. 8BEC mov ebp, esp
00401410 |. 6A 00 push 0
00401412 |. FF75 0C push dword ptr [ebp+C]
00401415 |. FF75 08 push dword ptr [ebp+8]
00401418 |. E8 D8FDFFFF call 004011F5
0040141D |. 83C4 0C add esp, 0C
00401420 |. 5D pop ebp
00401421 \. C3 retn
该函数为“gets”,为获取控制台输入的序列号
通过runtrace 很容易找到vm_loop,如下:
004210BD 主 xor ax, 0BF77 FL=S, EAX=0000E851
004210C2 主 jmp short 004210C6
004210C6 主 lea eax, dword ptr [edi+40] EAX=0012FAF8
004210C9 主 jmp short 004210CC
004210CC 主 cmp ebp, eax FL=PA
004210CE 主 jmp short 004210D1
004210D1 主 ja 00421208
00421208 主 movzx eax, byte ptr [esi] EAX=0000001B
0042120B 主 jmp 0042123A
0042123A 主 lea esi, dword ptr [esi+1] ESI=0043E5D9
0042123D 主 jmp 0042121E
0042121E 主 popfd FL=A, ESP=0012FA78
0042121F 主 jmp short 00421224
00421224 主 jmp dword ptr [eax*4+42271B] ;这里跳转到每个handler
对00421224下断,分析每个handler(这里也可以静态分析)
1B vm_push_imm32
1C vm_jcc
27 vm_push_reg32
26 vm_imul
01 vm_add_stk
17 vm_add_32
1D vm_pop_mem32
0B vm_push_mem32
05 vm_set_eflags
16 vm_get_eflags
17 vm_copy_stk
14 vm_copy_stk32
19 vm_nand32
02 vm_shr_32
09 vm_sub_32
06 vm_push_eflags
22 vm_pop_eflags
11 vm_pop_reg32
24 vm_nop
08 vm_exit
0D vm_push_stk
0F vm_push_imm8
12 vm_exts8_32
22 vm_push_stk
18 vm_push_esp
0E vm_copy_stk8
1E vm_pop_reg8
10 vm_push_reg8
1F vm_push_mem
1D vm_pop_mem32
如果算法不够复杂,则不需要完全逆向虚拟机,只需要分析出部分有用的handler进行动态跟踪即可。
因为cmp指令在虚拟机中都是通过减法模拟的,所以在vm_sub 的handler处下断,会发现
004213EB 2945 00 sub dword ptr [ebp], eax
004213EE ^ E9 78FEFFFF jmp 0042126B
这里将我们输入的序列号长度n与0d进行了减法,说明序列号长度为0d。而操作码0F vm_push_imm8,将8bit立即数0d加载到栈顶。
由于vm_code没有加密,所以可以直接对vm_code 进行解析
0043E600 0F 0D 12 05 09 16 01 04 00 1B 26 E6 43 00 1B D5 ...&鍯.?
0043E610 EA 43 00 27 00 14 19 1B 40 00 00 00 14 19 19 1B 闏.'.@...
0043E620 06 00 00 00 02 1C 1B 01 00 00 00 1B 00 00 00 00 ..........
0043E630 26 01 04 00 18 1B 00 00 00 00 17 17 0E 1E F4 10 &.....?
0043E640 F4 12 14 19 0F 57 12 14 19 19 10 F4 12 0F 57 12 ?W?W
0043E650 19 05 19 16 1E F4 01 03 00 10 F4 12 0F 1B 12 05 ?.?
0043E660 09 16 01 04 00 1B 82 E6 43 00 1B D5 EA 43 00 27 ..傛C.贞C.'
0043E670 00 14 19 1B 40 00 00 00 14 19 19 1B 06 00 00 00 .@......
0043E680 02 1C 1B 01 00 00 00 1B 00 00 00 00 26 01 04 00 .......&.
0043E690 18 1B 01 00 00 00 17 17 0E 1E FC 10 FC 12 14 19 ...??
0043E6A0 0F 6F 12 14 19 19 10 FC 12 0F 6F 12 19 05 19 16 o?o
通过分析大致流程如下(一般是通过脚本自动分析的)
0F vm_push_imm8 'W'
...
19 vm_nand32(nand(sn), nand(W)) xor
...
0F vm_push_imm8 1B
...
09 vm_sub_32
...
通过vm_code 不断定位 0F可
最后得出 (sn) xor (WoJiuShiZheMe) == 1B0602081C1F0D3E352C000A00
sn=LiHaiLeWoDeGe
由于该题有反调试措施,所以使用OD附加过掉反调试还是比较方便的。另外作者提供了32位修补bug的方法,在32位下使用SOD也可以过掉反调试。
Crackme除了采用虚拟机外还使用了自修改SMC技术,只有跑过壳的shellcode才能见识到真正有用的代码。
虚拟机为栈式虚拟机,下面是虚拟机的结构
EDI 指向 cpu context
ESI 指向 vm_code
EBP 指向 vm_stack
vm_handler表在 42271B,且没有加密
vm_code 没有加密
主要逆向流程如下:
输入序列号后来到程序空间,如下:
0040140D /. 55 push ebp
0040140E |. 8BEC mov ebp, esp
00401410 |. 6A 00 push 0
00401412 |. FF75 0C push dword ptr [ebp+C]
00401415 |. FF75 08 push dword ptr [ebp+8]
00401418 |. E8 D8FDFFFF call 004011F5
0040141D |. 83C4 0C add esp, 0C
00401420 |. 5D pop ebp
00401421 \. C3 retn
该函数为“gets”,为获取控制台输入的序列号
通过runtrace 很容易找到vm_loop,如下:
004210BD 主 xor ax, 0BF77 FL=S, EAX=0000E851
004210C2 主 jmp short 004210C6
004210C6 主 lea eax, dword ptr [edi+40] EAX=0012FAF8
004210C9 主 jmp short 004210CC
004210CC 主 cmp ebp, eax FL=PA
004210CE 主 jmp short 004210D1
004210D1 主 ja 00421208
00421208 主 movzx eax, byte ptr [esi] EAX=0000001B
0042120B 主 jmp 0042123A
0042123A 主 lea esi, dword ptr [esi+1] ESI=0043E5D9
0042123D 主 jmp 0042121E
0042121E 主 popfd FL=A, ESP=0012FA78
0042121F 主 jmp short 00421224
00421224 主 jmp dword ptr [eax*4+42271B] ;这里跳转到每个handler
对00421224下断,分析每个handler(这里也可以静态分析)
1B vm_push_imm32
1C vm_jcc
27 vm_push_reg32
26 vm_imul
01 vm_add_stk
17 vm_add_32
1D vm_pop_mem32
0B vm_push_mem32
05 vm_set_eflags
16 vm_get_eflags
17 vm_copy_stk
14 vm_copy_stk32
19 vm_nand32
02 vm_shr_32
09 vm_sub_32
06 vm_push_eflags
22 vm_pop_eflags
11 vm_pop_reg32
24 vm_nop
08 vm_exit
0D vm_push_stk
0F vm_push_imm8
12 vm_exts8_32
22 vm_push_stk
18 vm_push_esp
0E vm_copy_stk8
1E vm_pop_reg8
10 vm_push_reg8
1F vm_push_mem
1D vm_pop_mem32
如果算法不够复杂,则不需要完全逆向虚拟机,只需要分析出部分有用的handler进行动态跟踪即可。
因为cmp指令在虚拟机中都是通过减法模拟的,所以在vm_sub 的handler处下断,会发现
004213EB 2945 00 sub dword ptr [ebp], eax
004213EE ^ E9 78FEFFFF jmp 0042126B
这里将我们输入的序列号长度n与0d进行了减法,说明序列号长度为0d。而操作码0F vm_push_imm8,将8bit立即数0d加载到栈顶。
由于vm_code没有加密,所以可以直接对vm_code 进行解析
0043E600 0F 0D 12 05 09 16 01 04 00 1B 26 E6 43 00 1B D5 ...&鍯.?
0043E610 EA 43 00 27 00 14 19 1B 40 00 00 00 14 19 19 1B 闏.'.@...
0043E620 06 00 00 00 02 1C 1B 01 00 00 00 1B 00 00 00 00 ..........
0043E630 26 01 04 00 18 1B 00 00 00 00 17 17 0E 1E F4 10 &.....?
0043E640 F4 12 14 19 0F 57 12 14 19 19 10 F4 12 0F 57 12 ?W?W
0043E650 19 05 19 16 1E F4 01 03 00 10 F4 12 0F 1B 12 05 ?.?
0043E660 09 16 01 04 00 1B 82 E6 43 00 1B D5 EA 43 00 27 ..傛C.贞C.'
0043E670 00 14 19 1B 40 00 00 00 14 19 19 1B 06 00 00 00 .@......
0043E680 02 1C 1B 01 00 00 00 1B 00 00 00 00 26 01 04 00 .......&.
0043E690 18 1B 01 00 00 00 17 17 0E 1E FC 10 FC 12 14 19 ...??
0043E6A0 0F 6F 12 14 19 19 10 FC 12 0F 6F 12 19 05 19 16 o?o
通过分析大致流程如下(一般是通过脚本自动分析的)
0F vm_push_imm8 'W'
...
19 vm_nand32(nand(sn), nand(W)) xor
...
0F vm_push_imm8 1B
...
09 vm_sub_32
...
通过vm_code 不断定位 0F可
最后得出 (sn) xor (WoJiuShiZheMe) == 1B0602081C1F0D3E352C000A00
sn=LiHaiLeWoDeGe
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
- [原创]C++类成员指针调用 4493
- [原创]VMP3.2授权分析 55214
- [原创]看雪CTF2017 第十二题分析 5292
- [原创]看雪CTF2017 第十一题分析 6395
- [原创]看雪CTF2017 第十题分析 6090
赞赏
雪币:
留言: