0x00 前言看到有朋友提前发相关文章了,没办法我也只能提前发了。
首先文章不同于其他的文章,从vmp是如何vm opcode入手,看完以后不说还原,相信爆破,静态分析也应该有所帮助。 主要是vmp3.x以下。
0x01 简介vmp的流程 大体如下:
谈谈vmp的还原(1)
谈谈vmp的还原(1)
直接定位到流程:
谈谈vmp的还原(1)
谈谈vmp的还原(1)
首先读了vmp_opcode_begin_block end_block 然后计算_vm_opcode_size
谈谈vmp的还原(1)
没错,之前的帖子有提到,vmp作者设计了4套handle,就是这4套了。
谈谈vmp的还原(1)
注意到上上图113行之后,同时我们也可以看出早期版本的构造
谈谈vmp的还原(1)
下面这个,之前也有提到
谈谈vmp的还原(1)
注意到+8,之后会说
先允许我跳过esi的构造以及修复,继续讲下去
谈谈vmp的还原(1)
可以看到vmp通过这样方式实现jmp vm_entry,所以有些vm插件会通过这种方式来定位到入口 68 xx xx xx xx e9 xx xx xx xx 之后,创建区段vmp0
谈谈vmp的还原(1)
set jmp_entry
谈谈vmp的还原(1)
之后写之前的push esi jmp vm_entry了
谈谈vmp的还原(1)
然后写完之后写vmp1区段,流程大概就这个样子,当然我跳过了构造esi以及对esi的修正
0x10 反汇编引擎 之所以会先谈谈这个,因为如果不看懂这个,后面的vm流程肯定看不懂 为了逆出这个反汇编引擎,我看了几遍opcode的构造方式以及一份开源的反汇编引擎(libudis86)。不过正因为如此,我才大概猜测出来一部分,vmp作者是如何构造这套vm的。
谈谈vmp的还原(1)
谈谈vmp的还原(1)
这个函数大概3000+行 这下面通过这两条指令来看看是怎么反汇编的,当然需要一些基础知识。 1
2
| 817D FC 33020000 cmp dword ptr ss:[ebp-0x4],0x233//563
75 09 jnz short zf.0040D7E2
|
读取opcode
谈谈vmp的还原(1)
然后通过switch跳转
谈谈vmp的还原(1)
先判断类型
谈谈vmp的还原(1)
注意到*(a2-10)其实是对应的这个东西
谈谈vmp的还原(1)
再上个图就明白为什么是 (xx & 2 ) == 2了
谈谈vmp的还原(1)
然后读modrm 0x7D进行查找mnemonic
谈谈vmp的还原(1)
对应的mnemonic
谈谈vmp的还原(1)
谈谈vmp的还原(1)
之后就是解析modrm了挺精妙的,看图就好
谈谈vmp的还原(1)
谈谈vmp的还原(1)
谈谈vmp的还原(1)
谈谈vmp的还原(1)
先对modrm.mod进行分析 判断是否行如[base+disp] 如果是 判断是否有address size override prefix 判断是否包含sib 读取disp 之后再读取immediate
谈谈vmp的还原(1)
创建下一个结构体,读取opcode 0x75
谈谈vmp的还原(1)
其他的没啥好说的看一看,_vmp_SetJccIndex
谈谈vmp的还原(1)
是不是感觉很有意思把hex & 0xf然后switch 可能这样不是很明白 那么我们先看看0x70~0x7f这些opcode是什么
谈谈vmp的还原(1)
那么对照一下就明白了 Vmp作者为了区分溢不溢出 低于不低于做了一个很有意思的事情 初始化了一个 0x11 然后把不溢出不低于的,也就是形如jnx 带n的这样做了 0x11|2
谈谈vmp的还原(1)
那么理解了之后就得到反汇编引擎的结构了
谈谈vmp的还原(1)
谈谈vmp的还原(1)
对应内存中:
谈谈vmp的还原(1)
谈谈vmp的还原(1)
0x11 结束语 写得有点仓促,也懒得整理了 下一贴主要是讲vmp是如何膨胀指令的
|