返回
顶部

references:

术语:

  • VIP,virtual instruction pointer相当于x86的ip寄存器,指向下一条指令的地址,vmp2使用rsi来保存vip的值,rsi就是vip
  • VSP,virtual stack pointer,相当于x86的rsp,vmp 2使用rbp存储VSP,rbp相当于vsp
  • VM handler,用于执行虚拟指令的routine,例如VADD64,会将栈上的两个值加起来并将结果和RFLAGS寄存器一起保存在栈上
  • Virtual Instruction,也被称作虚拟字节码,是由虚拟机负责解释并执行的字节序列,每一个虚拟指令至少包含一个操作数,第一个操作数包含指令的opcode
  • virtual opcode,所有虚拟指令的第一个操作数,这个是vm handler的index,vmp2的opcode总是1字节
  • IMM/immeidate value,编码在虚拟指令中的一个值,就是一个等待被操作的数,比如将这个值转移到栈中或者到一个寄存器中,虚拟指令比如LREG,SREG和LCONST都拥有立即数在里面
  • Transformations,这个术语指的是解密虚拟指令中的操作数或者vm handler的index的操作,包括add\sub\inc\dec\not\neg\shl\shr\ror\rol\BSWAP,操作size为1、2、4、8字节,可以拥有立即数,比如xor rax,0x12345,或者add rax,0x12345

VMP 2有两种混淆手段,一种是大量无用的jcc跳转指令,另一种是大量无用的影响EFLAGS寄存器的指令,比如无意义的cmp或者bit test指令,这两种方式分别被称作opaque branching和dead store

本地寄存器

non-volatile register

rsi总是VIP,操作数从rsi寄存器存储的地址中取出

rsi的初始值由vm_entry初始化

rbp总是VSP,rbp中存储的是本地栈内存地址,

虚拟化

下图是一个简单的斐波那契数列函数虚拟化前后的样子

image-20250527184518419

这里使用的虚拟化工具是tigress

测试源代码

虚拟化命令:

export TIGRESS_HOME=/home/xxx/Music/tigress/3.1
export PATH="$PATH:/home/xxx/Music/tigress/3.1"
tigress --Environment=x86_64:Linux:Gcc:4.6 --Transform=Virtualize --Functions=fib,fac --out=vtest1.c test1.c

在main函数中有个这玩意儿

image-20250527195619336

megaInit函数,不过在虚拟化选项中这个函数并没有用到,可能会在别的选项中用到,这个函数里面的内容是空的

image-20250527195757629

vm entry

image-20250528100451274

然后我们查看汇编代码可以找到虚拟栈

image-20250528100653114

上图中rbp-120h被存储到了rbp-128h中,那么rbp-128h很可能就是VSP

而且观察这个局部变量的交叉引用和使用方式,看起来也很像是VSP

image-20250528100808340

image-20250528101150629

另外我们在上图中也可以看到VIP每次都会先自增1,然后再把自增后的结果存回去

loc_401720:
mov     rax, [rbp+VIP]
add     rax, 1
mov     [rbp+VIP], rax
mov     rax, [rbp+VIP]
mov     eax, [rax]; 自增1取值,就是取出来opcode之后的操作数
movsxd  rdx, eax
mov     rax, [rbp+VSP]  ; 取出VSP
add     rax, 8          ; VSP+=8
lea     rcx, [rbp+var_20]
add     rdx, rcx; 操作数加上一个局部变量地址放入到栈中
mov     [rax], rdx      ; VSP压栈
mov     rax, [rbp+VSP]
add     rax, 8
mov     [rbp+VSP], rax  ; 存储修改后的VSP
mov     rax, [rbp+VIP]
add     rax, 4
mov     [rbp+VIP], rax; VIP+4然后存回去,一共是+5,opcode+操作数

可以注意到的是VSP的增长方向和x86的rsp是反过来的

vm handler

他这个handler的dispatch也是非常的简单粗暴,直接就是一堆cmp跳转

image-20250528103812760

每个opcode对应一个handler,但是这个opcode是随机的并不是固定的,在另一个虚拟化过后的函数fib中,opcode就又都不一样了