vmp虚拟化学习(2):JCC指令模拟
vmp的万用门
VMP里的“万用门”主要利用 NOR(或非) 或 NAND(与非) 逻辑运算。因为在理论上,仅靠这两种门中的任何一种,就能组合实现NOT、AND、OR、XOR汇编里面最基本的4种逻辑运算。VMP早期版本以NOR门为主,3.x版本后又引入了NAND门来增加分析难度。
1 | Not(a) = ~a = ~a & ~a = Nand(a,a) |
在VMP 3.x版本中,大量使用了Nand运算来表示其他的各种逻辑,真实地隐藏了原本的各种逻辑运算,有效地加大了逆向分析的难度。
实现跳转指令JCC
VMP虚拟机内通常只有一个唯一的跳转指令(JMP)。条件跳转(如JE、JNZ)并非直接实现,而是先用万用门根据EFLAGS标志位计算出“是否跳转”的结果,然后根据这个结果选择目标地址,再执行那个唯一的跳转指令。
以je指令模拟为例:ZF=1%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F1.png)
这时ebp是虚拟栈寄存器,[ebp]和[ebp+4]存储的都是eflags的值,这条handler是VMP虚拟机中实现NOR(或非)运算的虚拟指令Not(eflags) = Nor(eflags(0x00000246),eflags(0x00000246)) = result0(0xFFFFDB9)
得到~ eflags;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F2.png)
Nor(~ eflags(0xFFFFDB9),imm0(0xFFFFFFBF)) = And(eflags(0x00000246),0x00000040) = result1(0x00000040)
保留zf标志位;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F3.png)
这条handler是VMP虚拟机中实现右移运算(SHR,即 Shift Right)的虚拟指令,shr(result1(0x00000040),imm1(0x6)) = result2(0x00000001)
zf标志位右移到第0位;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F4.png)
这条handler是VMP虚拟机中实现加法运算(ADD)的虚拟指令,add(result2(0x00000001),imm2(0xFFFFFFFF)) = reslut3(0x0000000)
转换成0或-1形式方便后续按位与;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F5.png)
这条handler是是VMP虚拟机中实现NAND(与非)运算的虚拟指令,Not(reslut3) = Nand(reslut3(0x0000000),reslut3(0x0000000)) = result4(0xFFFFFFFF)%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F6.png)
Nand(result4(0xFFFFFFFF),imm3(0x00439204)) = result5(0xFFBC6DFB)
此时出现了一个跳转地址imm3(0x00439204),result5的值可能有两个结果 0xFFFFFFFF 或 ~0x00439204,这取决于ZF是 0 或 1;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F7.png)
Nand(result5(0xFFBC6DFB),result5(0xFFBC6DFB)) = result6(0x00439204)
取反还原出结果 0 或 0x00439204;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F8.png)
Nand(reslut3(0x0000000),imm4(0x00441E38)) = result7(0xFFFFFFFF)
此时出现了另一个跳转地址imm4(0x00441E38),result7的值可能有两个结果 ~0x00441E38 或 0xFFFFFFFF,这取决于ZF是 0 或 1;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F9.png)
Nand(result7(0xFFFFFFFF),result7(0xFFFFFFFF)) = result8(0x00000000)
取反还原出结果 0 或 0x00441E38;%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F10.png)
Add(result6(0x00439204),result8(0x00000000)) = result9(0x00439204)
这里两个数其中必定有一个是0,取决于ZF是 0 或 1,这里就将最终的跳转地址求出来了。%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F11.png)
Add(reloc(0x00000000),result9(0x00439204)) = result10(0x00439204)
重定位相加,得到最终结果。
%EF%BC%9A%E6%8C%87%E4%BB%A4%E6%A8%A1%E6%8B%9F12.png)
后续将跳转地址赋值给esi,esi就是vEIP,这一套流程下来就模拟出来je指令。
