查询I/O通信端口

原理:使用IN指令来读取特定端口的数据进行两机通讯,但由于IN指令属于特权指令,在处于保护模式下的真机上执行此指令时,除非权限允许,否则将会触发类型为”EXCEPTION_PRIV_INSTRUCTION”的异常,而在虚拟机中并不会发生异常,在指定功能号为0xA/10(获取VMware版本)时,会在EBX中返回其版本号“VMXH”;而当功能号为0x14时,可用于获取VMware内存大小,当大于0时则说明处于虚拟机中。代码分析如下:

//查询I/O通信端口
BOOL CheckVMWare1()
{
        BOOL bResult = TRUE;
        __try
        {
                __asm
                {
                        push   edx
                        push   ecx
                        push   ebx                //保存环境
                        mov    eax, 'VMXh'
                        mov    ebx, 0             //将ebx清零
                        mov    ecx, 10            //指定功能号,用于获取VMWare版本,为0x14时获取VM内存大小
                        mov    edx, 'VX'          //端口号
                        in     eax, dx            //从端口edx 读取VMware到eax
                        cmp    ebx, 'VMXh'        //判断ebx中是否包含VMware版本’VMXh’,若是则在虚拟机中
                        setz[bResult]             //为零 (ZF=1) 时设置字节
                        pop    ebx                //恢复环境
                        pop    ecx
                        pop    edx
                }
        }
        __except (EXCEPTION_EXECUTE_HANDLER)       //如果未处于VMware中,则触发此异常
        {
                bResult = FALSE;
        }
        return bResult;
}

利用虚拟硬件检测

网卡MAC地址检测

原理:网卡设备的MAC地址是唯一不变的(虽然也能物理修改)。
MAC地址的前三个字节标识一个提供商,所以一般情况下只需要找到VM固定的前三个字节就可以了~
ipconfig /all

//通过MAC地址检测
BOOL CheckVMWare2()
{
        string mac;
        getMacAddr(mac);            //API见附件,以下是3种常见标识 
        if (mac == "00-05-69" || mac == "00-0c-29" || mac == "00-50-56")
        {
                return TRUE;
        }
        else
        {
                return FALSE;
        }
}

最后修改日期:2020年2月27日

作者