Evasions: Hardware
Contents
Hardware info detection methods
1. Check if HDD has specific name
2. Check if HDD Vendor ID has specific value
3. Check if audio device is absent
4. Check if CPU temperature information if available
5. Check physical display adapter for IDirect3D9 interface
Signature recommendations
Countermeasures
Hardware info detection methods
Virtual environments emulate hardware devices and leave specific traces in their descriptions - which may be queried and the conclusion about non-host OS made.
1. Check if HDD has specific name
Functions used:
- SetupDiGetClassDevs
- SetupDiEnumDeviceInfo
- SetupDiGetDeviceRegistryProperty
Code sample
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);
Detections table
Check if hard disk drive has one of the following names: | |
Detect | Name |
---|---|
QEMU | QEMU |
VirtualBox | VBOX |
VirtualPC | VIRTUAL HD |
VMware | VMware |
2. Check if HDD Vendor ID has specific value
The following function is used:
- DeviceIoControl(..., IOCTL_STORAGE_QUERY_PROPERTY, ...)
Code sample
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;
}
Detections table
Check if HDD Vendor ID is one of the following: | |
Detect | Name |
---|---|
VirtualBox | VBOX |
VMware | vmware |
3. Check if audio device is absent
This technique was extracted from TeslaCrypt malware sample and was described in this Joe Security blog post.
Code sample
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. Check if CPU temperature information is available
This technique was extracted from GravityRAT malware and is described by this link.
Code sample (Windows cmd command)
wmic /namespace:\\root\WMI path MSAcpi_ThermalZoneTemperature get CurrentTemperature
5. Check physical display adapter for IDirect3D9 interface
This method checks physical display adapters present in the system when the IDirect3D9 interface was instantiated. It works on all Windows versions starting from Windows XP.
Functions used:
- Direct3DCreate9 - called from `d3d9.dll` library
- GetAdapterIdentifier - called via IDirect3D9 interface
Code sample
#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);
}
}
Credits for this code sample go to elsamuko who pointed it out.
Example of output on a usual host machine is provided below:
VendorId: 0x10de
DeviceId: 0x103c
Driver: nvldumdx.dll
Description: NVIDIA Quadro K5200
And here is an example of output on a virtual machine (VMware):
VendorId: 0x15ad
DeviceId: 0x405
Driver: vm3dum64_loader.dll
Description: VMware SVGA 3D
Examined fields are named after the corresponding fields of D3DADAPTER_IDENTIFIER9 structure. Malware can compare values in these fields to the ones which are known to be present inside the virtual machine and if match is found, then it draws the conclusion that it’s run under virtual machine.
Detections table
Check if the following values are present in the fields of D3DADAPTER_IDENTIFIER9 structure: | |||
Detect | Structure field | Value | Comment |
---|---|---|---|
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 |
Signature recommendations
Signature recommendations are general for each technique: hook the function used and track if it is called. It’s pretty hard to tell why application wants to get HDD name, for example. It doesn’t necessarily mean applying evasion technique. So the best what can be done in this situation is intercepting target functions and tracking their calls.
Countermeasures
- versus HDD checks: rename HDD so that it's not detected by specific strings;
- versus audio device check: add audio device;
- versus CPU temperature check: add stub to hypervisor to output some meaningful information;
- versus physical display adapter check: set up hook on a function GetAdapterIdentifier from d3d9.dll, check if the queried adapter is related to DirectX and replace return values.