-
硬件信息检测方法
-
1. 检查硬盘是否有特定的名称
-
2. 检查HDD Vendor ID是否有特定值
-
3. 检查是否没有音频设备
-
4. 检查CPU温度信息是否可用
-
5. 检查物理显示适配器的IDirect3D9接口
-
识别标志
-
反制措施
硬件信息检测方法
虚拟环境模拟硬件设备,并在其描述中留下具体的痕迹–这些痕迹可以被查询,并对非主机操作系统做出结论。
1. 检查硬盘是否有特定的名称
使用的函数:
-
SetupDiGetClassDevs
-
SetupDiEnumDeviceInfo
-
SetupDiGetDeviceRegistryProperty
代码样本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
hDevs = SetupDiGetClassDevs( &guid, // GUID_DEVCLASS(DEVINTERFACE)_DISKDRIVE NULL, NULL, DIGCF_PRESENT); SetupDiEnumDeviceInfo( hDevsInfo, 0, &devinfo); // PSP_DEVINFO_DATA SetupDiGetDeviceRegistryProperty( hDevs, &devinfo, SPDRP_FRIENDLYNAME, &dword_1, szFriendlyName, // HDD name will be here dFriendlyNameSize, &dword_2); |
检测表:
检查硬盘驱动器是否有以下名称之一: |
|
检测 |
名称 |
QEMU |
QEMU |
VirtualBox |
VBOX |
VirtualPC |
VIRTUAL HD |
VMware |
VMware |
2. 检查HDD Vendor ID是否有特定值
使用了以下函数:
-
DeviceIoControl(…, IOCTL_STORAGE_QUERY_PROPERTY, …)
代码样本:
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
|
bool GetHDDVendorId(std::string& outVendorId) { HANDLE hDevice = CreateFileA(_T( "\\\\.\\PhysicalDrive0" ), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hDevice == INVALID_HANDLE_VALUE) return false ; STORAGE_PROPERTY_QUERY storage_property_query = {}; storage_property_query.PropertyId = StorageDeviceProperty; storage_property_query.QueryType = PropertyStandardQuery; STORAGE_DESCRIPTOR_HEADER storage_descriptor_header = {}; DWORD BytesReturned = 0; if (!DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &storage_property_query, sizeof (storage_property_query), &storage_descriptor_header, sizeof (storage_descriptor_header), &BytesReturned, )) { printf ( "DeviceIoControl() for size query failed\n" ); CloseHandle(hDevice); return false ; } if (!BytesReturned) { CloseHandle(hDevice); return false ; } std::vector< char > buff(storage_descriptor_header.Size); //_STORAGE_DEVICE_DESCRIPTOR if (!DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &storage_property_query, sizeof (storage_property_query), buff.data(), buff.size(), 0)) { CloseHandle(hDevice); return false ; } CloseHandle(hDevice); if (BytesReturned) { STORAGE_DEVICE_DESCRIPTOR* device_descriptor = (STORAGE_DEVICE_DESCRIPTOR*)buff.data(); if (device_descriptor->VendorIdOffset) outVendorId = &buff[device_descriptor->VendorIdOffset]; return true ; } return false ; } |
检测表:
检查硬盘供应商ID是否为以下之一: |
|
检测 |
名称 |
VirtualBox |
VBOX |
VMware |
vmware |
3. 检查是否没有音频设备
这项技术是从TeslaCrypt恶意软件样本中提取的
代码样本:
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
|
void AudioEvasion() { PCWSTR wszfilterName = L "audio_device_random_name" ; if (FAILED(CoInitialize(NULL))) return ; IGraphBuilder *pGraph = nullptr; if (FAILED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, ( void **)&pGraph))) return ; if (E_POINTER != pGraph->AddFilter(NULL, wszfilterName)) ExitProcess(-1); IBaseFilter *pBaseFilter = nullptr; CoCreateInstance(CLSID_AudioRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, ( void **)&pBaseFilter); pGraph->AddFilter(pBaseFilter, wszfilterName); IBaseFilter *pBaseFilter2 = nullptr; pGraph->FindFilterByName(wszfilterName, &pBaseFilter2); if (nullptr == pBaseFilter2) ExitProcess(1); FILTER_INFO info = { 0 }; pBaseFilter2->QueryFilterInfo(&info); if (0 != wcscmp(info.achName, wszfilterName)) return ; IReferenceClock *pClock = nullptr; if (0 != pBaseFilter2->GetSyncSource(&pClock)) return ; if (0 != pClock) return ; CLSID clsID = { 0 }; pBaseFilter2->GetClassID(&clsID); if (clsID.Data1 == 0) ExitProcess(1); if (nullptr == pBaseFilter2) ExitProcess(-1); IEnumPins *pEnum = nullptr; if (0 != pBaseFilter2->EnumPins(&pEnum)) ExitProcess(-1); if (0 == pBaseFilter2->AddRef()) ExitProcess(-1); } |
4. 检查CPU温度信息是否可用
这项技术是从GravityRAT恶意软件中提取的
代码样本(Windows cmd命令):
1
|
wmic /namespace :\\root\WMI path MSAcpi_ThermalZoneTemperature get CurrentTemperature |
5. 检查物理显示适配器的IDirect3D9接口
该方法检查IDirect3D9接口实例化时系统中存在的物理显示适配器。它适用于从Windows XP开始的所有Windows版本。
使用的函数:
-
Direct3DCreate9 – called from `d3d9.dll` library
-
GetAdapterIdentifier – called via IDirect3D9 interface
代码样本:
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
|
#include <d3d9.h> // https://github.com/qt/qtbase/blob/dev/src/plugins/platforms/windows/qwindowsopengltester.cpp#L124 void detect() { typedef IDirect3D9* (WINAPI* PtrDirect3DCreate9)( UINT ); HMODULE d3d9lib = ::LoadLibraryA( "d3d9" ); if (!d3d9lib) return ; PtrDirect3DCreate9 direct3DCreate9 = (PtrDirect3DCreate9)GetProcAddress(d3d9lib, "Direct3DCreate9" ); if (!direct3DCreate9) return ; IDirect3D9* direct3D9 = direct3DCreate9(D3D_SDK_VERSION); if (!direct3D9) return ; D3DADAPTER_IDENTIFIER9 adapterIdentifier; const HRESULT hr = direct3D9->GetAdapterIdentifier(0, 0, &adapterIdentifier); direct3D9->Release(); if (SUCCEEDED(hr)) { printf ( "VendorId: 0x%x\n" , adapterIdentifier.VendorId); printf ( "DeviceId: 0x%x\n" , adapterIdentifier.DeviceId); printf ( "Driver: %s\n" , adapterIdentifier.Driver); printf ( "Description: %s\n" , adapterIdentifier.Description); } } |
常规主机上的输出示例如下:
1
2
3
4
|
VendorId: 0x10de DeviceId: 0x103c Driver: nvldumdx.dll Description: NVIDIA Quadro K5200 |
而这里是一个在虚拟机(VMware)上输出的例子:
1
2
3
4
|
VendorId: 0x15ad DeviceId: 0x405 Driver: vm3dum64_loader.dll Description: VMware SVGA 3D |
检查的字段以D3DADAPTER_IDENTIFIER9结构的相应字段命名。恶意软件可以将这些字段中的值与已知存在于虚拟机中的值进行比较,如果发现匹配,则得出结论,它是在虚拟机下运行。
检测表:
检查D3DADAPTER_IDENTIFIER9结构的字段中是否存在以下值: | |||
检测 |
结构字段 |
值 |
注释 |
VMware |
VendorId | 0x15AD | |
DeviceId | 0x405 | Only when used in combination with VendorId related to VMware (0x15AD) | |
Driver | vm3dum.dll | ||
Driver | vm3dum64_loader.dll | ||
Description | VMware SVGA 3D |
识别标志
识别标志对每种技术都是通用的:拦截使用的函数,并跟踪它是否被调用。例如,很难说出为什么应用程序要获取硬盘名称。这并不一定意味着应用了规避技术。所以在这种情况下,最好的办法就是拦截目标函数并跟踪其调用。
反制措施
-
对比硬盘检查:重命名硬盘,使其不会被特定字符串检测到;
-
对照音频设备检查:添加音频设备;
-
对比CPU温度检查:将存根添加到虚拟机管理程序(hyperviso)以输出一些有意义的信息;
-
与物理显示适配器检查相比:在d3d9.dll中的函数GetAdapterIdentifier上设置挂钩,检查查询的适配器是否与DirectX相关,并替换返回值。
暂无评论内容