0

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

4

2 回答 2

3

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

虚拟机

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

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;
}

虚拟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 非常简单,只需要检查是否存在伪设备即可\\.\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),您将进入EBXEDX以及一个带有ECXCPU 供应商名称的 ASCII 字符串(请参阅维基百科的列表)。当然,VM 可以返回一个错误的名称,或者它可能是一个未知的 VM。

如果您在 VM 下运行,设置为 1(处理器信息和功能位)(管理程序)的第31EAX设置ECX1。再次,VM 可能会返回错误结果(并且某些 VM 不遵守此位)。


我不得不解决这个问题时,我还尝试检查 VM 中不支持的硬件技巧/功能(例如 USB Legacy 支持),但我发现它不够可靠,无法在生产中使用。


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

你能伪造这些价值观吗?是的,例如看看有没有办法在模拟器中将 ro.kernel.qemu 设置为 0?. 请注意,任何想要阻止您在仿真下使用它的体面应用程序也将使用多种检测技术(另请参见Android:以编程方式获取硬件信息)。

于 2017-09-08T11:10:39.267 回答
0

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

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

于 2017-09-08T11:09:26.340 回答