VM的开始会伴随着
1: push key
2: jmp addr
这个KEY 应用在接下来的解码中,在进入JMP后,就开始初始化虚拟机环境,例如初始化虚拟机的堆栈,寄存器之类的
1: 0046515C 9C pushfd ; 初始化虚拟堆栈vESP+28:EFL
2: 0046515D 8F4424 28 pop dword ptr ss:[esp+28] ; esp+28 保存EFL寄存器
3: 00465161 F8 clc
4: 00465162 F8 clc
5: 00465163 897424 24 mov dword ptr ss:[esp+24],esi ; 初始化虚拟堆栈vESP+24:ESI
6: 00465167 9C pushfd
7: 00465168 895424 24 mov dword ptr ss:[esp+24],edx ; 初始化虚拟堆栈vESP+20:EDX
8: 0046516C 5E pop esi
9: 0046516D 66:C1DE 03 rcr si,3
10: 00465171 66:11CE adc si,cx
11: 00465174 875C24 1C xchg dword ptr ss:[esp+1C],ebx ; 初始化虚拟堆栈vESP+1C:EBX
12: 00465178 0F9FC3 setg bl
13: 0046517B 895424 18 mov dword ptr ss:[esp+18],edx ; 初始化虚拟堆栈vESP+18:EDX
14: 0046517F 66:0FC1DE xadd si,bx
15: 00465183 66:81CE CFC0 or si,0C0CF
16: 00465188 9C pushfd
17: 00465189 F5 cmc
18: 0046518A 894424 18 mov dword ptr ss:[esp+18],eax ; 初始化虚拟堆栈vESP+14:EAX
19: 0046518E 66:0FBED1 movsx dx,cl
20: 00465192 F6C6 76 test dh,76
21: 00465195 F9 stc
22: 00465196 894C24 14 mov dword ptr ss:[esp+14],ecx ; 初始化虚拟堆栈vESP+10:ECX
23: 0046519A 66:0FBCF3 bsf si,bx
24: 0046519E FEC8 dec al
25: 004651A0 C0FF 07 sar bh,7
26: 004651A3 8D9F D01AB2FE lea ebx,dword ptr ds:[edi+FEB21AD0]
27: 004651A9 897C24 10 mov dword ptr ss:[esp+10],edi ; 初始化虚拟堆栈vESP+C:EDI
28: 004651AD 66:21C2 and dx,ax
29: 004651B0 66:81DE C1DF sbb si,0DFC1
30: 004651B5 896C24 0C mov dword ptr ss:[esp+C],ebp ; 初始化虚拟堆栈vESP+8:EBP
31:
做完这些操作后,虚拟机开始进入解码部分,可以称之为解码CALL。
PS: 解码CALL –-> 这个CALL在每次执行完虚拟指令块后都会跳回这个CALL为下一块虚拟指令块的hanlder进行解码,然后如此循环。这个CALL里最重要的就是handler的获取。
执行解码CALL后,就会进入虚拟指令了,这里的虚拟指令通俗的讲就是将正常的X86代码进行拆解,化为多条微指令进行执行,执行完毕后跳回解码CALL继续解码。
整个步骤分为:
1:初始化虚拟机环境:分配堆栈和寄存器
2:进入解码CALL根据KEY取dispatch表里的handler值,然后跳到handler的位置
3:跳转过来后就开始执行虚拟指令,执行完毕后跳回解码CALL,然后继续一轮一轮的循环。