转载注明看雪
我看的这个版本是2.40的版本,别的版本的VM没有研究过。
它的VM是基于PCode的了,每条PCode是0x20个BYTE,格式如下:
#pragma pack(1)
/*
reg_info
0 eax
1 ecx
2 edx
3 ebx
4 esp
5 ebp
6 esi
7 edi
*/
typedef struct _P_Code_
{
BYTE x86code[0x10]; //这个是用来在stack里面运行的原始x86代码 最多0x10个字节
BYTE flag; //0代表是一般情况 4代表是stack最后加ret情况 38h
BYTE disptach_type; //PCode分发号 39h
BYTE regdest_type; //目标寄存器标识 3Ah
DWORD dwDestValue_Addr_Size; //用来计算regdest相关信息的 3Bh
BYTE regsrc_type; //源寄存器的标识 3Fh
DWORD dwSrcValue_Addr_Size; //用来计算regsrc相关信息的 40h
DWORD PCode_Addr; //和PCode相关 44h
}P_CODE;
#pragma pack()
最后表明的38h,39h... 是基于运行时候的偏移。
如果你在跟踪Private主程序时候看到正常的语句,后面猛然接个大跳,很可能就开始进入VM了,比如:
RYOMA:2C8B3593 64 FF 30 push dword ptr fs:[eax]
RYOMA:2C8B3596 64 89 20 mov fs:[eax], esp
RYOMA:2C8B3599 E9 F0 9F 08 00 jmp near ptr 2C93D58Eh ; 进入虚拟机
进入VM前会做一些初始化工作:
首先会push VM_Data,然后再push ret_addr,例如这里
.rdata:2C93D754 9C pushf
.rdata:2C93D755 C7 04 24 12 D7 93+ mov dword ptr [esp], offset VM_Data
.rdata:2C93D75C 7D 00 jge short $+2
.rdata:2C93D75E E9 03 00 00 00 jmp loc_2C93D766
.rdata:2C93D75E ; ---------------------------------------------------------------------------
.rdata:2C93D763 67 db 67h ; g
.rdata:2C93D764 3E db 3Eh ; >
.rdata:2C93D765 09 db 9
.rdata:2C93D766 ; ---------------------------------------------------------------------------
.rdata:2C93D766
.rdata:2C93D766 loc_2C93D766: ; CODE XREF: .rdata:2C93D75Ej
.rdata:2C93D766 68 8E D7 93 2C push offset loc_2C93D78E
loc_2C93D78E就是执行完vm后的返回地址,这里是个call
然后跳到一个固定的VM_Fucking_In上面,如下
.rdata:2C93534E 9C pushf
.rdata:2C93534F 89 2C 24 mov [esp], ebp ; push ebp
.rdata:2C935352 89 F6 mov esi, esi
.rdata:2C935354 E9 03 00 00 00 jmp loc_2C93535C
.rdata:2C935354 ; ---------------------------------------------------------------------------
.rdata:2C935359 41 db 41h ; A
.rdata:2C93535A BF db 0BFh ; ?
.rdata:2C93535B 44 db 44h ; D
.rdata:2C93535C ; ---------------------------------------------------------------------------
.rdata:2C93535C
.rdata:2C93535C loc_2C93535C: ; CODE XREF: .rdata:2C935354j
.rdata:2C93535C 7D 00 jge short $+2
.rdata:2C93535E 8B EC mov ebp, esp
.rdata:2C935360 75 00 jnz short $+2
.rdata:2C935362 E9 00 00 00 00 jmp $+5
.rdata:2C935367 75 00 jnz short $+2
.rdata:2C935369 9C pushf
.rdata:2C93536A EB 00 jmp short $+2
.rdata:2C93536C E9 03 00 00 00 jmp loc_2C935374
.rdata:2C93536C ; ---------------------------------------------------------------------------
.rdata:2C935371 74 db 74h ; t
.rdata:2C935372 85 db 85h ; ?
.rdata:2C935373 DD db 0DDh ; ?
.rdata:2C935374 ; ---------------------------------------------------------------------------
.rdata:2C935374
.rdata:2C935374 loc_2C935374: ; CODE XREF: .rdata:2C93536Cj
.rdata:2C935374 7D 00 jge short $+2
.rdata:2C935376 9C pushf
.rdata:2C935377 89 2C 24 mov [esp], ebp ; push ebp
.rdata:2C93537A 7D 00 jge short $+2
.rdata:2C93537C E9 04 00 00 00 jmp loc_2C935385
........
上面的代码去掉花以后就是:
push ebp
mov ebp,esp
pushfd //保存一些寄存器
push ebp
push edi
push esi
push ecx
push edx
push ebx
push eax
push esp //代表下面保存reg的开始位置,可以理解成一个结构
push [ebp+8] //VM_Data
call VM_
真正的地方是在VM_里面,可以看出,这里的esp,ebp都不是最早进入VM时候的esp,ebp了。
下面我们再来看VM_,选几个重点地方分析一下。
RYOMA:2C8ADDF0 VM_ proc near
RYOMA:2C8ADDF0
RYOMA:2C8ADDF0 var_10038_VM_Str= byte ptr -10038h
RYOMA:2C8ADDF0 var_1074 = dword ptr -1074h
RYOMA:2C8ADDF0 var_38_regtype = dword ptr -38h
RYOMA:2C8ADDF0 var_34_reg_type = dword ptr -34h
RYOMA:2C8ADDF0 var_30_pVM_Struct= dword ptr -30h
RYOMA:2C8ADDF0 var_2C_p = dword ptr -2Ch
RYOMA:2C8ADDF0 var_28_pVM_Struct= dword ptr -28h
RYOMA:2C8ADDF0 var_24_VM_Regs = dword ptr -24h
RYOMA:2C8ADDF0 var_1D = byte ptr -1Dh
RYOMA:2C8ADDF0 var_1C = dword ptr -1Ch
RYOMA:2C8ADDF0 var_18 = dword ptr -18h
RYOMA:2C8ADDF0 var_12 = byte ptr -12h
RYOMA:2C8ADDF0 var_11 = byte ptr -11h
RYOMA:2C8ADDF0 var_10_regs = dword ptr -10h
RYOMA:2C8ADDF0 var_C_PVM_regEAX= dword ptr -0Ch
RYOMA:2C8ADDF0 var_8_count = dword ptr -8
RYOMA:2C8ADDF0 var_4_i_regs = dword ptr -4
RYOMA:2C8ADDF0 arg_0_VM_Data = dword ptr 8
RYOMA:2C8ADDF0 arg_4_regs = dword ptr 0Ch
RYOMA:2C8ADDF0
RYOMA:2C8ADDF0 55 push ebp
RYOMA:2C8ADDF1 8B EC mov ebp, esp
RYOMA:2C8ADDF3 50 push eax
RYOMA:2C8ADDF4 B8 10 00 00 00 mov eax, 10h
RYOMA:2C8ADDF9
RYOMA:2C8ADDF9 loop_: ; CODE XREF: VM_+11j
RYOMA:2C8ADDF9 81 C4 04 F0 FF FF add esp, -0FFCh
RYOMA:2C8ADDFF 50 push eax
RYOMA:2C8ADE00 48 dec eax
RYOMA:2C8ADE01 75 F6 jnz short loop_
//这里vm分配自己的堆栈空间。
RYOMA:2C8ADE03 8B 45 FC mov eax, [ebp+var_4_i_regs] ; 没有意义这里
RYOMA:2C8ADE06 83 C4 CC add esp, -34h
RYOMA:2C8ADE09 53 push ebx
RYOMA:2C8ADE0A 56 push esi
RYOMA:2C8ADE0B 57 push edi
RYOMA:2C8ADE0C 8B 75 0C mov esi, [ebp+arg_4_regs]
RYOMA:2C8ADE0F E9 E6 05 00 00 jmp set_vm_struct
RYOMA:2C8ADE14 ; ---------------------------------------------------------------------------
RYOMA:2C8ADE14
RYOMA:2C8ADE14 loop_fucking_vm: ; CODE XREF: VM_+5Aj
RYOMA:2C8ADE14 ; VM_+130j ...
RYOMA:2C8ADE14 0F B6 43 38 movzx eax, byte ptr [ebx+38h]
RYOMA:2C8ADE18 2C 01 sub al, 1 ; 0 4
RYOMA:2C8ADE1A 72 30 jb short less_0
RYOMA:2C8ADE1C 2C 03 sub al, 3
RYOMA:2C8ADE1E 0F 85 6C 05 00 00 jnz get_next_pcode
RYOMA:2C8ADE24 C6 43 38 00 mov byte ptr [ebx+38h], 0
RYOMA:2C8ADE28 C6 43 39 0D mov byte ptr [ebx+39h], 0Dh
RYOMA:2C8ADE2C 8B 43 3B mov eax, [ebx+3Bh]
RYOMA:2C8ADE2F 40 inc eax
RYOMA:2C8ADE30 89 43 40 mov [ebx+40h], eax ; size
RYOMA:2C8ADE33 8B 43 58 mov eax, [ebx+VM_Struct.VM_regESP]
RYOMA:2C8ADE36 2B 43 40 sub eax, [ebx+40h]
RYOMA:2C8ADE39 89 43 3B mov [ebx+3Bh], eax
RYOMA:2C8ADE3C 8B 43 40 mov eax, [ebx+40h]
RYOMA:2C8ADE3F C6 44 03 27 C3 mov byte ptr [ebx+eax+27h], 0C3h ; ret
RYOMA:2C8ADE44 8D 43 28 lea eax, [ebx+VM_Struct.Curr_PCode]
RYOMA:2C8ADE47 89 43 44 mov [ebx+44h], eax ; Curr_PCode
RYOMA:2C8ADE4A EB C8 jmp short loop_fucking_vm
RYOMA:2C8ADE4C ; ---------------------------------------------------------------------------
RYOMA:2C8ADE4C
RYOMA:2C8ADE4C less_0: ; CODE XREF: VM_+2Aj
RYOMA:2C8ADE4C 0F B6 43 39 movzx eax, byte ptr [ebx+39h]
RYOMA:2C8ADE50 34 00 xor al, 0 ; //没意义的
RYOMA:2C8ADE52 0F BE C0 movsx eax, al
RYOMA:2C8ADE55 89 45 FC mov [ebp+var_4_i_regs], eax
RYOMA:2C8ADE58 8B 45 FC mov eax, [ebp+var_4_i_regs]
RYOMA:2C8ADE5B 83 F8 23 cmp eax, 23h ; switch 36 cases
RYOMA:2C8ADE5E 0F 87 29 05 00 00 ja case_default_next_pcode ; default
RYOMA:2C8ADE5E ; jumptable 2C8ADE64 cases 0,1
RYOMA:2C8ADE64 FF 24 85 6B DE 8A+ jmp dword ptr VM_Dispatch_Table[eax*4] ; switch jump
RYOMA:2C8ADE64 2C ; ---------------------------------------------------------------------------
RYOMA:2C8ADE6B VM_Dispatch_Table: ; DATA XREF: VM_+74r
RYOMA:2C8ADE6B 8D E3 8A 2C 8D E3+ dd offset case_default_next_pcode ; jump table for switch statement
RYOMA:2C8ADE6B 8A 2C AC E3 8A 2C+ dd offset case_default_next_pcode
RYOMA:2C8ADE6B 00 DF 8A 2C 11 DF+ dd offset case_disptach_2_vm_end
RYOMA:2C8ADE6B 8A 2C 1E E0 8A 2C+ dd offset case_disptach_3_VM_Push_
RYOMA:2C8ADE6B B1 E0 8A 2C A6 DF+ dd offset case_disptach_4_VM_GetRegValue
RYOMA:2C8ADE6B 8A 2C 9B E0 8A 2C+ dd offset case_disptach_5_movs
RYOMA:2C8ADE6B 25 DF 8A 2C C7 E0+ dd offset case_disptach_6_VM_Pop_Reg
RYOMA:2C8ADE6B 8A 2C D0 E0 8A 2C+ dd offset case_disptach_7_vm_popad
RYOMA:2C8ADE6B DD E0 8A 2C EA E0+ dd offset case_disptach_8_vm_pushad
RYOMA:2C8ADE6B 8A 2C 4B E2 8A 2C+ dd offset case_disptach_9_movs
RYOMA:2C8ADE6B 5F E2 8A 2C 6F E2+ dd offset case_disptach_10_VM_Add_esp_4
RYOMA:2C8ADE6B 8A 2C 8D E2 8A 2C+ dd offset case_disptach_11_VM_Pushfd
RYOMA:2C8ADE6B 80 E2 8A 2C BC DF+ dd offset case_disptach_12_VM_Popfd
RYOMA:2C8ADE6B 8A 2C E8 DF 8A 2C+ dd offset case_disptach_13_run_in_stack
RYOMA:2C8ADE6B CE DF 8A 2C 10 E0+ dd offset case_disptach_14_set_run_in_stack_size
RYOMA:2C8ADE6B 8A 2C F6 DF 8A 2C+ dd offset case_disptach_15_SetRegValue
RYOMA:2C8ADE6B A1 E2 8A 2C 6B E3+ dd offset case_disptach_16_GetMemValue
RYOMA:2C8ADE6B 8A 2C 7E E3 8A 2C+ dd offset case_disptach_17_GetRegValueSrc
RYOMA:2C8ADE6B C3 E2 8A 2C 09 E3+ dd offset case_disptach_18_mov_mem_value
RYOMA:2C8ADE6B 8A 2C 16 E3 8A 2C+ dd offset case_disptach_19_VM_MovMemWithReg
RYOMA:2C8ADE6B 2A E3 8A 2C 3B E3+ dd offset case_disptach_20_set_offset_0
RYOMA:2C8ADE6B 8A 2C 4A E3 8A 2C+ dd offset case_disptach_21_mov_
RYOMA:2C8ADE6B 57 E3 8A 2C E5 E2+ dd offset case_disptach_22_set_dest_offset_0
RYOMA:2C8ADE6B 8A 2C F5 E2 8A 2C dd offset case_disptach_23_mov_mem_offset_reg
RYOMA:2C8ADE6B dd offset case_disptach_24_run_in_stack_get_cupid
RYOMA:2C8ADE6B dd offset case_disptach_25_VM_idiv
RYOMA:2C8ADE6B dd offset case_disptach_26_VM_imul
RYOMA:2C8ADE6B dd offset case_disptach_27_run_in_stack_cc
RYOMA:2C8ADE6B dd offset case_disptach_28_add_value
RYOMA:2C8ADE6B dd offset case_disptach_29_get_reg_value
RYOMA:2C8ADE6B dd offset case_disptach_30_GetMemValue
RYOMA:2C8ADE6B dd offset case_disptach_31_add_mem
RYOMA:2C8ADE6B dd offset case_disptach_32_VM_xor
RYOMA:2C8ADE6B dd offset case_disptach_33_get_reg_value
RYOMA:2C8ADE6B dd offset case_disptach_34_sub_
RYOMA:2C8ADE6B dd offset case_disptach_35_get_reg_value
.............................
进入VM_后,分配完vm_stack,马上就跳到set_vm_struct上面去了
RYOMA:2C8AE3FA set_vm_struct: ; CODE XREF: VM_+1Fj
RYOMA:2C8AE3FA 8D 9D C8 FF FE FF lea ebx, [ebp+var_10038_VM_Str]
RYOMA:2C8AE400 33 C0 xor eax, eax
RYOMA:2C8AE402 89 45 FC mov [ebp+var_4_i_regs], eax
RYOMA:2C8AE405 B8 74 A2 8B 2C mov eax, offset reg_type
RYOMA:2C8AE40A
RYOMA:2C8AE40A set_regs: ; CODE XREF: VM_+633j
RYOMA:2C8AE40A 8B 55 FC mov edx, [ebp+var_4_i_regs]
RYOMA:2C8AE40D 03 D2 add edx, edx
RYOMA:2C8AE40F 03 D2 add edx, edx
RYOMA:2C8AE411 03 D6 add edx, esi
RYOMA:2C8AE413 8B 12 mov edx, [edx]
RYOMA:2C8AE415 0F B6 08 movzx ecx, byte ptr [eax]
RYOMA:2C8AE418 89 14 8B mov [ebx+ecx*4], edx
RYOMA:2C8AE41B FF 45 FC inc [ebp+var_4_i_regs]
RYOMA:2C8AE41E 40 inc eax
RYOMA:2C8AE41F 83 7D FC 08 cmp [ebp+var_4_i_regs], 8
RYOMA:2C8AE423 75 E5 jnz short set_regs
RYOMA:2C8AE425 8B 45 08 mov eax, [ebp+arg_0_VM_Data]
RYOMA:2C8AE428 89 43 70 mov [ebx+70h], eax //保存VM_Data
RYOMA:2C8AE42B 56 push esi
RYOMA:2C8AE42C 8B F0 mov esi, eax
RYOMA:2C8AE42E 8D 7B 28 lea edi, [ebx+VM_Struct.Curr_PCode]
RYOMA:2C8AE431 B9 08 00 00 00 mov ecx, 8
RYOMA:2C8AE436 F3 A5 rep movsd
RYOMA:2C8AE438 5E pop esi
RYOMA:2C8AE439 8D 43 48 lea eax, [ebx+VM_Struct.VM_regEAX]
RYOMA:2C8AE43C 89 45 D4 mov [ebp+var_2C_p], eax
RYOMA:2C8AE43F 89 5D D0 mov [ebp+var_30_pVM_Struct], ebx
RYOMA:2C8AE442 33 C0 xor eax, eax
RYOMA:2C8AE444
RYOMA:2C8AE444 loop_set_vm_regs: ; CODE XREF: VM_+66Bj
RYOMA:2C8AE444 3C 05 cmp al, 5
RYOMA:2C8AE446 74 10 jz short loc_2C8AE458
RYOMA:2C8AE448 0F B6 D0 movzx edx, al
RYOMA:2C8AE44B 8B 4D D0 mov ecx, [ebp+var_30_pVM_Struct]
RYOMA:2C8AE44E FF 34 91 push dword ptr [ecx+edx*4]
RYOMA:2C8AE451 8B 4D D4 mov ecx, [ebp+var_2C_p]
RYOMA:2C8AE454 5F pop edi ; mov edi,[ecx+edx*4]
RYOMA:2C8AE455 89 3C 91 mov [ecx+edx*4], edi
RYOMA:2C8AE458
RYOMA:2C8AE458 loc_2C8AE458: ; CODE XREF: VM_+656j
RYOMA:2C8AE458 40 inc eax
RYOMA:2C8AE459 3C 0A cmp al, 0Ah
RYOMA:2C8AE45B 75 E7 jnz short loop_set_vm_regs
RYOMA:2C8AE45D 8B 43 6C mov eax, [ebx+VM_Struct.VM_keydata]
RYOMA:2C8AE460 31 43 6C xor [ebx+VM_Struct.VM_keydata], eax ; 清0
RYOMA:2C8AE463 8B C3 mov eax, ebx
RYOMA:2C8AE465 05 00 00 01 00 add eax, 10000h
RYOMA:2C8AE46A 83 E8 74 sub eax, 74h
RYOMA:2C8AE46D 89 43 58 mov [ebx+VM_Struct.VM_regESP], eax ; 设置VM_ESP
RYOMA:2C8AE470 8B 43 14 mov eax, [ebx+VM_Struct.regEBP] ; VM_EBP
RYOMA:2C8AE473 83 C0 04 add eax, 4
RYOMA:2C8AE476 89 43 5C mov [ebx+VM_Struct.VM_regEBP], eax ; 指向返回地址
RYOMA:2C8AE479 E9 96 F9 FF FF jmp loop_fucking_vm
这里涉及到一个VM_Struct
00000000 VM_Struct struc ; (sizeof=0x74)
00000000 regEAX dd ?
00000004 regECX dd ?
00000008 regEDX dd ?
0000000C regEBX dd ?
00000010 regESP dd ?
00000014 regEBP dd ?
00000018 regESI dd ?
0000001C regEDI dd ?
00000020 eflags dd ?
00000024 count dd ?
00000028 Curr_PCode db 32 dup(?)
00000048 VM_regEAX dd ?
0000004C VM_regECX dd ?
00000050 VM_regEDX dd ?
00000054 VM_regEBX dd ?
00000058 VM_regESP dd ?
0000005C VM_regEBP dd ?
00000060 VM_regESI dd ?
00000064 VM_regEDI dd ?
00000068 VM_eflags dd ?
0000006C VM_count dd ?
00000070 VM_Data dd ?
00000074 VM_Struct ends
set_vm_struct一开始,把作为参数传进来的regs保存到VM_Struct的0h-20h,然后把参数1 VM_Data保存到70h,然后复制一份当前的
PCode_data到28h,一共20h个BYTES,就是我们前面所说的PCode,还有就解释为什么有38h,39h等等了。下面就是设置VM_regs了,
VM_Struct里面一共出现了两套reg,一套是真实的regs 0-20h 一套是VM里面参与运算的regs,48h-68h,这套regs在set_vm_struct后期
通过真实的regs赋值,注意VM_regESP,VM_regEBP都是通过别的途径赋值的,可以进上面程序有标注,VM实行的push,pop都是相对于vm_stack的
这点要注意。
准备工作做好了,就开始解析PCode了,一共0x23个dispatch,都表明了,我写的程序里面都有,就不在多说了,主要说说的就是:
case_disptach_13_run_in_stack:
这个是把一些x86的代码,通过PCode的x86code[0x10]传过来,送到vm_stack里面,在vm_stack里面执行,具体可以看看idb文件。
这个vm还是有点bug,具体在case_disptach_5_movs和case_disptach_9_movs上面,
case_disptach_5_movs的作用就是把内存中一段内容movs到vm_stack中,case_disptach_9_movs正好方向相反。
RYOMA:2C8AE01E case_disptach_5_movs: ; CODE XREF: VM_+74j
RYOMA:2C8AE01E ; DATA XREF: VM_:VM_Dispatch_Tableo
RYOMA:2C8AE01E 8B 43 40 mov eax, [ebx+40h] ; jumptable 2C8ADE64 case 5
RYOMA:2C8AE021 85 C0 test eax, eax ; size
RYOMA:2C8AE023 79 03 jns short loc_2C8AE028
RYOMA:2C8AE025 83 C0 03 add eax, 3
RYOMA:2C8AE028
RYOMA:2C8AE028 loc_2C8AE028: ; CODE XREF: VM_+233j
RYOMA:2C8AE028 C1 F8 02 sar eax, 2 //开始时候是按照DWORD对其传送的
RYOMA:2C8AE02B 89 45 F8 mov [ebp+var_8_count], eax
RYOMA:2C8AE02E 33 C0 xor eax, eax
RYOMA:2C8AE030 89 45 FC mov [ebp+var_4_i_regs], eax
RYOMA:2C8AE033 83 7D F8 00 cmp [ebp+var_8_count], 0
RYOMA:2C8AE037 74 1D jz short loc_2C8AE056
RYOMA:2C8AE039
RYOMA:2C8AE039 loc_2C8AE039: ; CODE XREF: VM_+264j
RYOMA:2C8AE039 8B 43 58 mov eax, [ebx+VM_Struct.VM_regESP]
RYOMA:2C8AE03C 03 45 FC add eax, [ebp+var_4_i_regs]
RYOMA:2C8AE03F 8B 00 mov eax, [eax]
RYOMA:2C8AE041 8B 53 3B mov edx, [ebx+3Bh]
RYOMA:2C8AE044 03 55 FC add edx, [ebp+var_4_i_regs]
RYOMA:2C8AE047 89 02 mov [edx], eax
RYOMA:2C8AE049 83 45 FC 04 add [ebp+var_4_i_regs], 4
RYOMA:2C8AE04D FF 4D F8 dec [ebp+var_8_count]
RYOMA:2C8AE050 83 7D F8 00 cmp [ebp+var_8_count], 0
RYOMA:2C8AE054 75 E3 jnz short loc_2C8AE039
RYOMA:2C8AE056
RYOMA:2C8AE056 loc_2C8AE056: ; CODE XREF: VM_+247j
RYOMA:2C8AE056 8B 43 40 mov eax, [ebx+40h]
RYOMA:2C8AE059 25 03 00 00 80 and eax, 80000003h //这里是传送多余出来的BYTE
RYOMA:2C8AE05E 79 05 jns short loc_2C8AE065
RYOMA:2C8AE060 48 dec eax
RYOMA:2C8AE061 83 C8 FC or eax, 0FFFFFFFCh
RYOMA:2C8AE064 40 inc eax
RYOMA:2C8AE065
RYOMA:2C8AE065 loc_2C8AE065: ; CODE XREF: VM_+26Ej
RYOMA:2C8AE065 89 45 F8 mov [ebp+var_8_count], eax
RYOMA:2C8AE068 33 C0 xor eax, eax
RYOMA:2C8AE06A 89 45 FC mov [ebp+var_4_i_regs], eax //出错的地方在这里,var_4_i_regs清0了,又从开始地方传起来了
RYOMA:2C8AE06D 83 7D F8 00 cmp [ebp+var_8_count], 0
RYOMA:2C8AE071 74 1D jz short loc_2C8AE090
RYOMA:2C8AE073
RYOMA:2C8AE073 loc_2C8AE073: ; CODE XREF: VM_+29Ej
RYOMA:2C8AE073 8B 43 58 mov eax, [ebx+VM_Struct.VM_regESP]
RYOMA:2C8AE076 03 45 FC add eax, [ebp+var_4_i_regs]
RYOMA:2C8AE079 0F B6 00 movzx eax, byte ptr [eax]
RYOMA:2C8AE07C 8B 53 3B mov edx, [ebx+3Bh]
RYOMA:2C8AE07F 03 55 FC add edx, [ebp+var_4_i_regs]
RYOMA:2C8AE082 88 02 mov [edx], al
RYOMA:2C8AE084 FF 45 FC inc [ebp+var_4_i_regs]
RYOMA:2C8AE087 FF 4D F8 dec [ebp+var_8_count]
RYOMA:2C8AE08A 83 7D F8 00 cmp [ebp+var_8_count], 0
RYOMA:2C8AE08E 75 E3 jnz short loc_2C8AE073
case_disptach_9_movs也是这个问题。
差不多就这么多,不懂的可以看程序,和idb。
执行完vm后,会
pop eax
pop ebx
pop edx
pop ecx
pop esi
pop edi
pop ebp
popfd
ret 4
返回到上面提到的那个返回地址。
Private执行是会释放一个dll到自身空间2C48C000里面,这个dll就是这个vm引擎所在地方,我把它剥离出来,fix一下,可以反汇编大概看看。
^_^
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课