西西软件园多重安全检测下载网站、值得信赖的软件下载站!
软件
软件
文章
搜索

首页西西教程软件使用 → VMProtect2.04加壳程序从入门到精通

VMProtect2.04加壳程序从入门到精通

相关软件相关文章发表评论 来源:本站整理时间:2010/11/2 18:59:10字体大小:A-A+

作者:佚名点击:3925次评论:0次标签: VMProtect 加壳

VMProtect UltimateV2.13.5 中文注册版
  • 类型:加壳脱壳大小:13.5M语言:中文 评分:4.2
  • 标签:
立即下载
2 页 VMProtect虚拟机简介

1.基础知识
1.1.VMProtect虚拟机简介
虚拟机加密,是指像VMP这样的保护程序,它会把源程序的X86指令变成自定义的伪指令,等到执行的时候,VMP内置在保护程序中的VM就会启动,读取伪指令,然后解析执行。
VMP是一个堆栈虚拟机,它的一切操作都是基于堆栈传递的。在VMP中,每一个伪指令就是一个handler,VM中有一个核心的Dispatch部分,它通过读取程序的bytecode,然后在DispatchiTable里面定位到不同的handler中执行。绝大多数情况下,在一个handler中执行完成后,程序将回到Dispatch部分,然后到next handler中执行。
http_imgload.jpg下载此附件需要消耗2Kx,下载中会自动扣除。
在上面的框架中,核心的部件就是Dispatch部分,下面并列的部件就是handlers。
经过VMP加密的X86指令,一条简单的指令被分解成数条VMP的伪指令,它按照自己的伪指令排列去实现原指令的功能,在加上其他的花指令混乱等等,你将完全看不到源程序指令。VMP自带的各种机制都不再是以X86指令的形式去实现,而是用自己的伪指令去测试。
在VMP的VM运行过程中,各个寄存器的基本用途是:EBP和EDI是VM堆栈指针(不是常规的堆栈);ESI是伪指令指针(相当于常规的EIP);EAX是VM解密数据的主运算寄存器;EBX是VM解密数据的辅运算寄存器;ECX是常规的循环计数器;ESP是常规的堆栈栈顶指针。EDX是读取伪指令表数据;
EDI、EBP分别指向VM堆栈的上下限位置,EBP指向堆栈的下限并向上发展,EDI指向堆栈的上限并使用[EDI+EAX]的方式向下发展;ESI指向的内存块里包括要执行的伪指令序列,而不同的是,当VM要是使用到立即数时,也是从ESI读取。可见ESI内存块里面是精心构建的数据块,只有VM自身执行过程中,才能知道下一个数据是代表伪指令还是立即数;在VM运算中EAX寄存器很多时候通常只有AL参与运算然后在存取时再以AX或EAX得方式存取;EBX在很多加密数据运算中,都会参与到EAX值的计算中,协助运算中正确的值。而每次EAX的值运算结束后,反过来会计算好下一次运算中EBX的值。所以EBX的数据一旦出错,下一个数据解密必然错误;在VM运行中,通常一切操作都是在VM堆栈内完成的,所以绝大多数情况下对ESP的操作都是花指令或junk code。在一些虚拟与现实(比如说调用系统函数)交接的地方,系统并不知道VM堆栈的存在,这就需要把数据(比如系统函数的调用参数)移动到常规ESP栈顶。EDX是一个较少使用的寄存器,只在一些解密循环里面参与运算。而它的一个主要的运用是在DISPATCH部件里,根据ESI的值来获取DispatchTable的数据,让VM执行下一条伪指令。

1.2.VM堆栈
VMP的VM是基于堆栈的虚拟家,理解好VM的堆栈空间划分和操作,是理解整个VM运行的基础。
VMProtect2.04加壳程序是从TLS开始运行的,我们首先点击OD的options菜单,修改Startup and exit选项,让OD中断在TLS callback里。加壳程序运行后,VMP初始化VM,并进入DISPATCH部分。这里我们就以初始化后的堆栈为例。
VM的堆栈一共使用61个DWORD,上下分别有2个堆栈指针,下面为EBP指针,上面为EDI指针。下面是VM初始化时,给EDI和EBP指针赋值后的堆栈。
EDI=0013F8BC
EBP=0013F9B0
CPU Stack
Locked Value ASCII Comments
0013F8BC 009539E8 9. ;这里是EDI指向
0013F8C0 00950000 ...
0013F8C4 00150000 ...
0013F8C8 00000080 ...
0013F8CC 019314D6
0013F8D0 0013F8A8 .
0013F8D4 7C92E920 |
0013F8D8 00000000 ....
0013F8DC 00000000 ....
0013F8E0 00000000 ....
0013F8E4 FFFFFFFF
0013F8E8 7C98FEFF |
0013F8EC 7C00ADE7 .|
0013F8F0 00000000 ....
0013F8F4 00150000 ...
0013F8F8 0013F6F0 .
0013F8FC 0013F940 @.
0013F900 0013F944 D.
0013F904 7C92E920 |
0013F908 7C9301E0 |
0013F90C FFFFFFFF
0013F910 7C9301DB |
0013F914 7C9314D6 |
0013F918 7C931514 |
0013F91C 7C99E120 |
0013F920 7C9314EA |
0013F924 5ADF1158 XZ
0013F928 00000001 ...
0013F92C 00000000 ....
0013F930 7FFDA000 .
0013F934 7FFDF000 .
0013F938 00158070 p.
0013F93C 0013F890 .
0013F940 00000000 ....
0013F944 0043D759 YC.
0013F948 0000E9ED ..
0013F94C 409B0002 .@
0013F950 00000020 ...
0013F954 0013F9CC .
0013F958 0013F96C l.
0013F95C 0043E9ED C.
0013F960 000359F4 Y.
0013F964 00000020 ...
0013F968 004253CD SB.
0013F96C 409B0000 ..@
0013F970 00000020 ...
0013F974 0013F9CC .
0013F978 0013F98C .
0013F97C 00000000 .... ;这里是EBP指向
0013F980 00000000 .... ;这里是VM初始化保存的各个寄存器
0013F984 00000246 F..
0013F988 000359F4 Y.
0013F98C 00000020 ...
0013F990 00000000 ....
0013F994 0013F9CC .
0013F998 004253CD SB.
0013F99C 000359F4 Y.
0013F9A0 00400000 ..@.
0013F9A4 0013F9C0 .
0013F9A8 C456C619 V ;这里是VMP的2个加密数据
0013F9AC 2EF6420A .B.
0013F9B0 7C92118A | ; RETURN to ntdll.7C92118A ;这里是TLS进来时的栈顶
关于2个加密数据和初始化的过程我们后续来说,这里我们主要关注VM的堆栈划分。
我把上面的EDI指向的堆栈称为EDISTACK,把EBP指向的堆栈称为EBPSTACK。在VM中,EBPSTACK是运算区,各类数据的运算操作在这里完成;EDISTACK是存储区包括长期存储数据和临时存储EBPSTACK的运算数。
下面我们来看一条数据移动伪指令:
命名:
VM_MOVdw_EDISTACKdw_EBPSTACKdw
代码:
0043DC19 |. F6D8 NEG AL ; *
0043DC26 |. C0C8 07 ROR AL,7 ; *
0043DC34 |. 2C 20 SUB AL,20 ; *
0043DC41 |. 24 3C AND AL,3C ; *

0043E080 |$ 8B55 00 MOV EDX,DWORD PTR SS:[EBP] ; *
0043E086 |. 83C5 04 ADD EBP,4 ; *

0043D3D7 /> /891438 MOV DWORD PTR DS:[EDI+EAX],EDX ; *
功能:
把1个dword的数据从EBPSTAK栈顶移动到EDISTACK,使用EAX作为偏移量

在EDISTACK的数据移动中,使用[EDI+EAX]的方式来存储与获取各个值。通过计算不同的EAX的值,可以到达EDISTACK中不同位置。在计算EAX值时,实际真正计算的是AL的值,我们来考虑一下AL的最小值和最大值,AL=00时[EDI+EAX]=[0013F8BC+00000000]=0013F8BC,AL=FF时[EDI+EAX]=[0013F8BC+000000FF]=0013F9BB,这是使用[EDI+EAX]可以读取的上下限。但是,在VM的AL值计算过程中,最后有一条AND AL,0x3C指令,0x3C=00111100bit由于这条指令的限制,无论AL为任何值(从00000000bit到11111111bit),通过AND操作,只能有1111bit的活动空间大小,1111bit相当于16,所以EDISTACK最多可以读取16个dword;由于00111100bit最后两个00位的限制,任何数字与它AND后,后两位都必然为0,变成与4对齐的值,说明VM都是按照0013F8BC 0013F8C0 0013F8C4 0013F8C8这样的4对齐来读取。在读取时,VM可以读取byte word dword,但是VM将不会去读取0013F8BE。
由于EDISTACK堆栈向下发展,EBPSTACK堆栈向上发展,EDISTACK有0x3C控制着范围,而EBPSTACK是操作区,没有硬性的范围控制。为了预防两个空间相撞,在每次往EBPSTACK移动数据后,VM都有相应的边界检测指令如下:
0043CE5A |. 8D47 50 LEA EAX,[EDI+50] ; *
0043EE5D |. 39C5 CMP EBP,EAX ; *
0043F08C |.^\0F87 29F6FFFF JA 0043E6BB ; *
比较结果 大于 ,这个正常的情况,在这个VM跟踪过程中,我没有发现一次小于的情况。如果小于,也就是EBPSTACK栈顶已经到达[EDI+50]位置,VM将会重新分配堆栈空间。0x50的偏移量比0x3C的偏移量多5个dword的缓冲区。我们来手动修改EBP指针,看看VM的对于两个堆栈空间即将相撞的处理情况:
CPU Disasm
Address Hex dump Command Comments
0043F092 |. 52 PUSH EDX ;
0043D6C1 |. 8D5424 08 LEA EDX,[ARG.2] ; *EDX获得的是原来EDI指针地址0013F8BC
0043DF38 |. 8D4F 40 LEA ECX,[EDI+40] ; *0x40的偏移量是0x3C的偏移量数据1个dword结束后的位置
0043DF46 |. 29D1 SUB ECX,EDX ; *减法计算出数据存储量
0043DF4B |. 8D45 80 LEA EAX,[EBP-80] ; *增加0x80的空间
0043DF5C |. 24 FC AND AL,FC ; *按4对齐
0043DF68 |. 29C8 SUB EAX,ECX ; *在增加原来数据大小的堆栈空间
0043DF6E |. 89C4 MOV ESP,EAX ; *
0043DF7E |. 56 PUSH ESI ; |Arg1 = NOTEPAD.425748, *
0043DF87 |. 89D6 MOV ESI,EDX ; |*
0043DB3A /$ 8D7C01 C0 LEA EDI,[EAX+ECX-40] ; *
0043EC1E . 89C7 MOV EDI,EAX ; *
0043EEED |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ ; *移动原来EDISTACK中存储的数据
0043EEF7 |. 8B7C24 10 MOV EDI,DWORD PTR SS:[ESP+10] ; *
0043EEFF |. 8B7424 10 MOV ESI,DWORD PTR SS:[ESP+10] ; *
这里我们可以看到,每次发现两个堆栈空间即将相撞,VM都重新给EBP分配堆栈,并把原来EDISTACK存储的数据移动到新的空间内。
下面是使用OD跟踪VM堆栈的几个小技巧:
在OD中跟踪VM数据移动时,双击0013F8BC地址,OD将会以0013F8BC为基址,显示上下各个地址与它的偏移量,如图:
CPU Stack
Locked Value ASCII Comments
$-C 759D0000 ..u
$-8 00000001 ...
$-4 0013F8FC .
$ ==> 009539E8 9. ;这里是0013F8BC,双击后的效果
$+4 00950000 ...
$+8 00150000 ...
$+C 00000080 ...
$+10 019314D6
在跟踪VM时,在数据移动伪指令中的AND AL,0x3C的下一条指令下断点,这样每次进行数据移动,你都可以在这个断点看到,数据的去向和来源,这是极其有用的。在很多复杂的运算地方,你需要在草稿纸上记下,EDISTACK中一些空间的数据时来自于什么时候?比如标志位ZF检测+跳转是VM的一个重要操作,而EFLAGS标志数都是相差不多或类似的00000286 00000246等等,如果你不能准确知道[EDI+EAX]存储或读取的位置,你将无法理解VM的操作。这非常的重要,请牢记!必要时连OD得数据窗口也一起配合显示VM堆栈

把OD里的堆栈窗口拉高,让它竟可能多的显示数据,在高分辨率的电脑上,最好是能够显示出整个VM的堆栈。默认情况下,堆栈窗口是随着ESP指针的变化而自动显示的,这对于我们要时刻盯着VM堆栈的需求不相符,在堆栈窗口-->右键-->Lock address 打钩,这样OD就会锁定堆栈窗口。
到这里,关于堆栈空间的介绍就结束了。对堆栈的理解是本文的根基。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)