吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 72507|回复: 232
收起左侧

[原创] VMProtect 3.09 虚拟机架构浅析

    [复制链接]
Cr4ckm3 发表于 2017-3-10 00:36
本帖最后由 Cr4ckm3 于 2017-3-10 09:59 编辑

0x00 写在前面
最近两周一直在研究VMProtect相关的东西,发现VMProtect 2.x 被研究的比较充分,FKVMP、Zeus、VMP分析插件1.4等神器也出来了很久。但VMProtect 3 没有在论坛内找到相关的资料,这里写一点简单分析作为抛砖引玉之用。新人第一贴,求论坛的大大们多多鼓励。

根据官方公告,VMProtect 3使用了新的虚拟机架构,本文通过分析自己加虚拟化的简单程序,介绍一下VMProtect 3虚拟机的基本架构,并与VMProtect 2.x进行简单对比。
这里强调一下,本贴只介绍虚拟机架构方面的内容,关于脱壳、IAT恢复、过anti等等请参考其他大佬的文章。

0x01 初步分析
分析的样本是用MASM32编写的小程序,源代码如下:
[Asm] 纯文本查看 复制代码
include \masm32\include\masm32rt.inc

.data?
value dd ?
int_array dd 100 dup(?)

.data
;item dd 0
text db "Hello Text",0
caption db "Hello Caption",0

.code

start:

call main
push NULL
call ExitProcess


main proc

mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
mov eax, 0deadbeefh
ret
main endp

end start


编译完成后大小1.50 KB (1,536 字节)

使用VMProtect 1.81 demo版本对main函数(地址0x40100C)加虚拟化,最快速度,关掉一切其他保护。
这里之所以使用 1.81 demo这么低的版本,主要原因是该版本VMP中的虚拟机代码没有混淆,生成的bytecode也比较规则,没有2.x版本的冗余分支,同时又能被VMP分析插件1.4完美支持,因此非常适合拿来学习VMP虚拟机结构。
加密后文件大小5.00 KB (5,120 字节)

再使用VMProtect 2.12.3版本加虚拟化,选项相同 ,关掉所有保护。
加密后文件大小15.0 KB (15,360 字节)

再使用论坛的VMProtect 3.09版本加虚拟化,选项相同,关掉所有保护。
加密后文件大小516 KB (528,896 字节)

可见VMProtect 3.x版本加密后的代码量有非常大的变化,注意这里关掉了所有保护选项的情况,因此这些多出来的代码不是壳代码,也不是调试器检测的代码,就是实实在在虚拟化后的指令。
这么为什么会多出这么多,这里简单分析一下。

需要用到OD的追踪功能(很好用的功能,但大家经常忽略掉他)
OD分别打开两个文件,Ctrl+F11 跟踪步入,64位电脑先将ntdll.dll和kernel32.dll标记为系统DLL,避免记录到trace中。
跟踪完成后分析两个程序产生trace的区别。

console.vmp_1.81_demo.exe  生成527条trace
用OD统计下指令数(注意在选项中关掉统计时将相邻指令合并的选项),前几条是这样
[Asm] 纯文本查看 复制代码
Count Address Command Comment
48. 00403025 mov al,byte ptr ds:[esi]
48. 00403027 movzx eax,al
48. 0040302A sub esi,-0x1
48. 0040302D jmp dword ptr ds:[eax*4+0x403103]


console.vmp_2.12.3.exe 生成14277条trace
用OD统计下指令数,前几条是这样
[Asm] 纯文本查看 复制代码
Count Address Command Comment
149. 004046E5 mov ecx,dword ptr ds:[eax*4+0x405254]
149. 004046EC pushad
149. 004046ED lea esp,dword ptr ss:[esp+0x2C]
149. 004046F1 jle console_.00404622
149. 00404833 neg cx
149. 00404836 sub cx,0xFBDF


console.vmp_3.09.exe 生成2238条Trace
[Asm] 纯文本查看 复制代码
Count Address Command Comment
18. 00421B90 jmp edi
18. 0042D77B lea eax,dword ptr ss:[esp+0x60]
18. 0042D77F cmp sp,0x6934
18. 0042D784 cmp ebp,eax
18. 0042D786 ja console_.00421B90
2. 00408854 jmp edi
2. 004099CF inc eax
2. 004099D0 ror eax,0x2
2. 004099D3 jmp console_.0041442D


如果了解VMP架构的小伙伴应该发现问题了。我们具体比较一下
先说1.81,由于是demo版本,所以没有混淆,所以trace数相当的少。
2.12版本加了大量垃圾指令,同时也会额外生成几条bytecode,所以Trace数量猛增。
关键是3.09版本,其文件大小是2.12版本的几十倍,但trace数却只是2.12版本的几分之一。
再看指令数统计,答案就很明白了。

我们知道VMP 1.x 2.x的虚拟机结构都是典型的取指令、解码opcode、根据opcode进行dispatch的过程,整个虚拟机是个大循环结构,handler表最多0xFF大小,所有x86指令都由这0xFF(由于有重复,实际会少)个handler模拟完成。
执行次数最多的jmp dword ptr ds:[eax*4+0x403103]和mov ecx,dword ptr ds:[eax*4+0x405254]都是典型的dispatch指令。
由于循环的存在,很少的指令也会生成较多的Trace

反观3.x 可以看到只有5条指令重复执行了18次,剩下的指令最多只执行过2次。可以说3.x循环的部分是相关少的。那么这些取指令和dispatch的过程都是独立的。最为可怕的是handler本身也不是复用的。也就是说两条相同的指令会生成不同的handler代码,尽管他们实现的功能是完全相同的。因此文件大小会发生极大的变化。
(这里可能不确切,更大的可能是VMProtect的handler表变大了,由于测试指令过少,所以没有发生重复。如果真的每条指令都单独生成一系列handler,那加密指令多的时候文件会膨胀的可怕。但确定的一点是,原本复杂的循环结构消失了。)

0x02 版本对比

前面已经说过没有了循环结构,那么具体分析一下3.x的虚拟机是如何工作的。
首先简单说一下2.x的虚拟机,资料很多,不多说了,只提几个要点。

VMP虚拟机是栈式机,与x86体系结构的寄存器式虚拟机不同。x86的add eax, ebx指令,在VMP中会变成push ebx, push eax, add,  pop eax的形式。这里的栈称为虚拟栈。
EBP指向虚拟机栈顶,充当x86中的ESP功能,即虚拟机的vm_esp。
虚拟机执行的字节码是编码在程序中的,ESI指向其地址,ESI也就是vm_eip
EDI指向寄存器数组,也就是vm_context。2.x版本的vm_context也在栈中,在EBP上方。(其实最特别早期的VMP版本中vm_context也曾位于全局数据区,过段时间会写篇关于VMP各版本变化过程的文章,敬请期待)
vm_context包含16个4字节寄存器(32位的情况下)
栈结构是这样:
栈底--->ebp------>edi(vm_context)---> esp
EBX 经常参与解密,保存密钥。

说了关于旧版本的废话,这里直接抛出新版本的结构对比:
相同点:
ESI依然是vm_eip,指向要解析的字节码。
EBP依然是vm_esp,指向虚拟栈顶
EBX 依然经常参与解密。
不同点:
栈结构是这样:
栈底--->ebp------>esp(vm_context)
ESP成为vm_context指针EDI作为跳转寄存器,统一的dispatcher消失,每次跳转需要从ESI取出4字节进行解密加到EDI上,然后jmp edi(或push edi,ret 功能一样)
这里ESP成为vm_context指针的设计对我们来说是个好消息,因为vm_context不能随便移动,因此涉及到栈操作的垃圾指令大大减少了。
但jmp edi的跳转方式很让人头疼。
FKVMP和VMP分析插件等神器的基本逻辑是找到dispatcher 即jmp dword ptr ds:[eax*4+0x403103]类似的代码
然后枚举eax的值0~0xFF即可得到所有handler的入口,根据指令特征识别handler。依次解密出bytecode。

3.x不再有统一的dispatch过程,使得之前的神器从架构上无法应用到3.x版本。


0x3 具体分析

前面是为了有个统一的印象。
接下来具体分析。

我们直接看前面OD得到的Trace,实际的trace中有大量的垃圾指令,但正如前面所说,多不涉及栈操作,因此比较简单,以下的分析均是去了垃圾指令的,所以会发现地址不太连续。

虚拟机初始化部分
[Asm] 纯文本查看 复制代码

<ModuleEntryPoint>call console_.0040100C                    ; ESP=0019FF80

; jmp push call入口, 和vmp 2.x差不多
0040100C Main     jmp console_.00481F2C
00481F2C Main     push 0x6D3BB7D7                           ; ESP=0019FF7C
00481F31 Main     call console_.00436946                    ; ESP=0019FF78

;寄存器入栈
00436946 Main     push eax                                  ; ESP=0019FF74
00436948 Main     push edi                                  ; ESP=0019FF70
00436949 Main     push ebp                                  ; ESP=0019FF6C
0043694A Main     pushfd                                    ; ESP=0019FF68
0043694C Main     push edx                                  ; ESP=0019FF64
00436953 Main     push ebx                                  ; ESP=0019FF60
00436958 Main     push ecx                                  ; ESP=0019FF5C
0043695C Main     push esi                                  ; ESP=0019FF58
0043695D Main     mov eax,0x0                               ; EAX=00000000
00436965 Main     push eax                                  ; ESP=0019FF54


; ESI = 入口处压入的常数,解密ESI
00436968 Main     mov esi,dword ptr ss:[esp+0x28]           ; ESI=6D3BB7D7
0043696C Main     neg esi                                   ; FL=CAS, ESI=92C44829
0043696E Main     not esi                                   ; ESI=6D3BB7D6
0043697C Main     neg esi                                   ; FL=CAS, ESI=92C4482A
00436984 Main     bswap esi                                 ; ESI=2A48C492
0043698A Main     not esi                                   ; ESI=D5B73B6D
0043698C Main     xor esi,0x2A080CB4                        ; FL=S, ESI=FFBF37D9
00436996 Main     not esi                                   ; ESI=0040C826
0043699B Main     lea esi,dword ptr ds:[esi+eax]
0043699E Main     inc al                                    ; FL=C, EAX=00000001

; 分配栈空间,仍为0xC0
; ebp仍为栈指针, esp指向context
004369A7 Main     mov ebp,esp                               ; EBP=0019FF54
004369B0 Main     sub esp,0xC0                              ; ESP=0019FE94

; 初始化EBX
004369BB Main     mov ebx,esi                               ; EBX=0040C826


; edi = 0x4369DE 初始化EDI
004369DE Main     lea edi,dword ptr ds:[0x4369DE]           ; EDI=004369DE



跳转到第一个handler


[Asm] 纯文本查看 复制代码
; 取ESI的4字节
004369EA Main     mov eax,dword ptr ds:[esi]                ; EAX=D7FE101E
; vEIP += 4

004369F0 Main     add esi,0x4                               ; FL=0, ESI=0040C82A

; 解码EAX
004369FE Main     xor eax,ebx                               ; FL=S, EAX=D7BED838
00436A00 Main     inc eax                                   ; FL=PS, EAX=D7BED839
0045D528 Main     ror eax,0x2                               ; FL=PS, EAX=75EFB60E
00410CB9 Main     inc eax                                   ; FL=P, EAX=75EFB60F
00410CBD Main     xor eax,0x75EF373B                        ; FL=0, EAX=00008134
0044A61F Main     dec eax                                   ; FL=P, EAX=00008133
00449463 Main     xor ebx,eax                               ; FL=0, EBX=00404915

; 跳转到 edi+eax
00449465 Main     add edi,eax                               ; FL=PA, EDI=0043EB11
00438226 Main     push edi                                  ; ESP=0019FE90
00438227 Main     retn                                      ; ESP=0019FE94



这里就开始是handler部分了,与2.x 一样,最开始的几条bytecode指令是把栈中的真实寄存器pop到虚拟寄存器数组vm_context中


[Asm] 纯文本查看 复制代码

; ======================= handler 
; vPopReg4 R14 (0x38)
; 这里handler命令规则采用VMP分析插件的命名风格,表示从栈中弹出4字节数据到寄存器R13中(以R0开头)
; 解码寄存器下标 al
0043EB11 Main     movzx eax,byte ptr ds:[esi]               ; EAX=000000F3
0043EB14 Main     add esi,0x1                               ; FL=P, ESI=0040C82B
0043EB1D Main     xor al,bl                                 ; FL=S, EAX=000000E6
0043EB2A Main     not al                                    ; EAX=00000019
0043EB38 Main     xor al,0x7D                               ; FL=0, EAX=00000064
0043EB3F Main     inc al                                    ; FL=P, EAX=00000065
0043EB43 Main     xor al,0xF6                               ; FL=PS, EAX=00000093
0043EB49 Main     ror al,1                                  ; EAX=000000C9
0043EB4E Main     dec al                                    ; FL=CS, EAX=000000C8
0043EB58 Main     neg al                                    ; FL=CA, EAX=00000038
0043EB64 Main     xor bl,al                                 ; EBX=0040492D

; 取出栈顶的值,退出4字节栈空间,赋到vm_context中
; 明显的pop操作,除了寄存器使用不同,实现方法其实和2.x是一样的
0043EB6B Main     mov ecx,dword ptr ss:[ebp]                ; ECX=00000000
0042B819 Main     add ebp,0x4                               ; FL=0, EBP=0019FF58
004539B2 Main     mov dword ptr ss:[esp+eax],ecx


第一条handler结束后,又是跳转
虽然功能完全一样,但VMP又实现出了完全独立了另一套代码
以此规避掉了循环

[Asm] 纯文本查看 复制代码
; 接下来又从ESI取4字节,解密并跳转  上次解密代码的地址是004369EA
004539B5 Main     mov eax,dword ptr ds:[esi]                ; EAX=D7FCBE81
004539B7 Main     lea esi,dword ptr ds:[esi+0x4]            ; ESI=0040C82F
004539BE Main     xor eax,ebx                               ; FL=PS, EAX=D7BCF7AC
0044BADF Main     inc eax                                   ; FL=S, EAX=D7BCF7AD
0044BAE2 Main     ror eax,0x2                               ; EAX=75EF3DEB
0043D2C3 Main     inc eax                                   ; FL=0, EAX=75EF3DEC
0043D2C6 Main     xor eax,0x75EF373B                        ; FL=P, EAX=00000AD7
0045507E Main     dec eax                                   ; FL=0, EAX=00000AD6
00455081 Main     xor ebx,eax                               ; FL=0, EBX=004043FB
0045508A Main     add edi,eax                               ; FL=P, EDI=0043F5E7
0045508C Main     push edi                                  ; ESP=0019FE90
0045508D Main     retn                                      ; ESP=0019FE94


这里又是一个pop handler。

[Asm] 纯文本查看 复制代码
; ======================= handler 
; vPopReg4 R8 (0x20)
0043F5E7 Main     movzx eax,byte ptr ds:[esi]               ; EAX=0000004D
0043F5EA Main     add esi,0x1                               ; FL=PA, ESI=0040C830
0043F5F6 Main     xor al,bl                                 ; FL=S, EAX=000000B6
0043F5FD Main     not al                                    ; EAX=00000049
0043F5FF Main     xor al,0x7D                               ; FL=0, EAX=00000034
0043F605 Main     inc al                                    ; FL=P, EAX=00000035
0043F60E Main     xor al,0xF6                               ; FL=PS, EAX=000000C3
0043F616 Main     ror al,1                                  ; FL=CPS, EAX=000000E1
0043F61D Main     dec al                                    ; FL=CS, EAX=000000E0
0043F626 Main     neg al                                    ; FL=C, EAX=00000020
0043F628 Main     xor bl,al                                 ; FL=PS, EBX=004043DB

0043F630 Main     mov ecx,dword ptr ss:[ebp]                ; ECX=00401000
0043F63A Main     add ebp,0x4                               ; EBP=0019FF5C
0043F643 Main     mov dword ptr ss:[esp+eax],ecx


这里又是一个跳转。

[Asm] 纯文本查看 复制代码
; 跳转到下条指令,与之前代码位置又都不同
0043F64E Main     mov eax,dword ptr ds:[esi]                ; EAX=28020B6A
0043F652 Main     lea esi,dword ptr ds:[esi+0x4]            ; ESI=0040C834
0043F65D Main     xor eax,ebx                               ; FL=P, EAX=284248B1
00467C71 Main     inc eax                                   ; EAX=284248B2
00467C72 Main     ror eax,0x2                               ; FL=CP, EAX=8A10922C
00426C32 Main     inc eax                                   ; FL=CPS, EAX=8A10922D
00426C34 Main     xor eax,0x75EF373B                        ; FL=S, EAX=FFFFA516
00426C39 Main     dec eax                                   ; EAX=FFFFA515
00426C3A Main     xor ebx,eax                               ; EBX=FFBFE6CE
00426C3C Main     add edi,eax                               ; FL=CP, EDI=00439AFC
00408854 Main     jmp edi


这里又是一个pop handler

[Asm] 纯文本查看 复制代码
; ======================= handler 
; vPopReg4
00439AFC Main     movzx eax,byte ptr ds:[esi]               ; EAX=00000068
00439B06 Main     lea esi,dword ptr ds:[esi+0x1]            ; ESI=0040C835
00439B0C Main     xor al,bl                                 ; EAX=000000A6
00439B18 Main     not al                                    ; EAX=00000059
00439B21 Main     xor al,0x7D                               ; FL=P, EAX=00000024
0047EF23 Main     inc al                                    ; FL=0, EAX=00000025
0047EF2C Main     xor al,0xF6                               ; FL=S, EAX=000000D3
0047EF32 Main     ror al,1                                  ; FL=CS, EAX=000000E9
0047EF3D Main     dec al                                    ; FL=CPS, EAX=000000E8
0047EF3F Main     neg al                                    ; FL=CPA, EAX=00000018
0047EF49 Main     xor bl,al                                 ; FL=S, EBX=FFBFE6D6

0047EF50 Main     mov ecx,dword ptr ss:[ebp]                ; ECX=00401000
0047EF55 Main     lea ebp,dword ptr ss:[ebp+0x4]            ; EBP=0019FF60
0047EF5B Main     mov dword ptr ss:[esp+eax],ecx


基本模式:
ESI保存bytecode和跳转地址,每条Bytecode前有4字节跳转地址
进行跳转时将跳转地址读出来,进行解密,解密后的值再加上EDI
就是最终的跳转地址,即handler地址。
按照惯例,虚拟机入口pop出所有寄存器到vm_context
应该会产生大量的pop指令,不一一分析了,这里直接跳过。

跳过的bytecode如下
[Asm] 纯文本查看 复制代码
vPopReg4 R1 (0x4)   
vPopReg4 R3 (0xC)
vPopReg4 R0 (0x0)
vPopReg4 R11 (0x2C)
vPopReg4 R12
vPopReg4 R2
vPopReg4 R13


执行完10个pop,这里终于出现了新handler, 是压入立即数指令,也就是mov eax, 0deadbeefh对应的bytecode。
[Asm] 纯文本查看 复制代码
; vPushImm4 DEADBEEF
; 取立即数并解密
0047D362 Main     mov eax,dword ptr ds:[esi]                ; EAX=39A96DBB
0040F037 Main     lea esi,dword ptr ds:[esi+0x4]            ; ESI=0040C865
0040F03D Main     xor eax,ebx                               ; FL=S, EAX=C612D09B
0040F044 Main     neg eax                                   ; FL=CPA, EAX=39ED2F65
0040F047 Main     rol eax,0x2                               ; EAX=E7B4BD94
0040F04C Main     add eax,0x4B906ADA                        ; FL=C, EAX=3345286E
00477C1C Main     xor eax,0x7A4740E4                        ; FL=0, EAX=4902688A
00477C23 Main     sub eax,0x69850CCD                        ; FL=CPAS, EAX=DF7D5BBD
00477C28 Main     ror eax,1                                 ; EAX=EFBEADDE
00477C2A Main     bswap eax                                 ; EAX=DEADBEEF
00477C31 Main     xor ebx,eax                               ; FL=P, EBX=211603CF
; 压到栈中
00477C38 Main     sub ebp,0x4                               ; FL=A, EBP=0019FF7C
00477C42 Main     mov dword ptr ss:[ebp],eax



又是跳转,但这次稍有不同,因为是push指令,需要检查栈是否发生溢出,这与2.x是一致的
[Asm] 纯文本查看 复制代码
; 取下次跳转的地址
00477C46 Main     mov eax,dword ptr ds:[esi]                ; EAX=095A81E6
0043B383 Main     lea esi,dword ptr ds:[esi+0x4]            ; ESI=0040C869
0043B391 Main     xor eax,ebx                               ; FL=0, EAX=284C8229
0043ED4B Main     inc eax                                   ; EAX=284C822A
0043ED4C Main     ror eax,0x2                               ; FL=C, EAX=8A13208A
00436549 Main     inc eax                                   ; FL=CPS, EAX=8A13208B
00436550 Main     xor eax,0x75EF373B                        ; FL=S, EAX=FFFC17B0
00418A8E Main     dec eax                                   ; FL=PAS, EAX=FFFC17AF
00418A91 Main     xor ebx,eax                               ; FL=PS, EBX=DEEA1460
00418A93 Main     add edi,eax                               ; FL=CPA, EDI=0043EB11
; 由于是push指令,为了避免栈中数据与vm_context重合,需要检查栈溢出,这与2.x是一致的
; 检查栈溢出
0042D77B Main     lea eax,dword ptr ss:[esp+0x60]           ; EAX=0019FEF4
0042D784 Main     cmp ebp,eax                               
0042D786 Main     ja console_.00421B90


这部分代码不在trace中,因为实际不会溢出,这里单独从OD中拿出来作为分析,同样都去掉了垃圾指令

[Asm] 纯文本查看 复制代码
; 如果发生溢出
0042D78C    8BD4            mov edx,esp
0042D790    B9 40000000     mov ecx,0x40
; 分配0x80空间
0042D79C    8D4425 80       lea eax,dword ptr ss:[ebp-0x80]  
00472FEA    24 FC           and al,0xFC
00472FEC    2BC1            sub eax,ecx    
; 上抬vm_context位置
004783AE    8BE0            mov esp,eax  
004061B8    57              push edi                                 ; console_.<ModuleEntryPoint>
004061B9    9C              pushfd
00474547    56              push esi                                 ; console_.<ModuleEntryPoint>
00474548    8BF2            mov esi,edx                              ; console_.<ModuleEntryPoint>
0043AA70    8BF8            mov edi,eax
; 复制vm_context内容
004307BC    FC              cld    
00416140    F3:A4           rep movs byte ptr es:[edi],byte ptr ds:[esi]


00416148    5E              pop esi                                  ; kernel32.755362C4
004166E8    9D              popfd
004166EC    5F              pop edi                                  ; kernel32.755362C4
00456F23    57              push edi                                 ; console_.<ModuleEntryPoint>
00456F24    C3              retn



接下来回到原本的分析过程中,由于重复了10遍mov eax, 0deadbeefh,
因此会出现10遍同样的handler,但地址各不相同

[Asm] 纯文本查看 复制代码
vPopReg4 R15(0x3C)
vPushImm4 DEADBEEF
vPopReg4 R4 (0x10)
vPushImm4 DEADBEEF
vPopReg4 R12(0x30)
vPushImm4 DEADBEEF
vPopReg4 R13(0x34)
vPushImm4 DEADBEEF
vPopReg4 R2 (0x08)
vPushImm4 DEADBEEF
vPopReg4 R9 (0x24)
vPushImm4 DEADBEEF
vPopReg4 R10(0x28)
vPushImm4 DEADBEEF
vPopReg4 R15(0x3C)
vPushImm4 DEADBEEF
vPopReg4 R4 (0x10)
vPushImm4 DEADBEEF
vPopReg4 R7 (0x1C)


这里可以看到同样的mov eax, 0deadbeefh ,pop的寄存器是不同的,可见2.x的寄存器轮转机制并没有变化。


新跳转
[Asm] 纯文本查看 复制代码
00450F03 Main     mov eax,dword ptr ds:[esi]                ; EAX=D7E129A1
00450F08 Main     lea esi,dword ptr ds:[esi+0x4]            ; ESI=0040C8E3
00450F0E Main     xor eax,ebx                               ; FL=0, EAX=2858C061
0043F841 Main     inc eax                                   ; EAX=2858C062
0042D4DE Main     ror eax,0x2                               ; FL=C, EAX=8A163018
00444518 Main     inc eax                                   ; FL=CS, EAX=8A163019
0044451A Main     xor eax,0x75EF373B                        ; FL=PS, EAX=FFF90722
0044451F Main     dec eax                                   ; EAX=FFF90721
00442C79 Main     xor ebx,eax                               ; FL=P, EBX=0040EEE1
00442C83 Main     add edi,eax                               ; FL=C, EDI=0040AC3D
00442C85 Main     jmp edi

新的handler ,这次是push,用于退出虚拟机时保存虚拟寄存器到栈中
[Asm] 纯文本查看 复制代码
; vPushReg4 R7(0x1C)
; 解密寄存器下标
0040AC3D Main     movzx eax,byte ptr ds:[esi]               ; EAX=0000005F
00454BB7 Main     add esi,0x1                               ; FL=P, ESI=0040C8E4
00454BBD Main     xor al,bl                                 ; FL=PS, EAX=000000BE
00475727 Main     not al                                    ; EAX=00000041
00413C0A Main     xor al,0x7D                               ; FL=P, EAX=0000003C
00456F67 Main     inc al                                    ; FL=0, EAX=0000003D
00456F6B Main     xor al,0xF6                               ; FL=S, EAX=000000CB
00456F6E Main     ror al,1                                  ; EAX=000000E5
00447E46 Main     dec al                                    ; FL=CPS, EAX=000000E4
00447E48 Main     neg al                                    ; FL=CA, EAX=0000001C
00481E64 Main     xor bl,al                                 ; FL=S, EBX=0040EEFD
; push reg
00481E67 Main     mov eax,dword ptr ss:[esp+eax]            ; EAX=DEADBEEF
00481E71 Main     lea ebp,dword ptr ss:[ebp-0x4]            ; EBP=0019FF7C
00481E7A Main     mov dword ptr ss:[ebp],eax


接下来的bytecode都是push指令,不一一分析了
[Asm] 纯文本查看 复制代码
vPushReg4 R11(0x2C)
vPushReg4 R0(0x0)
vPushReg4 R3(0xC)
vPushReg4 R1(0x4)
vPushReg4 R5(0x14)
vPushReg4 R6(0x18)
vPushReg4 R8(0x20)


又是一段跳转代码
[Asm] 纯文本查看 复制代码
00429FBE Main     mov eax,dword ptr ds:[esi]                ; EAX=D7F040B7
00429FC0 Main     lea esi,dword ptr ds:[esi+0x4]            ; ESI=0040C90B
00429FC6 Main     xor eax,ebx                               ; FL=S, EAX=D7B04B20
00429FC8 Main     inc eax                                   ; FL=PS, EAX=D7B04B21
00429FC9 Main     ror eax,0x2                               ; EAX=75EC12C8
00425BD2 Main     inc eax                                   ; FL=P, EAX=75EC12C9
00425BD4 Main     xor eax,0x75EF373B                        ; FL=0, EAX=000325F2
00425BD9 Main     dec eax                                   ; EAX=000325F1
00425BDA Main     xor ebx,eax                               ; FL=P, EBX=00432E66
00425BDF Main     add edi,eax                               ; FL=0, EDI=0045E09E
0042D77B Main     lea eax,dword ptr ss:[esp+0x60]           ; EAX=0019FEF4
0042D784 Main     cmp ebp,eax                               ; FL=PA
0042D786 Main     ja console_.00421B90
00421B90 Main     jmp edi



新的handler
vRet, 功能与之前一样,从栈中将寄存器弹出到真实寄存器中。
[Asm] 纯文本查看 复制代码
0045E09E Main     mov esp,ebp                               ; ESP=0019FF60
0045E0AA Main     pop esi                                   ; ESP=0019FF64, ESI=00401000
0045E0AB Main     pop ecx                                   ; ECX=00401000, ESP=0019FF68
0045E0B2 Main     pop ebx                                   ; EBX=003F7000, ESP=0019FF6C
0045E0BA Main     pop edx                                   ; EDX=00401000, ESP=0019FF70
0045E0C7 Main     popfd                                     ; FL=PZ, ESP=0019FF74
0045E0CD Main     pop ebp                                   ; ESP=0019FF78, EBP=0019FF94
0045E0D6 Main     pop edi                                   ; ESP=0019FF7C, EDI=00401000
0045E0DB Main     pop eax                                   ; EAX=DEADBEEF, ESP=0019FF80
004822D1 Main     retn                                      ; ESP=0019FF84

; 这里已经是非虚拟化的代码了
00401005 Main     push 0x0                                  ; ExitCode = 0x0, ESP=0019FF80
00401007 Main     call <jmp.&kernel32.ExitProcess>          ; FL=0, EAX=00401000, ECX=00000000, EDX=00000000, EBX=7707F9A0, ESP=0019FE8C, EBP=0019FF64, ESI=00000000, EDI=00000000
; 程序退出


我们把1.81 demo的bytecode提取出来,这里用到VMP分析插件1.4这个神器(由于是demo版本,FKVMP是不行的)

[Asm] 纯文本查看 复制代码
00403765 VMP_0040100C  /$  78           vPopReg4 vR14        DWORD _t0 = 0
00403766               |.  6B F70C72B7  vPushImm4 0B7720CF7  DWORD _t1 = 0B7720CF7
0040376B               |.  39           vAdd4                DWORD _t2 = 0B7720CF7; DWORD _t3 = AddFlag(_t1, check00000000)
0040376C               |.  74           vPopReg4 vR13        DWORD _t4 = _t3
0040376D               |.  5C           vPopReg4 vR7         DWORD _t5 = 0B7720CF7
0040376E               |.  40           vPopReg4 vR0         DWORD _t6 = EAX
0040376F               |.  48           vPopReg4 vR2         DWORD _t7 = EDX
00403770               |.  64           vPopReg4 vR9         DWORD _t8 = EBP
00403771               |.  50           vPopReg4 vR4         DWORD _t9 = EDX
00403772               |.  74           vPopReg4 vR13        DWORD _t10 = ECX
00403773               |.  44           vPopReg4 vR1         DWORD _t11 = EDI
00403774               |.  54           vPopReg4 vR5         DWORD _t12 = ESI
00403775               |.  70           vPopReg4 vR12        DWORD _t13 = EFL
00403776               |.  68           vPopReg4 vR10        DWORD _t14 = EBX
00403777               |.  4C           vPopReg4 vR3         DWORD _t15 = 401016
00403778               |.  58           vPopReg4 vR6         DWORD _t16 = 403765
00403779               |.  FA EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t17 = 0DEADBEEF
0040377E               |.  4C           vPopReg4 vR3         DWORD _t18 = 0DEADBEEF
0040377F               |.  E9 EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t19 = 0DEADBEEF
00403784               |.  58           vPopReg4 vR6         DWORD _t20 = 0DEADBEEF
00403785               |.  23 EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t21 = 0DEADBEEF
0040378A               |.  40           vPopReg4 vR0         DWORD _t22 = 0DEADBEEF
0040378B               |.  B4 EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t23 = 0DEADBEEF
00403790               |.  60           vPopReg4 vR8         DWORD _t24 = 0DEADBEEF
00403791               |.  23 EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t25 = 0DEADBEEF
00403796               |.  4C           vPopReg4 vR3         DWORD _t26 = 0DEADBEEF
00403797               |.  6B EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t27 = 0DEADBEEF
0040379C               |.  7C           vPopReg4 vR15        DWORD _t28 = 0DEADBEEF
0040379D               |.  B4 EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t29 = 0DEADBEEF
004037A2               |.  4C           vPopReg4 vR3         DWORD _t30 = 0DEADBEEF
004037A3               |.  6B EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t31 = 0DEADBEEF
004037A8               |.  6C           vPopReg4 vR11        DWORD _t32 = 0DEADBEEF
004037A9               |.  E9 EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t33 = 0DEADBEEF
004037AE               |.  40           vPopReg4 vR0         DWORD _t34 = 0DEADBEEF
004037AF               |.  23 EFBEADDE  vPushImm4 0DEADBEEF  DWORD _t35 = 0DEADBEEF
004037B4               |.  58           vPopReg4 vR6         DWORD _t36 = 0DEADBEEF
004037B5               |.  28           vPushReg4 vR10       EBX DWORD v0 = EBX
004037B6               |.  30           vPushReg4 vR12       EFL DWORD v1 = EFL
004037B7               |.  14           vPushReg4 vR5        ESI DWORD v2 = ESI
004037B8               |.  04           vPushReg4 vR1        EDI DWORD v3 = EDI
004037B9               |.  34           vPushReg4 vR13       ECX DWORD v4 = ECX
004037BA               |.  10           vPushReg4 vR4        DWORD _t42 = _t9
004037BB               |.  24           vPushReg4 vR9        EBP DWORD v5 = EBP
004037BC               |.  08           vPushReg4 vR2        EDX DWORD v6 = EDX
004037BD               |.  18           vPushReg4 vR6        EAX DWORD v7 = 0DEADBEEF
004037BE               |.  30           vPushReg4 vR12       DWORD _t46 = _t13
004037BF               |.  1C           vPushReg4 vR7        DWORD _t47 = 0B7720CF7
004037C0               \.  A4           vRet                 return Stack(34, 4)


对比可以发现其实bytecode是基本一致的,但是内部实现已经发生了巨大变化。

这里简单分析就结束了。
至于条件跳转等其他实现细节,以后再慢慢讨论

0x04 写在最后

从今年2月分开始的连续几个月时间可能都要研究虚拟机保护相关的内容,因此也会陆续发些心得笔记上来。
这里希望论坛大大们可以给些指点,好少走点弯路。
也希望其他坛友们能多多回帖讨论。


相关文件都放在附件中了
解压密码www.52pojie.cn
深夜发贴,求鼓励
以上

vmp_3.09.zip

373.85 KB, 下载次数: 476, 下载积分: 吾爱币 -1 CB

VMP3分析文件

免费评分

参与人数 116吾爱币 +125 热心值 +110 收起 理由
liphily + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ajia + 1 热心回复!
wo4mt + 1 + 1 用心讨论,共获提升!
lin64850 + 1 + 1 谢谢@Thanks!
wmsuper + 2 + 1 谢谢@Thanks!
蜗牛跑了快 + 1 + 1 用心讨论,共获提升!
zycode + 1 + 1 我很赞同!感谢用心的分享内容
uubs + 1 + 1 谢谢@Thanks!
白帝 + 1 + 1 热心回复!
【健谈】 + 1 + 1 谢谢@Thanks!
爱吃桃的猪 + 1 + 1 原理vmp也不是珠穆朗玛峰,受益匪浅
菜鸟也想飞 + 1 谢谢@Thanks!
xiaohang99 + 1 + 1 谢谢@Thanks!
tingpu + 1 + 1 我很赞同!
rods + 1 + 1 很走心的分析
可可乐乐 + 1 + 1 我很赞同!
Macc + 1 + 1 谢谢@Thanks!
qianjma + 1 + 1 我很赞同!
ccm5085 + 1 + 1 我很赞同!
sisco + 1 + 1 我很赞同!
九牛一毛 + 1 + 1 我很赞同!虽然还没学到这,先给楼主加分
WOO123 + 1 + 1 我很赞同!
mxs520 + 1 + 1 我很赞同!
aska80 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
CROW_df + 1 + 1 用心讨论,共获提升!
xy188 + 1 热心回复!
文可う润心 + 1 + 1 谢谢@Thanks!
拉酷 + 1 + 1 请问如何把ntdll.dll设置为系统dll
飞鸽传书 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
、古城 + 1 用心讨论,共获提升!
knva + 1 + 1 已答复!
noalieri + 1 + 1 我很赞同!
heimu360 + 1 我很赞同!
青莲剑哥 + 1 + 1 我很赞同!
iiiiol + 1 + 1 我很赞同!
gao0411 + 1 + 1 我很赞同!
birdbro + 1 + 1 我很赞同!
三十三平方 + 1 用心讨论,共获提升!
繁星满天1122 + 1 学习了,谢谢楼主
shuobatian + 1 + 1 我很赞同!
yuxing818 + 1 谢谢@Thanks!
zhizhizha + 1 + 1 用心讨论,共获提升!
chenhongleng + 1 我很赞同!
白菜圆子汤 + 1 + 1 我很赞同!
okmad + 1 + 1 谢谢@Thanks!
snccwt + 1 + 1 用心讨论,共获提升!
hisea + 1 + 1 我很赞同!
马斯维尔 + 1 + 1 我很赞同!
sgh885977 + 1 + 1 热心回复!
lj520lwl + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
吾2破解 + 1 + 1 我很赞同!
littlewisp + 1 + 1 我很赞同!
wagxu + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
lapop + 1 + 1 热心回复!
xuanqing + 1 + 1 谢谢@Thanks!
三年一梦love + 1 + 1 谢谢@Thanks!
wentwent + 1 + 1 热心回复!
dearcia + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
黑脑 + 1 + 1 热心回复!
sd3166 + 1 热心回复!
siwuxie095 + 1 厉害厉害
辣手神探 + 1 + 1 用心讨论,共获提升!
Aought + 1 + 2 我很赞同!
刘浩有个大梦想 + 1 + 1 我很赞同!
wlgaiyan + 1 用心讨论,共获提升!
listentoyou + 1 + 1 用心讨论,共获提升!
akingaa + 1 + 1 热心回复!
limfcn + 1 + 1 谢谢@Thanks!
pb1977 + 1 + 1 用心讨论,共获提升!
Three_fish + 1 + 1 谢谢@Thanks!
鲁鲁豪君 + 1 + 1 我很赞同!
stackburn + 1 + 1
心中有曲自然嗨i + 1 + 1 热心回复!
Ink + 1 + 1 用心讨论,共获提升!
飞不走的鱼 + 1 + 1 谢谢@Thanks!
fenghaoda + 1 + 1 我很赞同!
Lokavid + 1 + 1 我很赞同!
NewType + 2 + 1 用心讨论,共获提升!
时光的旅行者 + 1 + 1 热心回复!
莫名的伤 + 1 + 1 已答复!
0Nullptr + 1 + 1 热心回复!
zhluosss + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
MXWXZ + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
610100 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Koyoter + 1 + 1 谢谢@Thanks!
猎户座xemo + 3 + 1 我很赞同!
lxlxxxl + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ZMZwise + 2 + 1 厉害了,膜拜啊
longlong1 + 1 + 1 表示VMP2都脱不了
海底总动员 + 1 + 1 我很赞同!
wangxp + 1 + 1 谢谢@Thanks!
神枪泡泡丶 + 2 + 1 用心讨论,共获提升!
lies2014 + 1 + 1 用心讨论,共获提升!
247605832 + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
微笑着走过 + 2 + 1 我就佩服这种学习的精神,一个人苦苦专研.
codelive + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
铅笔刀 + 2 + 1 低调的大神啊
adys + 1 + 1 我很赞同!
hejialong + 2 + 1 谢谢@Thanks!
thisis + 1 已答复!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Cr4ckm3 发表于 2017-3-27 20:27
拉酷 发表于 2017-3-26 17:56
请问如何把ntdll.dll设置为系统dll  ?

OD中切换到 “E" 窗口,右键对应的DLL 选择”设为系统DLL”即可
 楼主| Cr4ckm3 发表于 2017-5-13 15:00
生鲜喵 发表于 2017-4-28 19:40
那楼主,作为小白的我问下,微软打hyper-y虚拟机是否和这个一个机制??作为系统自带的程序功能,是否会在 ...

hyper-y是与VMWare和VirtualBox一样的虚拟机软件。 VMProtect是用于软件保护的。这和VMProtect的虚拟机只是名称相似实际上没关系。VMProtect的虚拟机,实际是一种程序语言解释器,和Java虚拟机是同一种类型的概念。
酒醒黄昏 发表于 2017-3-10 10:21
ugvnui 发表于 2017-3-10 10:22
纯好贴,,高质量。。。。喜欢。。想你看起!!
Hmily 发表于 2017-3-10 10:26
好文,VMP3.x的架构变了,本文是我看到第一篇公开分析的科普文章,新版handle也更多了,期待更多分析和工具的出现,加精鼓励!
pxhb 发表于 2017-3-10 10:30
先收藏,以后有时间看看,不错的好东西
 楼主| Cr4ckm3 发表于 2017-3-10 10:31
Hmily 发表于 2017-3-10 10:26
好文,VMP3.x的架构变了,本文是我看到第一篇公开分析的科普文章,新版handle也更多了,期待更多分析和工具 ...

感谢H大的评价

免费评分

参与人数 1热心值 +1 收起 理由
heimu360 + 1 我很赞同!

查看全部评分

crack晓晓 发表于 2017-3-10 10:39
厉害了我的C
chinasmu 发表于 2017-3-10 11:03
楼主6到没朋友
ygh23 发表于 2017-3-10 11:13 来自手机
好东西啊。
掂软心内 发表于 2017-3-10 11:21
膜拜,这个真的厉害了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-3-29 10:38

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表