0%

检测虚拟机环境

检测虚拟机环境

今天在写程序时,不想让这个程序在虚拟机上运行

于是尝试了一下代码:

注册表和硬件检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <windows.h>

// 函数声明
BOOL CheckRegistry();
BOOL CheckHardware();

int main() {
if (CheckRegistry() || CheckHardware()) {
printf("可能运行在虚拟机中。\n");
} else {
printf("未检测到虚拟机。\n");
}
return 0;
}

// 检查注册表
BOOL CheckRegistry() {
HKEY hKey;
LONG lResult;
DWORD dwType, dwSize;
char szBuffer[256];

// 检查VMware注册表项
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\VMware, Inc.\\VMware Tools", 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
RegCloseKey(hKey);
return TRUE;
}

// 检查VirtualBox注册表项
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Oracle\\VirtualBox Guest Additions", 0, KEY_READ, &hKey);
if (lResult == ERROR_SUCCESS) {
RegCloseKey(hKey);
return TRUE;
}

return FALSE;
}

// 检查硬件信息
BOOL CheckHardware() {
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);

// 检查处理器数量
if (sysInfo.dwNumberOfProcessors <= 1) {
return TRUE;
}

// 检查物理内存
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(memInfo);
GlobalMemoryStatusEx(&memInfo);
if (memInfo.ullTotalPhys < 1024 * 1024 * 1024) { // 小于1GB
return TRUE;
}

return FALSE;
}

  1. CheckRegistry函数:检查系统注册表中是否存在与虚拟机相关的注册表项。例如,VMware和VirtualBox在安装时会在注册表中添加特定的项。

  2. CheckHardware函数:检查系统的硬件信息,如处理器数量和物理内存大小。虚拟机通常具有较少的处理器和较小的内存。

缺陷

虚拟机可能会隐藏特征来避免被检测,在实际操作中,检测注册表确实没法判断成功程序所在环境为虚拟机,仍然能运行成功。

GPU检测

突然想到了在打开任务管理器时,主机会显示GPU,而虚拟机不会显示GPU

主机image-20240711130459658

虚拟机Win11image-20240711130535937

虚拟机Win10image-20240711130613593

检测GPU信息

但是在使用程序检测GPU时,仍然在虚拟机中检测出:image-20240711130804118

但是,这里发现GPU有很明显的特征,适配器名称有VMware字段

所以,获取到GPU信息后,匹配一下适配器名称中有没有VMware或者VirtualBox字段

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 辅助函数:检查字符串是否包含特定子字符串(不区分大小写)
int containsSubstring(const char* str, const char* substr) {
char lowerStr[128];
char lowerSubstr[128];
int i;

// 将字符串和子字符串转换为小写
for (i = 0; str[i] && i < 127; i++) {
lowerStr[i] = tolower((unsigned char)str[i]);
}
lowerStr[i] = '\0';

for (i = 0; substr[i] && i < 127; i++) {
lowerSubstr[i] = tolower((unsigned char)substr[i]);
}
lowerSubstr[i] = '\0';

return strstr(lowerStr, lowerSubstr) != NULL;
}

DWORD WINAPI GPUProcDetect(LPVOID lpParameter)
{
// 初始化Direct3D
IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (pD3D == NULL) {
printf("Direct3D 初始化失败\n");
return 1;
}

// 获取系统中第一个显示适配器的信息
D3DADAPTER_IDENTIFIER9 adapterIdentifier;
HRESULT hr = pD3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &adapterIdentifier);
if (FAILED(hr)) {
printf("获取适配器信息失败\n");
pD3D->Release();
exit(1);
}

// 输出适配器信息
/*printf("适配器名称: %s\n", adapterIdentifier.Description);
printf("设备名称: %s\n", adapterIdentifier.DeviceName);
printf("设备驱动版本: %d.%d.%d.%d\n",
HIWORD(adapterIdentifier.DriverVersion.HighPart),
LOWORD(adapterIdentifier.DriverVersion.HighPart),
HIWORD(adapterIdentifier.DriverVersion.LowPart),
LOWORD(adapterIdentifier.DriverVersion.LowPart));*/

// 检查适配器名称是否包含VMware或VirtualBox
if (containsSubstring(adapterIdentifier.Description, "vmware") || containsSubstring(adapterIdentifier.Description, "virtualbox")) {
printf("检测到虚拟机环境,程序将退出。\n");
pD3D->Release();
Sleep(3000);
exit(1);
}

// 释放Direct3D对象
pD3D->Release();

return 0;
}

image-20240711131135615

这也只是一种现在比较可行的简单的检测方法,不保证可能厂商以后把这个特征也抹除