描述
虚拟环境在模拟硬件设备时会留下一下痕迹或特征,可以通过查找这些内容来判断是否处于虚拟环境中。
1.检查硬盘是否有特定名称
以SetupDiGetClassDevs函数为例:
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#pragma comment(lib, "Setupapi.lib")
// 定义要检查的硬盘名称
#define TARGET_NAME L"VBOX"
// 检查硬盘是否有特定名称
BOOL CheckDiskName()
{
// 初始化一个WinAPI应用程序,并返回一个包含所有磁盘驱动器设备信息的设备信息集句柄
HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
printf("SetupDiGetClassDevs failed: %d\n", GetLastError());
return FALSE;
}
// 遍历设备信息集中的每个设备信息元素
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
DWORD dwIndex = 0;
while (SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_DISK, dwIndex, &DeviceInterfaceData))
{
// 获取设备接口详细数据,并分配足够的内存空间
DWORD dwSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DeviceInterfaceData, NULL, 0, &dwSize, NULL);
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// 获取设备接口详细数据,并打印设备路径
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DeviceInterfaceData, DeviceInterfaceDetailData, dwSize, NULL, NULL))
{
printf("Device path: %ws\n", DeviceInterfaceDetailData->DevicePath);
// 打开设备文件,并获取存储属性
HANDLE hDevice = CreateFile(DeviceInterfaceDetailData->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
STORAGE_PROPERTY_QUERY StoragePropertyQuery;
StoragePropertyQuery.PropertyId = StorageDeviceProperty;
StoragePropertyQuery.QueryType = PropertyStandardQuery;
STORAGE_DEVICE_DESCRIPTOR StorageDeviceDescriptor;
DWORD dwBytesReturned = 0;
// 发送IO控制码,并获取存储属性
if (DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&StoragePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
&StorageDeviceDescriptor, sizeof(STORAGE_DEVICE_DESCRIPTOR),
&dwBytesReturned, NULL))
{
// 获取硬盘名称,并打印
WCHAR szDiskName[256];
ZeroMemory(szDiskName, sizeof(szDiskName));
memcpy(szDiskName,
(BYTE*)&StorageDeviceDescriptor + StorageDeviceDescriptor.VendorIdOffset,
StorageDeviceDescriptor.ProductIdOffset - StorageDeviceDescriptor.VendorIdOffset);
printf("Disk name: %ws\n", szDiskName);
// 比较硬盘名称和目标名称,如果相同,则返回真
if (wcscmp(szDiskName, TARGET_NAME) == 0)
{
return TRUE;
}
}
CloseHandle(hDevice);
}
}
HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData);
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
// 如果没有找到匹配的硬盘名称,则返回假
return FALSE;
}
int main()
{
// 检查硬盘是否有特定名称
BOOL bFound = CheckDiskName();
if (bFound)
{
printf("Disk name is matched, exit\n");
// 这里可以退出程序或执行其他代码
return 0;
}
printf("Disk name is not matched, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
}
以SetupDiEnumDeviceInfo函数为例:
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#pragma comment(lib, "Setupapi.lib")
// 定义要检查的硬盘名称
#define TARGET_NAME L"VMware"
// 定义设备实例ID最大长度
#define MAX_DEVICE_ID_LEN 200
// 检查硬盘是否有特定名称
BOOL CheckDiskName()
{
// 初始化一个WinAPI应用程序,并返回一个包含所有磁盘驱动器设备信息的设备信息集句柄
HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
printf("SetupDiGetClassDevs failed: %d\n", GetLastError());
return FALSE;
}
// 遍历设备信息集中的每个设备信息元素
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DWORD dwIndex = 0;
while (SetupDiEnumDeviceInfo(hDevInfo, dwIndex, &DeviceInfoData))
{
// 获取设备实例ID,并打印
WCHAR szDeviceInstanceId[MAX_DEVICE_ID_LEN];
if (SetupDiGetDeviceInstanceId(hDevInfo, &DeviceInfoData, szDeviceInstanceId, MAX_DEVICE_ID_LEN, NULL))
{
printf("Device instance ID: %ws\n", szDeviceInstanceId);
// 获取设备描述,并打印
WCHAR szDeviceDescription[256];
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)szDeviceDescription, sizeof(szDeviceDescription), NULL))
{
printf("Device description: %ws\n", szDeviceDescription);
// 比较设备描述和目标名称,如果相同,则返回真
if (wcscmp(szDeviceDescription, TARGET_NAME) == 0)
{
return TRUE;
}
}
}
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
// 如果没有找到匹配的硬盘名称,则返回假
return FALSE;
}
int main()
{
// 检查硬盘是否有特定名称
BOOL bFound = CheckDiskName();
if (bFound)
{
printf("Disk name is matched, exit\n");
// 这里可以退出程序或执行其他代码
return 0;
}
printf("Disk name is not matched, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
}
以SetupDiGetDeviceRegistryProperty函数为例:
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#pragma comment(lib, "Setupapi.lib")
// 定义要检查的硬盘名称
#define TARGET_NAME L"VIRTUAL HD"
// 检查硬盘是否有特定名称
BOOL CheckDiskName()
{
// 初始化一个WinAPI应用程序,并返回一个包含所有磁盘驱动器设备信息的设备信息集句柄
HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
printf("SetupDiGetClassDevs failed: %d\n", GetLastError());
return FALSE;
}
// 遍历设备信息集中的每个设备信息元素
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DWORD dwIndex = 0;
while (SetupDiEnumDeviceInfo(hDevInfo, dwIndex, &DeviceInfoData))
{
// 获取设备描述,并打印
WCHAR szDeviceDescription[256];
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)szDeviceDescription, sizeof(szDeviceDescription), NULL))
{
printf("Device description: %ws\n", szDeviceDescription);
// 比较设备描述和目标名称,如果相同,则返回真
if (wcscmp(szDeviceDescription, TARGET_NAME) == 0)
{
return TRUE;
}
}
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
// 如果没有找到匹配的硬盘名称,则返回假
return FALSE;
}
int main()
{
// 检查硬盘是否有特定名称
BOOL bFound = CheckDiskName();
if (bFound)
{
printf("Disk name is matched, exit\n");
// 这里可以退出程序或执行其他代码
return 0;
}
printf("Disk name is not matched, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
}
2.检查HDD Vendor ID是否有特定值
以DeviceIoControl函数为例:
#include <windows.h>
#include <stdio.h>
// 定义要检查的HDD Vendor ID
#define TARGET_ID "WDC"
// 定义启用GUID_DEVINTERFACE_DISK的宏
#define _NTDDI_WIN2K 0x05000000
// 包含设备和驱动程序安装的头文件
#include <setupapi.h>
// 链接到设备和驱动程序安装的库文件
#pragma comment(lib, "Setupapi.lib")
// 定义设备实例ID最大长度
#define MAX_DEVICE_ID_LEN 200
// 检查HDD Vendor ID是否有特定值
BOOL CheckHDDVendorID()
{
// 初始化一个WinAPI应用程序,并返回一个包含所有磁盘驱动器设备信息的设备信息集句柄
HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
printf("SetupDiGetClassDevs failed: %d\n", GetLastError());
return FALSE;
}
// 遍历设备信息集中的每个设备信息元素
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
DWORD dwIndex = 0;
while (SetupDiEnumDeviceInfo(hDevInfo, dwIndex, &DeviceInfoData))
{
// 获取设备实例ID,并打印
WCHAR szDeviceInstanceId[MAX_DEVICE_ID_LEN];
if (SetupDiGetDeviceInstanceId(hDevInfo, &DeviceInfoData, szDeviceInstanceId, MAX_DEVICE_ID_LEN, NULL))
{
printf("Device instance ID: %ws\n", szDeviceInstanceId);
// 打开设备句柄
HANDLE hDevice = CreateFile(szDeviceInstanceId, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
// 定义存储查询结果的结构体
typedef struct _STORAGE_PROPERTY_QUERY {
STORAGE_PROPERTY_ID PropertyId; // 使用枚举类型
STORAGE_QUERY_TYPE QueryType;
UCHAR AdditionalParameters[1];
} STORAGE_PROPERTY_QUERY;
typedef struct _STORAGE_DEVICE_DESCRIPTOR {
ULONG Version;
ULONG Size;
UCHAR DeviceType;
UCHAR DeviceTypeModifier;
BOOLEAN RemovableMedia;
BOOLEAN CommandQueueing;
ULONG VendorIdOffset;
ULONG ProductIdOffset;
ULONG ProductRevisionOffset;
ULONG SerialNumberOffset;
STORAGE_BUS_TYPE BusType;
ULONG RawPropertiesLength;
UCHAR RawDeviceProperties[1];
} STORAGE_DEVICE_DESCRIPTOR;
// 构造查询结构体
STORAGE_PROPERTY_QUERY query = { 0 };
query.PropertyId = StorageDeviceProperty; // 使用枚举常量 // 修改这里
query.QueryType = PropertyStandardQuery; // 标准查询
// 发送控制代码到设备驱动程序
DWORD dwBytesReturned = 0;
BYTE buffer[1024] = { 0 }; // 存储返回数据的缓冲区
BOOL bResult = DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
buffer, sizeof(buffer),
&dwBytesReturned, NULL);
if (bResult)
{
// 获取返回数据中的设备描述结构体
STORAGE_DEVICE_DESCRIPTOR* deviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)buffer;
// 获取HDD Vendor ID并打印
char* vendorId = (char*)buffer + deviceDescriptor->VendorIdOffset;
printf("HDD Vendor ID: %s\n", vendorId);
// 比较HDD Vendor ID和目标值,如果相同,则返回真
if (strcmp(vendorId, TARGET_ID) == 0)
{
return TRUE;
}
}
}
}
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
// 如果没有找到匹配的HDD Vendor ID,则返回假
return FALSE;
}
int main()
{
// 检查HDD Vendor ID是否有特定值
BOOL bFound = CheckHDDVendorID();
if (bFound)
{
printf("HDD Vendor ID is matched, exit\n");
// 这里可以退出程序或执行其他代码
return 0;
}
printf("HDD Vendor ID is not matched, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
}
3.检查音频设备是否存在
一般虚拟环境可能不会存在音频设备,那么恶意软件即可通过检查音频设备来达到规避的目的。
以CoCreateInstance函数为例:
以CoCreateInstance函数为例:
#include <windows.h>
#include <stdio.h>
// 定义启用IMMDevice接口的宏
#define _WIN32_WINNT 0x0600
// 包含MMDevice API的头文件
#include <mmdeviceapi.h>
// 检查音频设备是否存在
BOOL CheckAudioDevice()
{
// 初始化COM库
CoInitialize(NULL);
// 创建一个IMMDeviceEnumerator接口对象
IMMDeviceEnumerator* pEnumerator = NULL;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
if (FAILED(hr))
{
printf("CoCreateInstance failed: %x\n", hr);
return FALSE;
}
// 获取默认的音频输出设备
IMMDevice* pDevice = NULL;
hr = pEnumerator->lpVtbl->GetDefaultAudioEndpoint(pEnumerator, eRender, eConsole, &pDevice);
if (FAILED(hr))
{
printf("GetDefaultAudioEndpoint failed: %x\n", hr);
return FALSE;
}
// 释放COM对象
pDevice->lpVtbl->Release(pDevice);
pEnumerator->lpVtbl->Release(pEnumerator);
// 返回真表示有音频设备
return TRUE;
}
int main()
{
// 检查音频设备是否存在
BOOL bFound = CheckAudioDevice();
if (!bFound)
{
printf("No audio device found, exit\n");
// 这里可以退出程序或执行其他代码
return 0;
}
printf("Audio device found, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
}
4.检查CPU温度信息是否可用
一般虚拟环境不会支持该功能,恶意软件可以尝试读取CPU温度信息来判断是否在虚拟环境中。
wmic /namespace:\\root\WMI path MSAcpi_ThermalZoneTemperature get CurrentTemperature
5.检查物理显示适配器的 IDirect3D9 接口
恶意软件可以获取或控制系统中的Direct3D设备,并检查物理显示适配器的IDirect3D9接口的Description输出是否是特定值,如果是则不运行,从而规避检测。
以Direct3DCreate9函数为例:
以Direct3DCreate9函数为例:
#include <windows.h>
#include <d3d9.h>
#include <stdio.h>
// 定义要检查的Description输出
#define TARGET_DESC "VMware SVGA 3D"
// 检查物理显示适配器的Description输出是否是特定值
BOOL CheckDisplayAdapterDesc()
{
// 创建一个IDirect3D9对象
IDirect3D9* pD3D = NULL; // 声明为C类型
pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (pD3D == NULL)
{
printf("Direct3DCreate9 failed\n");
return FALSE;
}
// 获取物理显示适配器的数量
UINT AdapterCount = pD3D->GetAdapterCount();
// 遍历每个物理显示适配器
for (UINT i = 0; i < AdapterCount; i++)
{
// 获取物理显示适配器的标识符
D3DADAPTER_IDENTIFIER9 Identifier;
HRESULT hr = pD3D->GetAdapterIdentifier(i, 0, &Identifier);
if (FAILED(hr))
{
printf("GetAdapterIdentifier failed: %x\n", hr);
continue;
}
// 获取物理显示适配器的Description输出并打印
char* Desc = Identifier.Description;
printf("Display adapter %d Description: %s\n", i, Desc);
// 比较Description输出和目标值,如果相同,则返回真
if (strcmp(Desc, TARGET_DESC) == 0)
{
return TRUE;
}
}
// 释放IDirect3D9对象
pD3D->Release();
// 如果没有找到匹配的Description输出,则返回假
return FALSE;
}
int main()
{
// 检查物理显示适配器的Description输出是否是特定值
BOOL bFound = CheckDisplayAdapterDesc();
if (bFound)
{
printf("Display adapter Description is matched, exit\n");
// 这里可以退出程序或执行其他代码
return 0;
}
printf("Display adapter Description is not matched, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
}
以GetAdapterIdentifier函数为例:
#include <windows.h>
#include <d3d9.h>
#include <stdio.h>
// 定义要检查的Description输出
#define TARGET_DESC "VMware SVGA 3D"
// 检查物理显示适配器的Description输出是否是特定值
BOOL CheckDisplayAdapterDesc()
{
// 创建一个IDirect3D9对象
IDirect3D9* pD3D = NULL;
pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (pD3D == NULL)
{
printf("Direct3DCreate9 failed\n");
return FALSE;
}
// 获取物理显示适配器的数量
UINT AdapterCount = pD3D->GetAdapterCount();
// 遍历每个物理显示适配器
for (UINT i = 0; i < AdapterCount; i++)
{
// 获取物理显示适配器的标识符
D3DADAPTER_IDENTIFIER9 Identifier;
HRESULT hr = pD3D->GetAdapterIdentifier(i, 0, &Identifier);
if (FAILED(hr))
{
printf("GetAdapterIdentifier failed: %x\n", hr);
continue;
}
// 获取物理显示适配器的Description输出并打印
char* Desc = Identifier.Description;
printf("Display adapter %d Description: %s\n", i, Desc);
// 比较Description输出和目标值,如果相同,则返回真
if (strcmp(Desc, TARGET_DESC) == 0)
{
return TRUE;
}
}
// 释放IDirect3D9对象
pD3D->Release();
// 如果没有找到匹配的Description输出,则返回假
return FALSE;
}
int main()
{
// 检查物理显示适配器的Description输出是否是特定值
BOOL bFound = CheckDisplayAdapterDesc();
if (bFound)
{
printf("Display adapter Description is matched, exit\n");
// 这里可以退出程序或执行其他代码
return 0;
}
printf("Display adapter Description is not matched, continue\n");
// 这里插入恶意代码,比如显示一个弹窗消息
MessageBoxA(NULL, "You have been infected by a malware!", "Malware Alert", MB_OK | MB_ICONWARNING);
}