qq群: 387430043
个人空间 0f4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6M7r3q4U0k6g2)9J5k6h3u0A6L8r3W2T1K9h3I4A6i4K6u0W2j5$3!0E0i4K6u0r3x3K6f1@1y4U0V1#2y4U0j5$3y4o6p5@1y4U0j5H3x3b7`.`.
终于到了分析用delphi语言编写的vmp保护接近最后一个版本了,delphi时代最后的狂欢了,我说的不知道有没有问题,但是我想表达的就是这个意思,这个版本可能是2.x的网上可以找到的最后一个版本了,代码结构相较于之前版本改动不算很大,所以说是最后的狂欢了,而支持分析vmp的插件貌似只支持到2.08,以后版本就不支持了,这也给后续版本的vmp,增加更加神秘的面纱了,然后他的下个版本就是3.0了,听说代码重构了,改用C++写了,我上一篇文章写的是vmp1.6的分析,他后面有1.7,1.8,等等,变化不大,我就不浪费时间了,OK,2.12.3这个版本正好取到承上启下的作用,等分析完这个版本就可以去分析3.0了,想想还是有点小兴奋,感觉像打怪升级,现在最新版本也3.9几,当然我这么说肯定要被大神们笑话了,有时候学习就是这样,给自己一点动力,方能事半功倍。
我们把VmProtect.2.12.3目录下的HelloASM.vmp1拖到OD里面,这个文件是用vmp编译过的,然后说下一些设置,首先选项这一栏我选择了最快速度,然后加密的字节,仍旧是程序入口的5个nop指令,生成的exe文件大小是12kb,就这大小而言还不算大,这边再补充一下上个文章中的一个知识点,因为后面需要用到,下面是1.64版本虚拟机入口执行时候的例子
我说一下上面的两个部分,第一部分是1.64demo版本虚拟机入口的部分代码,当EIP为004050FA时,这时候堆栈就是1.64demo版本第二部分的样子,这时ESP = 0019FF44,等下我们用来做对比,接着回到我们的现在的OD。
首先我们看下第一条指令,是一个jmp指令,和以前一样,
再往下看
上面这边已经不是push A , call B 了,在1.6版本这个A就是指加密了的伪代码地址,这个pushfd是占坑的作用,当执行到00405894的时候我们把当前8个寄存器和标志寄存器的值记录一下,如下所示
我们再往下看
00405A0C和00405A11这两处代码加上前面的代码,是不是和push A , call B 一样了呢。00405A2C和00405A2D两条指令组合等于啥也没干,垃圾指令。根据1.6版本的经验,后面的代码就把一堆寄存器入栈了
上面这些代码是不是跟我们前面提到的1.64版本中,从004050E6到004050FA 的代码干的事情一样,只是变得很不好分析了。其实我们可以不用去一个一个去跟踪上面的代码,我们只要在004050B2下个断点,运行到这边看下堆栈,和前面保存的寄存做个比较,就可以还原出他,原来的样子。以下就是执行到004050B2时,堆栈的样子,因为这边寄存器好几个值都是401000,我就保证他们每个都出现一次这样写,
上面的和1.64的对比了一下,基本上相同,这时候esp = 19ff3c,ebp = 0019FF40。为什么我在0019FF40后面注释push 0 ,而不是在0019FF44注释呢,我是根据004050C8的指令推断的,执行到这条指令ebp等于0019FF40,当然后面填充虚拟寄存器的时候也可以证明这一点。多出来没有注释的,现在还不知道干什么用,很有可能就是让伪代码执行的更复杂,我们再往下看
上面这些分析下来,和1.6,1.2版本相比并没有本质的变化。以上就是还没执行handler前的分析过程,下面开始就是分析handler的执行
以上第一条handler的执行过程,依旧是填充虚拟寄存器的handler,将19ff40上的值也就是0填充到了虚拟寄存,有变化的是,少了个 and al,0x3C 这个大家应该有印象吧,之前读取的伪代码有两个作用,一个是计算handler地址,另外一个作用就是解密出虚拟寄存器的偏移,这个版本因为[eax*4 + handler基址]算出的是加密后的handler,那么这个虚拟寄存器的偏移,就得另外存放在伪代码里面。使用了两个字节的伪代码,09和3C,虚拟寄存器的偏移是0x3C,对应前面的push 0。我们再看下一条handler
以上handler的一些注意点,我们分析一下,00404867 上的这条指令,执行后,堆栈上19ff40的值变成AD7B4B1E,上一条handler就是将19ff40的值0,填充到虚拟寄存器,00404874上的这条指令相当于add esp,0x34。作用就是平衡前面的三个push 操作,所以可以将他们视作垃圾指令,同样00405522和00405525组合在一起也是没用的指令,接着我们在看下00405522和00405525组合,这两条指令有点迷惑性,分析之后这个跳转相当于jmp,jg指令要跳转需要满足esp比-0x4大,很显然这个条件永远满足,我们继续看00404158这个ja指令,从他开始往前找影响标志位的指令就是404148的这个比较指令,因为ebp和eax的值都是固定的,所以这个跳转指令相当于jmp,00404154这条指令也是平衡前面的入栈,所以他和前面的几条都是垃圾指令,这条handler总体分析下来总结就是,好像啥也不做,用了很多垃圾指令,和条件跳转干扰我们分析。
我们再看下一条handler
上面这条handler和前面一条handler都是干扰我们分析的,00405193这一条指令的ebp+4 = 0019FF40,就是我们前面填充虚拟寄存器的那个堆栈地址,既然他们是没有用的handler,那他们对应的伪代码是不是可以跳过,就是执行完第一条handler后回到执行40463e处的代码的时候我们把esi的值改为0040590D,这样不就是跳过了那两条handler了呢,我试过了不行,但是在1.2版本碰到干扰的伪代码可以直接修改跳过他,但是这边还是可以改的,还需要改ebp,我们知道第一条handler执行完,回到40463e处代码的时候,ebp = 0019FF44,接着执行第二条,第三条handler完后,回到40463e处代码的时候,ebp = 0019FF40,所以说直接修改esi的值就会出错,这也是作者故意给我们挖的坑,经过分析第二条handler迷惑性很强,又是在伪代码处读取数据,其实他就一个作用将ebp的值减去4,然后第三条handler可以直接跳过。
我们接着往下看第四条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,09和0C,虚拟寄存器的偏移是0C,从他填充到虚拟寄存器值的存放的位置判断这条也是用作混淆的。
我们接着往下看第五条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,09和0C,虚拟寄存器的偏移是0C,从他填充到虚拟寄存器值的存放的位置判断这条也是用作混淆的。
我们接着往下看第六条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,04和24,虚拟寄存器的偏移是24,对应前面的push ebp。
我们接着往下看第七条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,09和08,虚拟寄存器的偏移是08,对应前面的push ecx。
我们接着往下看第八条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,04和34,虚拟寄存器的偏移是34,对应前面的push edx。
我们接着往下看第九条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,04和28,虚拟寄存器的偏移是28,对应前面的push ebx。
我们接着往下看第十条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,72和00,虚拟寄存器的偏移是0,对应前面的push esi。
我们接着往下看第十一条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,09和10,虚拟寄存器的偏移是10,对应前面的push eax。
我们接着往下看第十二条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,04和04,虚拟寄存器的偏移是04,对应前面的push edi。
我们接着往下看第十三条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,09和14,虚拟寄存器的偏移是14,对应前面的push 重复。
我们接着往下看第十四条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,04和38,虚拟寄存器的偏移是38,对应前面的push eflag。
我们接着往下看第十五条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,09和2c,虚拟寄存器的偏移是2c,对应前面的85011D2F 。
我们接着往下看第十六条handler,也就是第一条执行的那个handler,使用了两个字节的伪代码,04和30,虚拟寄存器的偏移是30,对应前面的伪代码地址 。
执行到这边虚拟寄存器已经填充完毕。我们看下分布
这里我把数值替换成对应的寄存器
上面的这个位置表中根据之前分析1.2版本经验推断,混淆,未填充(可能不只这两种),这些位置的虚拟寄存器,可以当做变量随便使用,其他虚拟寄存器,只在模拟被vm的代码时候,用于保存计算结果。
我们接着看第十七条handler,使用了两个字节的伪代码,C4和38
所以上面这条handler也是用于混淆的handler了,没作用。
我们接着看第十八条handler,也就是第二条执行的那个handler,前面分析过了,执行之前ebp = 19ff70,执行完之后,ebp=19ff6c,将读取到的4字节存放到ebp中。对应5个字节伪代码0x1E,0x73,B6,0x1B,0x46。
我们接着看第十九条handler,这边我就不把对应的代码全部贴出来了,前面分析过后,基本上哪些是垃圾指令,都能够一眼看出来了,这里就做一些分析记录就行了,这条handler执行之后,[0019FF68] = FFFFFEFF, ebp = 0019FF68 , 对应的3字节伪代码,0x23,0xff,0xfe。esi = 00405931。
我们接着看第二十条handler,这条handler执行之后,[0019FF68] = FFFFFEFF, ebp = 0019FF68 , 对应的3字节伪代码,0x23,0xff,0xfe。esi = 00405931。
我们接着看第二十一条handler,这条handler执行之后,[0019FF64] = 0x246, ebp = 0019FF64, 对应的2字节伪代码,0x10,0x38。esi = 00405933。这条是混淆用的
我们接着看第二十二条handler,这条handler执行之后,[0019FF60] = 0x0019FF64, ebp = 0019FF60, 对应的1字节伪代码,0x4e。esi = 00405934。还看不出来干什么的
我们接着看第二十三条handler,这条handler执行之后,[0019FF60] = 0x246, ebp = 0019FF60, 对应的1字节伪代码,0x42。esi = 00405935。这条也是混淆用的,分析到这边,发现前面全是搞混淆的,这边以后我加快分析,就不每一条执行的handler都记录了。
伪代码地址405936 对应的handler,将某个值填充到偏移为18的虚拟寄存器,我们前面做了个表格,知道这个虚拟寄存器是未填充的,所以我们可以大胆判断,这条也是混淆用的。
伪代码地址405939 对应的handler,这边很有意思,将虚拟标志寄存器的值0x246,存放到偏移为0x2c的那个虚拟寄存器,这边应该是虚拟寄存器位置互换,位于偏移为0x38的标志虚拟寄存器就解放了,后面有多次对其进行垃圾数据的写入 。
伪代码地址40593D 对应的handler,开始计算esi的值,这里是读取伪代码的值, 期间还会多次读取伪代码的数据进行各种解密计算,其中穿插有很多干扰的handler,和一些其他的环节,这边我就不一一分析,计算过程了。
伪代码地址40597B 对应的handler,这条将偏移为0x3c的那个虚拟寄存器值 0 ,存放到0x19ff6c,我们再看下一条handler,这条将偏移为0x8的那个虚拟寄存器值0x0401000,存放到0x19ff68,我们再看下一条handler,这条将偏移为0x4的那个虚拟寄存器值0x0401000,存放到0x19ff64,我们再看下一条handler,这条将偏移为0x0的那个虚拟寄存器值0x0401000,存放到0x19ff60,我们再看下一条handler,这条将偏移为0x2c的那个虚拟寄存器值0x00000246,存放到0x0019FF5C,我们再看下一条handler,这条将偏移为0x10的那个虚拟寄存器值0x0019FFCC,存放到0x0019FF58,我们再看下一条handler,这条将偏移为0x4的那个虚拟寄存器值0x0401000,存放到0x0019FF54,我们再看下一条handler,这条将偏移为0x28的那个虚拟寄存器值0x0037C000存放到0x0019FF50(这边解释一下,这个为什么和刚开始执行时候的ebx不一样,因为每次运行程序断在入口点的时候ebx都不一样,由于我调试的时候重新运行了程序)我们再看下一条handler,这条将偏移为0x24的那个虚拟寄存器值0x0019FF80,存放到0x0019FF4C我们再看下一条handler,这条将偏移为0x8的那个虚拟寄存器值0x00401000,存放到0x0019FF48我们再看下一条handler,这条将偏移为0x14的那个虚拟寄存器值0x00401000,存放到0x0019FF44我们再看下一条handler,这条将偏移为0xC的那个虚拟寄存器值0xAD7B4B1E,存放到0x0019FF40
我们总结一下上面的这几条虚拟寄存器值吐出到ebp指向的堆栈操作,前面因为我命名的时候是根据他们的值命名的,但是发现有好几个寄存器值都是一样的,其实这边应该把他们的值先设置成不同的比较好一点,都分析到这里了,只能硬着头皮继续分析,一些虚拟寄存器名字可能会有张冠李戴的错误,遇到这个不用管它。
我们再看下一条handler,这一条是条读取指令执行完,[19ff3c] = 5284B4E2,我们再看下一条,这一条加法指令执行完,[19ff40] = 0,我们再看下一条,这一条就是对偏移为0x34的那个虚拟寄存器写入00000257,这是个标志寄存器的值,所以这里正好印证前面的分析。我们再看下一条,这条将偏移为0x3c的那个虚拟寄存器值0x0,存放到0x19ff3c,我们再看下一条,这条将偏移为0x38的那个虚拟寄存器值0x00405899,这个0x00405899就是我们前面讲的经过多次解密计算后的将要改写esi值的值,这里偏移为0x38的那个虚拟寄存器保存了这个值,再存放到0x19ff38,等待使用。我们再看下一条handler,这条handler对应的伪代码地址0x40599f,我们全面分析一下,
上面这一条handler执行完,esi变为0x00405899。
我们接着看下一条handler,这条是将偏移为0x28的那个虚拟寄存器(对应ebx)值改为0。
我们接着看下一条handler,这条是从伪代码读取4字节的数据AD7B4B1E。我们接着看伪代码地址为4058A3的handler,这里是将AD7B4B1E存放在偏移为0x1c的那个虚拟寄存器中,
我们接着看下一条handler,这条handler是将0019FF44的值00401000,存放到偏移为0xC的那个虚拟寄存器,我们前面推导出,0019FF44保存的是偏移为0x14的那个虚拟寄存器(对应edx),这边应该也是虚拟寄存器位置互换了,
我们接着看下一条handler,这条handler是将0019FF48的值00401000,存放到偏移为0x10的那个虚拟寄存器,我们前面推导出,0019FF48保存的是偏移为0x8的那个虚拟寄存器(对应ecx),这边应该也是虚拟寄存器位置互换了
我们接着看下一条handler,这条handler是将0019FF4C的值0019FF80,存放到偏移为0x18的那个虚拟寄存器,我们前面推导出,0019FF4C保存的是偏移为0x24的那个虚拟寄存器(对应ebp),这边应该也是虚拟寄存器位置互换了
我们接着看下一条handler,这条handler是将0019FF50的值003AE000,存放到偏移为0x14的那个虚拟寄存器,我们前面推导出,0019FF50保存的是偏移为0x28的那个虚拟寄存器(对应ebx),这边应该也是虚拟寄存器位置互换了
我们接着看下一条handler,这条handler是将0019FF54的值0401000,存放到偏移为0x0的那个虚拟寄存器,我们前面推导出,0019FF54保存的是偏移为0x4的那个虚拟寄存器(对应edi),这边应该也是虚拟寄存器位置互换了
我们接着看伪代码地址为4058CD对应的handler,这条handler是将0019FF58的值0019FFCC,存放到偏移为0x24的那个虚拟寄存器,我们前面推导出,0019FF58保存的是偏移为0x10的那个虚拟寄存器(对应eax),这边应该也是虚拟寄存器位置互换了,这边要说一下这条handler执行前,前面执行了好多干扰handler,所做的事情完全一样但是就是没有意义。
我们接着看下一条handler,这条handler是将0019FF5C的值0x246,存放到偏移为0x34的那个虚拟寄存器,我们前面推导出,0019FF5C保存的是偏移为0x2C的那个虚拟寄存器(对应新eflag),这边应该也是虚拟寄存器位置互换了,这里我解释一下这个eflag,他本来的偏移是0x38,后来有换到0x2C,这次又换到了0x34,挺有意思的。从执行伪代码地址40597B开始,虚拟寄存器的值相当于拷贝了一份到堆栈上,所以可以随便去互换各个虚拟寄存器的位置。
我们接着看下一条handler,这条handler是将0019FF60的值0401000,存放到偏移为0x30的那个虚拟寄存器,我们前面推导出,0019FF60保存的是偏移为0x0的那个虚拟寄存器(对应esi),这边应该也是虚拟寄存器位置互换了
我们接着看下一条handler,这条handler是将0019FF64的值0401000,存放到偏移为0x8的那个虚拟寄存器,我们前面推导出,0019FF64保存的是偏移为0x4的那个虚拟寄存器(对应edi),这边应该也是虚拟寄存器位置互换了
我们接着看下一条handler,这条handler是将0019FF68的值0401000,存放到偏移为0x20的那个虚拟寄存器,我们前面推导出,0019FF68保存的是偏移为0x8的那个虚拟寄存器(对应ecx),这边应该也是虚拟寄存器位置互换了
我们接着看下一条handler,这条handler是将0019FF6C的值0,存放到偏移为0x3C的那个虚拟寄存器,我们前面推导出,0019FF6C保存的是偏移为0x3C的那个虚拟寄存器(对应重定位0)。
我们接着看下一条handler,这条handler是将0019FF70的值0x246,存放到偏移为0x4的那个虚拟寄存器, 我们前面知道,0x246就是虚拟标志寄存器的值。
[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于 6天前
被阿强编辑
,原因: