0x1 原理
- 汇编指令
cpuid
本身就提供 虚拟机检测 - 一共有两种检测方式
- 基于 vmp3.4
0x1.1 获取虚拟机状态
eax=1
作为参数,调用cpuid
ecx[31]
就是当前的运行状态1: 虚机
0: 真机
代码实现
bool check_by_cpuid ()
{
bool IsUnderVM = false;
__asm {
xor eax, eax;
inc eax;
cpuid;
bt ecx, 0x1f;
jc UnderVM;
nop;
jmp NotUnderVM;
UnderVM:;
mov IsUnderVM, 0x1;
NotUnderVM:
nop;
}
return IsUnderVM;
}
0x1.2 获取平台名称
eax=0x40000000
作为参数,调用cpuid
- 此时
ebx,ecx,edx
中以16进制保存了当前虚拟机的字符串名字
代码实现
void get_Hypervisor (char* out_name)
{
int n_ebx = 0;
int n_ecx = 0;
int n_edx = 0;
__asm {
xor eax, eax;
mov eax, 0x40000000;
cpuid;
mov n_ebx, ebx;
mov n_ecx, ecx;
mov n_edx, edx;
nop;
}
*(int*)out_name = n_ebx;
*((int*)out_name + 1) = n_ecx;
*((int*)out_name + 2) = n_edx;
}
这是两个虚拟机中的例子
0x2 对抗
- 直接需改源程序 肯定是不现实 的
- 这里选择直接需改 虚拟机的指令
- 有一些虚拟机支持 修改 汇编指令的返回值
- hyperv的话开启虚拟机的嵌套虚拟化就可以解决这个问题
0x2.1 vmware
- 这里选择 vm虚拟机作为例子
.vmx
是vm虚拟机的配置文件,每一个虚拟机都有- 可以在
.vmx
文件中自定义汇编指令
对抗方案1:
cpuid.1.ecx="0---:----:----:----:----:----:----:----"
对抗方案2:
cpuid.40000000.ebx="0000:0000:0000:0000:0000:0000:0000:0000"
cpuid.40000000.ecx="0000:0000:0000:0000:0000:0000:0000:0000"
cpuid.40000000.edx="0000:0000:0000:0000:0000:0000:0000:0000"
对抗效果: