Demo指令:mov eax,0x200
主要看与vm1.10版本的虚拟机不同之处:
1、不再是用一个固定地址来保存vm_context,而是将vm_context放在了堆栈上,vm_esp不再直接是esp而是ebp,esp只是用来作混淆作用。
2、每次handler执行中都会对esp进行减不等数值,在handler执行完成后会还原esp到vm_context位置
3、opcode部分也就是vm_eip还是用esi指向,不同之处在于esi不再是递增,还是递减获取opcode
4、vm_start以及vm_ret都不会用pushad和pushfd来一键保存还原寄存器,而是每个寄存器的分别vPush操作。
5、加入了很多垃圾代码来干扰分析。
6、由于vm_eip是倒置的,在取常量时候会用到xchg指令来重置
7、1.60开始VMP就是栈式虚拟机,不再将vm_context放在内存中,而是放在了vm_esp(ebp)的上面,如果ebp将要覆盖到vm_context,比如一些vPushImmxx操作后就会进行vCheckEsp操作,发现快要覆盖就将原来的vm_context复制到更高的栈地址去(-xx)。
具体分析如下,mov这一条指令vm后主要就是由vPushReg32,vPushImm32,vPopReg32,每个handler都只保留了非垃圾指令部分,其实也就只用关注那几个重要的寄存器,eax,ebp,edi,esi这几个寄存器操作的一般都是有效指令,而在每条handler的结尾都会由一条lea esp,[esp+xxx]来恢复esp:
esi = vm_eip
edi = vm_context
ebp = vm_esp
00417600 68 26764100 push 00417626
$ ==> > 00417626 VMP1_60_.00417626
------------
00416E26 891C24 mov dword ptr [esp], ebx ; push ebx
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
004160C8 894424 04 mov dword ptr [esp+0x4], eax ; push eax
$-10 > 00416E2E
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
004160CD 877C24 20 xchg dword ptr [esp+0x20], edi ; push edi
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626 VMP1_60_.00417626
------------
004160D5 895C24 1C mov dword ptr [esp+0x1C], ebx ; push ebx
$-14 > 44444444
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
004160DB 9C pushfd
004160DC 8F4424 10 pop dword ptr [esp+0x10] ; pushfd
$-18 > 00000206
$-14 > 44444444
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
004160E8 894C24 0C mov dword ptr [esp+0xC], ecx ; push ecx
$-1C > 22222222
$-18 > 00000206
$-14 > 44444444
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
004160F9 896C24 08 mov dword ptr [esp+0x8], ebp ; push ebp
$-20 > 55555555
$-1C > 22222222
$-18 > 00000206
$-14 > 44444444
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
00416105 895424 24 mov dword ptr [esp+0x24], edx ; push edx
$-24 > 33333333
$-20 > 55555555
$-1C > 22222222
$-18 > 00000206
$-14 > 44444444
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
0041610C 877424 20 xchg dword ptr [esp+0x20], esi ; push esi
$-28 > 66666666
$-24 > 33333333
$-20 > 55555555
$-1C > 22222222
$-18 > 00000206
$-14 > 44444444
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
0041741C C74424 20 00000>mov dword ptr [esp+0x20], 0x0 ; reloc
$-2C > 00000000
$-28 > 66666666
$-24 > 33333333
$-20 > 55555555
$-1C > 22222222
$-18 > 00000206
$-14 > 44444444
$-10 > 77777777
$-C > 11111111
$-8 > 44444444
$-4 > 0041760A
$ ==> > 00417626
------------
0041742D 8B7424 6C mov esi, dword ptr [esp+0x6C] ; ;;;;esi = key
------------
00417436 8D6C24 40 lea ebp, dword ptr [esp+0x40] ;ebp = 临时寄存器栈顶
------------
00417446 83EC 7C sub esp, 0x7C
0041744D 68 C52A792D push 0x2D792AC5 ;esp 此时 = 最开始 - 0xF0
00417455 8D7C24 04 lea edi, dword ptr [esp+0x4] ; edi = vm_context
//也就是最开始 - 0xEC
------------
00417467 0375 00 add esi, dword ptr [ebp] ; vm重定向--->[ebp]保存reloc地址
------------
---------------vm_loop
00417472 8A46 FF mov al, byte ptr [esi-0x1] ; esi = vm_data , al = opcode,对应vm_handler表中索引
0041747C 4E dec esi ;esi = vmv_data,这里倒着增长。
00417485 0FB6C0 movzx eax, al
00417489 8B0C85 F76E4100 mov ecx, dword ptr [eax*4+0x416EF7] ; ;;;;;;ecx = 加密handler地址
00417495 81F1 E4FAC583 xor ecx, 0x83C5FAE4 ; Decode_handler地址1
00417361 41 inc ecx ; Decode_handler地址2
00416490 C1C9 1B ror ecx, 0x1B ; Decode_handler地址3
00416496 F7D9 neg ecx ; Decode_handler地址4
00416499 81C1 00000000 add ecx, 0x0 ; Decode_handler地址5
00416B82 894C24 30 mov dword ptr [esp+0x30], ecx ; ecx = handler地址
00416B8C 9C pushfd
00416B8D FF7424 34 push dword ptr [esp+0x34] ; push handler地址
00416B91 C2 3800 retn 0x38
------------vPopReg32
00416DD9 80E0 3C and al, 0x3C ; 解密操作数
00416DE6 8B55 00 mov edx, dword ptr [ebp] ; 取vm_esp栈顶元素
00416C44 83C5 04 add ebp, 0x4 ; vm_esp += 4
004168BD 891407 mov dword ptr [edi+eax], edx ; edi = vm_comtext,这里就是vPopReg32 edi[eax]
------------vPushImm32
00416C0F 66:8B46 FE mov ax, word ptr [esi-0x2] ; ax = 00000002
00416C0F 66:8B46 FE mov ax, word ptr [esi-0x2] ; ax = 00000200
00416C25 98 cwde ; ax -> eax = 00000200
00416123 83ED 04 sub ebp ; vm_esp -= 4
00416541 8945 00 mov dword ptr [ebp], eax ; vPushImm32 0x200
004169C7 8D76 FE lea esi, dword ptr [esi-0x2] ; vm_data -= 2
------------vPushReg32
00416B57 80E0 3C and al, 0x3C ; 解密操作数
00416B63 8B1407 mov edx, dword ptr [edi+eax] ; 获取vm_reg
00416B6F 83ED 04 sub ebp, 0x4 ; vm_esp -= 4
00416D17 8955 00 mov dword ptr [ebp], edx ; vPush
------------vRet
004165FC 8B7424 24 mov esi, dword ptr [esp+0x24] ; pop esi
00416605 8B5424 28 mov edx, dword ptr [esp+0x28] ; pop edx
0041758B 8B6C24 30 mov ebp, dword ptr [esp+0x30] ; pop ebp
00417592 8B4C24 34 mov ecx, dword ptr [esp+0x34] ; pop ecx
00416C76 FF7424 38 push dword ptr [esp+0x38] ; +0x38 = eflags
00416C7A 9D popfd ; popfd
00416C7E 8B5C24 38 mov ebx, dword ptr [esp+0x38] ; pop ebx
00416C88 8B7C24 3C mov edi, dword ptr [esp+0x3C] ; pop edi
00416941 8B4424 44 mov eax, dword ptr [esp+0x44] ; pop eax
00416949 8B5C24 4C mov ebx, dword ptr [esp+0x4C] ; pop ebx
00416951 FF7424 50 push dword ptr [esp+0x50] ; push retAddr
00416955 C2 5400 retn 0x54 ; ret
vCheckEsp:
004146E8 8D47 50 lea eax, dword ptr [edi+0x50] ; eax = 距离vm_context0x50地址处
004146F7 39C5 cmp ebp, eax ; vm_esp和vm_context + 0x50比较
004146FE 8D6424 24 lea esp, dword ptr [esp+0x24] ; 恢复esp为vm_context栈顶
00414702 /0F87 74060000 ja <vm_loop> ; if( vm_esp > vm_context + 0x50 )
0041470A 89E2 mov edx, esp ; edx = 现在的vm_context
00415A58 8D4F 40 lea ecx, dword ptr [edi+0x40] ; ecx = vm_context + 0x40
00415A64 29D1 sub ecx, edx ; ecx = vm_context + 0x40 - vm_context = 0x40
; ecx = 0x40作为后面rep复制的长度
00415A71 8D45 80 lea eax, dword ptr [ebp-0x80] ; eax = vm_esp - 0x80
00415A7A 29C8 sub eax, ecx ; vm_esp - 0x80 - 0x40 = vm_esp - 0x120
00415A83 89C4 mov esp, eax ; ;
00415AA2 897424 18 mov dword ptr [esp+0x18], esi ; 保存vm_eip $-C8 > 00415B48
004140D1 89D6 mov esi, edx ; esi = vm_context
004140D7 8D7C08 C0 lea edi, dword ptr [eax+ecx-0x40] ; edi = eax+ecx-0x40 = eax = 新vm_context地址
004149D9 877C24 18 xchg dword ptr [esp+0x18], edi ; 保存新的vm_context地址
00414BD0 8D6424 18 lea esp, dword ptr [esp+0x18] ; 抬高栈顶
00414BE1 89C7 mov edi, eax ; 恢复edi = 新vm_context地址
00414BE4 FC cld ; df = 0 ,每次复制向下递增esi和edi
00414620 F3:A4 repmovs byte ptr es:[edi], byte ptr [esi]; 复制vm_context的0x40部分到抬高的栈位置
00414629 8B7C24 2C mov edi, dword ptr [esp+0x2C] ; 更新vm_context
0041462E 8B7424 30 mov esi, dword ptr [esp+0x30] ; 还原vm_eip
00414651 8D6424 40 lea esp, dword ptr [esp+0x40] ; 恢复栈顶
00414655 /E9 22070000 jmp <vm_loop>
vCheckEsp:
vm_esp与接近vm_context的部分比较,如果快要接近到vm_context,就将vm_context内容复制到更高的栈上去(-x地址),然后还原
edi为新的vm_context,再把vm_eip还原。