我是虚拟机世界的初学者,有一个小问题。如果软件在 VM 上运行(例如 VMware Player),它如何知道它安装在 VM 上?软件是从操作系统获取信息还是软件和硬件(VMware Player)之间有直接通信?先感谢您
2 回答
不幸的是,没有唯一的答案。每个虚拟机都有一种您可以使用的桥接器,但您必须为要检测的每个 VM 编写特定的检查(示例是 VC++ 特定的,但您可以轻松地将它们调整到您的编译器)。请注意,理论上您应该无法确定您是否在 VM 下运行。
虚拟机
VMWare 使用IN
指令来处理客户机到主机的通信。通常,该指令在用户模式下不可用,它会引发异常,但 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;
}
虚拟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
比赛Model
和Manufacturer
反对(?i)(Hyper-V|Virtual Machine|VMware|VirtualBox)
。 - 在
Win32_VideoController
对阵.Name
_(?i)Hyper-V
CPUID
说明也可以帮助您(当支持这些值时)。
EAX
设置为 0(获取供应商 ID),您将进入EBX
,EDX
以及一个带有ECX
CPU 供应商名称的 ASCII 字符串(请参阅维基百科的列表)。当然,VM 可以返回一个错误的名称,或者它可能是一个未知的 VM。
如果您在 VM 下运行,设置为 1(处理器信息和功能位)(管理程序)的第31EAX
位设置ECX
为1。再次,VM 可能会返回错误结果(并且某些 VM 不遵守此位)。
当我不得不解决这个问题时,我还尝试检查 VM 中不支持的硬件技巧/功能(例如 USB Legacy 支持),但我发现它不够可靠,无法在生产中使用。
在评论中你说你在 Android 上运行。这是一个完全不同的故事,但常见的技术类似于我所说的 WMI(或上述的组合)。一种常见的方法是检查知名模拟器的设备名称字符串,从 Android 7 开始有一个特定的标志ro.kernel.qemu
。
你能伪造这些价值观吗?是的,例如看看有没有办法在模拟器中将 ro.kernel.qemu 设置为 0?. 请注意,任何想要阻止您在仿真下使用它的体面应用程序也将使用多种检测技术(另请参见Android:以编程方式获取硬件信息)。
我认为只要它运行正常,它对于运行它的软件并不重要。
如果你真的想检查你是否正在运行(或者你自己编写的代码)是否在 VM 上运行。在 Windows 情况下,可以在设备管理器中检查硬件(Windows 情况),因为 VM 应用程序会创建一些虚拟硬件。例如VMWare
将创建一些名为 VMware... 的硬件设备。