备注
原文地址:https://evasions.checkpoint.com/techniques/hardware.html
原文标题:Evasions: Hardware
更新日期:2021年5月31日
此文后期:根据自身所学进行内容扩充
因自身技术有限,只能尽自身所能翻译国外技术文章,供大家学习,若有不当或可完善的地方,希望可以指出,用于共同完善这篇文章。
目录
- 硬件信息检测方法
- 1. 检查硬盘是否有特定的名称
- 2. 检查HDD Vendor ID是否有特定值
- 3. 检查是否没有音频设备
- 4. 检查CPU温度信息是否可用
- 5. 检查物理显示适配器的IDirect3D9接口
- 识别标志
- 反制措施
硬件信息检测方法
虚拟环境模拟硬件设备,并在其描述中留下具体的痕迹--这些痕迹可以被查询,并对非主机操作系统做出结论。
1. 检查硬盘是否有特定的名称
使用的函数:
- SetupDiGetClassDevs
- SetupDiEnumDeviceInfo
- SetupDiGetDeviceRegistryProperty
代码样本:
[C++] 纯文本查看 复制代码 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, ...)
代码样本:
[C++] 纯文本查看 复制代码 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恶意软件样本中提取的,并在Joe Security的这篇博文中进行了描述。
代码样本:
[C++] 纯文本查看 复制代码 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命令):
[C++] 纯文本查看 复制代码 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
代码样本:
[C++] 纯文本查看 复制代码 #include <d3d9.h>
// [url]https://github.com/qt/qtbase/blob/dev/src/plugins/platforms/windows/qwindowsopengltester.cpp#L124[/url]
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);
}
}
这个代码样本归功于指出它的elsamuko。
常规主机上的输出示例如下:
[C++] 纯文本查看 复制代码 VendorId: 0x10de
DeviceId: 0x103c
Driver: nvldumdx.dll
Description: NVIDIA Quadro K5200
而这里是一个在虚拟机(VMware)上输出的例子:
[C++] 纯文本查看 复制代码 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相关,并替换返回值。
|