0x1 原理

  • 汇编指令 cpuid本身就提供 虚拟机检测
  • 一共有两种检测方式
  • 基于 vmp3.4

0x1.1 获取虚拟机状态

  1. eax=1作为参数,调用cpuid
  2. 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 获取平台名称

  1. eax=0x40000000作为参数,调用cpuid
  2. 此时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;
}

这是两个虚拟机中的例子

hyperv.png

vmp.png

0x2 对抗

  1. 直接需改源程序 肯定是不现实 的
  2. 这里选择直接需改 虚拟机的指令
  3. 有一些虚拟机支持 修改 汇编指令的返回值
  4. 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"

对抗效果:

image-20200422170937482.png

Last modification:August 20, 2021
如果觉得我的文章对你有用,请随意赞赏