如何检测软件是否存在VM

时间:2017-09-08 11:04:51

标签: virtual-machine cpuid

我是虚拟机世界的初学者,并且有一个小问题。如果某个软件在VM上运行(例如VMware Player),它是如何知道它安装在VM上的?软件是否从操作系统获取信息,或者软件和硬件之间是否存在直接通信(VMware Player)?提前谢谢你

2 个答案:

答案 0 :(得分:1)

不幸的是,没有一个独特的答案。每个虚拟机都有一种可以使用的桥接,但是您必须为要检测的每个VM编写特定的检查(示例是VC ++特定的,但您可以轻松地将它们调整到您的编译器)。请注意,在 theory 中,您无法确定是否在VM下运行。

VMWare的

VMWare使用IN指令来处理guest虚拟机以进行主机通信。通常,此指令在用户模式下不可用,并且它会抛出异常,但VM会处理它。如果我们捕获异常,那么我们知道我们没有在VMWare下运行(或者我们是执行IN指令的权限)。第二次测试以确定我们是否拥有特权或者我们是否在WMWare下运行几乎没用,但是标准检测代码并且我在这里写它是为了完整性(我们只检查预期的字符串VMXh寄存器中的EBX,注意我们必须使用所需的值初始化一些寄存器。)

bool IsRunningInsideVmWare()
{
    bool flag = true;

    __try
    {
        __asm
        {
            push    edx
            push    ecx
            push    ebx

            mov     eax, 'VMXh'
            mov     ebx, 0
            mov     ecx, 10
            mov     edx, 'VX'

            in      eax, dx
            cmp     ebx, 'VMXh'
            setz    [flag]

            pop     ebx
            pop     ecx
            pop     edx
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        flag = false;
    }

    return flag;
}

Virtual PC

客人可以使用不存在的指令0f3f070b与主机通信,然后你可以做的就是发出这样的指令,VM会正确解释它,但是物理CPU会抛出异常(你可以捕获并跳转)过度违规的指令)。在这个例子中,我们将EBX设置为异常处理程序中的已知值,然后我们就可以检测到这种情况。

DWORD __forceinline VpcExceptionFilter(LPEXCEPTION_POINTERS ep)
{
    ep->ContextRecord->ctx->Ebx = -1;
    ep->ContextRecord->ctx->Eip += 4;

    return EXCEPTION_CONTINUE_EXECUTION;
}

bool IsRunningInsideVpc()
{
    bool flag = false;

    __try
    {
        _asm
        {
            push    ebx

            mov     eax, 1
            mov     ebx, 0 

            __emit  0Fh
            __emit  3Fh
            __emit  07h
            __emit  0Bh

            test    ebx, ebx
            setz    [flag]

            pop     ebx
        }
    }
    __except(VpcExceptionFilter(GetExceptionInformation()))
    {
    }

    return flag;
}

VirtualBox的

要检测VirtualBox非常简单,您只需要检查是否存在伪设备\\.\VBoxMiniRdrDN

bool IsRunningInsideVirtualBox()
{
    HANDLE handle = CreateFile("\\\\.\\VBoxMiniRdrDN", GENERIC_READ, FILE_SHARE_READ, 
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (handle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(handle);
        return true;
    }

    return false;
}

可以使用WMI和以下查询完成一些更通用的(假设:您在Windows上运行):

  • Win32_BaseBoard匹配Name(?i)(Hyper-V|Virtual Machine|Microsoft|VMware|VirtualBox|Parallels Virtual)
  • Win32_ComputerSystem匹配ModelManufacturer(?i)(Hyper-V|Virtual Machine|VMware|VirtualBox)
  • Win32_VideoController匹配Name(?i)Hyper-V

CPUID说明也可以为您提供帮助(当支持这些值时)。

EAX设置为0(获取供应商ID ),您将获得EBXEDXECX与CPU供应商的ASCII字符串名称(参见Wikipedia列表)。当然,VM可以返回错误的名称,也可能是未知的VM。

EAX设置为1(处理器信息和功能位ECX虚拟机管理程序)的第31位设置为1 '在VM下运行。同样,VM可能会返回错误结果(并且某些VM不会遵循此位)。

I had to play with this issue我还试图检查VM中不支持的硬件技巧/功能时(例如USB Legacy支持),但我发现它不够可靠用于生产。

评论中你说你在Android上运行。这是一个完全不同的故事,但常见的技术类似于我所说的WMI(或上述的组合)。一种常见的方法是检查众所周知的模拟器的设备名称字符串,从Android 7开始有一个特定的标志ro.kernel.qemu

你可以伪造这些价值观吗?是的,请参阅示例Is there a way to set ro.kernel.qemu to 0 in a emulator?。请注意,任何可以阻止您在仿真中使用它的体面应用程序也将使用多种检测技术(另请参阅Android: Get Hardware Information Programmatically)。

答案 1 :(得分:0)

我认为只要它运行正常,它对运行它的软件很重要。

如果您确实想要检查您是否正在运行(或者如果您的自编代码)正在VM上运行。在Windows情况下,可以检查设备管理器中的硬件(Windows案例),因为VM应用程序会创建一些虚拟硬件。例如,{{1}}将创建一些名为VMware ... devices的硬件。