谈谈vmp的爆破

谈谈vmp的爆破
文章图片
0x00 前言

玩vmp的笔记吧,祝大家新年快乐。先谈谈爆破,这个比起其他的方面的话,应该很多人喜欢,比较直截了当。当然,也会提一些vmp其他的东西。


0x10 需要的基础知识

平常我们爆破一个软件,有一种有常见的方法就是通过修改jcc跳转来达到爆破的目的。而vmp实现jcc,跳还是不跳,其实计算是eflags。
以jz为例,大家都知道jz跳不跳其实是看zf标志位的状态:
zf == 1 ---> 跳转
zf == 0 ---> 不跳转
那么我们看看vmp是怎么做的,先上个elflags reg图和给几个要用的数字以及一个handle:
谈谈vmp的爆破
文章图片
数字:0x815、0x246、0x206、0x216、0x40
(如果有玩过vmp的,应该对这几个数字有熟悉)
handle大致样子,记为vm_p(a,b):
not a
not b
and a,b
下面我会一一解释。
先看看0x815的二进制:100000010101
好像看不出来什么所以然,那么这样呢?
谈谈vmp的爆破
文章图片
这样就很直观了,其实等价于OF AF PF CF的mask。
同理大家可以看看其他的几个数字。
比如0x40,这里就直接用维基的图了:
谈谈vmp的爆破
文章图片
明白了这几个数字的含义那么我们看看可以怎么得到zf为1的情况,之前已经说到了会用到eflag的值。是不是可以这样:
~zf= and(0x40,not(eflags)) = 0(1)
zf= and(0x40,eflags) = 1(2)
注意到这里的0和1都是所对应到eflags zf的数值
那么eflags又是怎么得到的,这里vmp通过加法和0x815实现
eflags = and( eflags1, 0x815) + and( eflags2, not(0x815))(3)
而vmp中的not,and运算都可以用vm_p来实现,比如我们将式(1)转换后,如下:
~zf = vm_p(not(0x40),eflags) = 0
至于eflags1,eflags2我们可以并不关心他怎么运算的,因为我们只需要修改最终的eflags即可达到爆破的目的。
不过接触过vmp的人应该明白eflags1,eflags2的数值是通过vm_p(sn,sn)+?这样的式子得到的。
相信vmp为什么会选择0x40这个数字来计算zf大家也明白了(还有一点,大家注意一下af)。
【谈谈vmp的爆破】

0x02 实战

明白了原理之后,我们找个东西进行一番实践。
这里我选择的是EverEdit,因为官方刚好有两个vmp版本
使用的是官方下的32位的绿色版
你可以输入了随意输入sn后(不过注意,everedit的sn太短不行,233)通过暂停法然后再单步找到vmp调用handle的地方(也就是dispather),也可以通过那块保存sn的堆空间找到(因为是malloc的),当然方法很多。
谈谈vmp的爆破
文章图片
使用trace into记录到文件中。
谈谈vmp的爆破
文章图片
接下来我们只需要找到vm_p这条handle,然后在记录的文件之中搜索(记得倒着,从下向上)就ok。
而怎么找handle,如果你对vmp有了解的话,应该知道其实就4套handler。
这里我用一种我的方法,先分析是如何jmp到handle的。
0052474C8B1485 00D05B00mov edx,dword ptr ds:[eax*4+0x5BD000]; <== handler调用
00524753^\E9 EA9BFAFFjmp EverEdit.004CE342
004CE3424Adec edx; EverEdit.00524F92
然后我们在看看0x5BD000这个数组:
谈谈vmp的爆破
文章图片
如果有人再仔细一些会发现,这个地址刚好是vmp0的区段的开始。
对了,可以提一提,这个数组大小是0x100 * 4。但其实vmp加密的时候第一次扫了186次,第二次随机扫剩下的,再把地址填进去。
至于为什么是186次:
1).186个匹配规则
2).186个handle
然后我把这些地址记录下来,修改后打印出来:
谈谈vmp的爆破
文章图片
具体代码就不帖了。
很幸运的是,od看了看第一个handle对应的就是vm_p,如下:
0041742D66:D3C2rol dx,cl
004174308B45 00mov eax,dword ptr ss:[ebp]
0041743366:89F2mov dx,si
004174368B55 04mov edx,dword ptr ss:[ebp+0x4]
0041743966:0FBAE3 01bt bx,0x1
0041743EF7D0not eax
0041744066:0FBAE4 01bt sp,0x1
0041744560pushad
00417446F7D2not edx
00417448F8clc
0041744966:85E4test sp,sp
0041744CF5cmc
0041744D21D0and eax,edx
0041744F9Cpushfd
00417450890C24mov dword ptr ss:[esp],ecx; EverEdit.005BA174
not eax
not edx
and eax,edx
这时候根据前面的知识,我们只需要搜索trace记录的log,比如搜索eax=40或者edx=40或者not(40)等
谈谈vmp的爆破
文章图片
搜索三次后达到找到这个地方:
00417430 Mainmov eax,dword ptr ss:[ebp]; EAX=FFFFFFBF
00417436 Mainmov edx,dword ptr ss:[ebp+0x4]; EDX=00000246
0041743E Mainnot eax; EAX=00000040
00417446 Mainnot edx; EDX=FFFFFDB9
0041744D Mainand eax,edx; FL=PZ, EAX=00000000


vm_p(not(40),eflags) ------>and( 40, not(eflags))
很明显这里就是取0x40与eflags进行运算了,然后相信怎么修改大家也有明确了。
比如这里eax得到0,注册码不成立,那么正确的应该是这样vm_p(not(0x40),0x216) = 0x40,也就是eax的值是0x40成立。后面还有vm_shr之类的运算,不过那是确定zf的。
(这里想吐槽下EverEdit的作者,把sn一个一个读取的过程也vm了,跑了这么多行指令也是醉了)
然后我们可以根据寄存器的情况,写个小脚本或者做补丁了。比如这样的:
bp 41744d
start:
run
cmp eax,00000040
jnz start
cmp edx,FFFFFDB9
jnz start
cmp esp,0012E4E4
jnz start
end:
bc 41744d
ret
当然这里取esp不太好,取esi,edi之类的更好。(可以思考一下)
谈谈vmp的爆破
文章图片
停下来的时候修改寄存器的数值即可达到爆破的目的。
谈谈vmp的爆破
文章图片
这里我直接修改edx为not(206)即可。然后这个软件好像是个重启验证,恩,有兴趣的可以下断之后,研究研究。应该多改一次就可以了,估计不止一个jcc。


0x03 结束语

接着说下vmp3.x的爆破,其实差不多,不过vmp3.x比起之前的来说区别还是很多
比如把handle更分散,用jmp等方法连接,然后还有一些检测。不过大家了解了vmp对于eflag的使用,那么应该没啥问题。
这里给个最新版的点,以便于大家理解。trace into之后的对比前16w行即可
00423F898A45 0Bmov al,byte ptr ss:[ebp+0xB]
00423F8C8BE5mov esp,ebp
00423F8E5Dpop ebp; EverEdit.00423ED3
00423F8FC2 0800retn 0x8
最后说下vmp。在未了解之前,就一直说听过。在了解了之后,才发现这个东西设计得多么细腻,从反汇编引擎到加壳的过程可以说是一个很顺畅的流程。当然vmp3.x重写了反汇编引擎(有点怪异..),然后想看怎么加壳发现流程被vm了。
本文由看雪论坛 waiWH 原创转载请注明来自看雪社区
欢迎关注 “看雪学院” 公众号:ikanxue

    推荐阅读