目录
WMI检测方法
背景介绍
1. 通用的WMI查询
2. 利用WMI逃避追踪
2.1. 使用WMI启动程序
2.2. 通过WMI使用任务计划程序启动进程
3. 检查最后的启动时间
4. 检查网络适配器的最后重置时间
识别标志
反制措施
归功于
WMI检测方法
Windows管理接口(WMI)查询是获得操作系统和硬件信息的另一种方式。WMI使用COM接口和它们的方法。
背景介绍
标准COM函数被用来处理查询。它们的调用顺序如下所述,可分为6个步骤。
1. COM的初始化。
-
CoInitialize/CoInitializeEx
2. 创建所需的接口实例。
-
创建接口实例:CoCreateInstance/CoCreateInstanceEx
3. 通过接口实例连接到特定的服务,其功能如下。
-
ConnectServer
4. 用这些函数获取服务的方法并设置其参数。
-
Method (to get methods)
-
Put (to set arguments)
5. 从服务中检索信息,并用下面的函数执行服务的方法。左边的函数是右边的函数的代理–这些函数在内部被调用。
-
ExecQuery -> IWbemServices_ExecQuery (检索信息)
-
ExecMethod -> IWbemServices_ExecMethod (执行方法)
-
ExecMethodAsync -> IWbemServices_ExecMethodAsync (执行方法)
6. 用以下函数检查查询的结果。
-
[enumerator]->Next
-
[object]->Get
要想了解所描述的理论是如何应用于实践的,请查看下面的例子。
1. 通用的WMI查询
由于WMI提供了另一种收集系统信息的方式,它可以被用来执行其他文章中描述的规避技术,例如:
-
检查处理器数量是否不足
-
检查硬盘大小是否小
-
检查MAC地址是否特定
-
检查CPU温度信息是否可用
代码样本:
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
/* Check number of cores using WMI */ BOOL number_cores_wmi() { IWbemServices *pSvc = NULL; IWbemLocator *pLoc = NULL; IEnumWbemClassObject *pEnumerator = NULL; BOOL bStatus = FALSE; HRESULT hRes; BOOL bFound = FALSE; // Init WMI bStatus = InitWMI(&pSvc, &pLoc); if (bStatus) { // If success, execute the desired query bStatus = ExecWMIQuery(&pSvc, &pLoc, &pEnumerator, _T( "SELECT * FROM Win32_Processor" )); if (bStatus) { // Get the data from the query IWbemClassObject *pclsObj = NULL; ULONG uReturn = 0; VARIANT vtProp; // Iterate over our enumator while (pEnumerator) { hRes = pEnumerator-> Next (WBEM_INFINITE, 1, &pclsObj, &uReturn); if (0 == uReturn) break; // Get the value of the Name property hRes = pclsObj-> Get (_T( "NumberOfCores" ), 0, &vtProp, 0, 0); if (V_VT(&vtProp) != VT_NULL) { // Do our comparaison if (vtProp.uintVal < 2) { bFound = TRUE; break; } // release the current result object VariantClear(&vtProp); pclsObj->Release(); } } // Cleanup pEnumerator->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); } } return bFound; } /* Check hard disk size using WMI */ BOOL disk_size_wmi() { IWbemServices *pSvc = NULL; IWbemLocator *pLoc = NULL; IEnumWbemClassObject *pEnumerator = NULL; BOOL bStatus = FALSE; HRESULT hRes; BOOL bFound = FALSE; INT64 minHardDiskSize = (80LL * (1024LL * (1024LL * (1024LL)))); // Init WMI bStatus = InitWMI(&pSvc, &pLoc); if (bStatus) { // If success, execute the desired query bStatus = ExecWMIQuery(&pSvc, &pLoc, &pEnumerator, _T( "SELECT * FROM Win32_LogicalDisk" )); if (bStatus) { // Get the data from the query IWbemClassObject *pclsObj = NULL; ULONG uReturn = 0; VARIANT vtProp; // Iterate over our enumator while (pEnumerator) { hRes = pEnumerator-> Next (WBEM_INFINITE, 1, &pclsObj, &uReturn); if (0 == uReturn) break; // Get the value of the Name property hRes = pclsObj-> Get (_T( "Size" ), 0, &vtProp, 0, 0); if (V_VT(&vtProp) != VT_NULL) { // Do our comparaison if (vtProp.llVal < minHardDiskSize) { // Less than 80GB bFound = TRUE; break; } // release the current result object VariantClear(&vtProp); pclsObj->Release(); } } // Cleanup pEnumerator->Release(); pSvc->Release(); pLoc->Release(); CoUninitialize(); } } return bFound; } |
代码样本(PowerShell):
1
|
( Get -CimInstance -ClassName Win32_BIOS - Property SerialNumber).SerialNumber |
识别标志:
如果下面的函数包含来自表列 “
Query
“的第3个参数:
-
IWbemServices_ExecQuery(…, query, …)
则表明该应用程序试图使用规避技术。
检查表:
以下WMI查询可用于检测虚拟环境: |
||||
Query查询方式 |
Field字段 |
Value值 |
Detect检测 |
Comments注释 |
SELECT * FROM Win32_Processor |
NumberOfCores |
< 2 |
[general] |
|
ProcessorId |
[empty] |
|||
SELECT * FROM Win32_LogicalDisk |
Size |
< 60GB |
||
SELECT * FROM Win32_BaseBoard |
SerialNumber |
None |
||
Version |
None |
|||
SELECT * FROM MSAcpi_ThermalZoneTemperature |
CurrentTemperature |
“Not supported” |
||
SELECT * FROM Win32_PnPEntity |
DeviceId |
PCI\VEN_80EE&DEV_CAFE |
VirtualBox |
|
IDE\CDROOMVBOX | ||||
IDE\DISKVBOX* | ||||
VEN_VMWARE |
VMware |
|||
PROD_VMWARE_VIRTUAL | ||||
SELECT * FROM Win32_NetworkAdapterConfiguration |
MACAddress |
08:00:27 |
VirtualBox |
See “Check if MAC address is specific” section in “Network” chapter |
00:1C:42 |
Parallels |
|||
00:05:69 |
VMware |
|||
00:0C:29 | ||||
00:1C:14 | ||||
00:50:56 | ||||
00:16:E3 |
XEN |
|||
SELECT * FROM Win32_Bios |
Serial Number |
VMware- |
VMware |
|
0 |
VirtualBox |
|||
Version |
INTEL – 6040000 |
VMware |
See “SystemBiosVersion” in “Check if particular registry keys contain specified strings” section in “Registry” chapter |
|
BOCHS |
BOCHS |
|||
PARALLELS |
Parallels |
|||
QEMU |
QEMU |
|||
VBOX |
VirtualBox |
|||
SELECT * FROM Win32_ComputerSystem |
Model |
VMware |
VMware |
|
VirtualBox |
VirtualBox |
|||
Manufacturer |
VMware |
VMware |
||
innotek GmbH |
VirtualBox |
|||
SELECT * FROM Win32_VideoController |
AdapterCompatibility |
VMware |
VMware |
|
Oracle Corporation |
VirtualBox |
|||
Caption |
VMware |
VMware |
||
VirtualBox |
VirtualBox |
|||
Description |
VMware |
VMware |
||
VirtualBox |
VirtualBox |
|||
Name |
VMware |
VMware |
||
VirtualBox |
VirtualBox |
|||
SELECT * FROM Win32_PointingDevice |
Description |
VMware |
VMware |
表中所列的查询并不是唯一可能的,提出这些查询是为了让人们了解它们是如何工作的,以及用这些调用可以检索到什么信息
反制措施:
反制措施取决于通过WMI方法实现的特定检查,它们与相关文章中描述的相应方法相同。此外,你必须重新启动 “winmgmt “服务。
2. 利用WMI逃避追踪
WMI提供了一种创建新进程和安排任务的方法。沙盒通常使用CreateProcessInternalW函数挂钩来跟踪子进程。然而,当你使用WMI创建进程时,函数CreateProcessInternalW不会在父进程中被调用。因此,使用WMI创建的进程可能不会被沙盒跟踪,其行为也不会被记录。
2.1. 使用WMI启动程序
你可以通过WMI使用 “Win32_Process “类的 “Create “方法来创建一个新的进程。
代码样本:
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
|
// Initialize COM CoInitializeEx(NULL, COINIT_MULTITHREADED); // Set general COM security levels hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); if (FAILED(hres) && hres != RPC_E_TOO_LATE) break; // create an instance of WbemLocator CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbemLocator); wbemLocator->ConnectServer(CComBSTR( "ROOT\\CIMV2" ), NULL, NULL, NULL, 0, NULL, NULL, &wbemServices); // get Win32_Process object wbemServices->GetObject(CComBSTR( "Win32_Process" ), 0, NULL, &oWin32Process, &callResult); wbemServices->GetObject(CComBSTR( "Win32_ProcessStartup" ), 0, NULL, &oWin32ProcessStartup, &callResult); oWin32Process->GetMethod(CComBSTR( "Create" ), 0, &oMethCreate, &oMethCreateSignature); oMethCreate->SpawnInstance(0, &instWin32Process); oWin32ProcessStartup->SpawnInstance(0, &instWin32ProcessStartup); // set startup information for process instWin32ProcessStartup->Put(CComBSTR( "CreateFlags" ), 0, &varCreateFlags, 0); instWin32Process->Put(CComBSTR( "CommandLine" ), 0, &varCmdLine, 0); instWin32Process->Put(CComBSTR( "CurrentDirectory" ), 0, &varCurDir, 0); CComVariant varStartupInfo(instWin32ProcessStartup); instWin32Process->Put(CComBSTR( "ProcessStartupInformation" ), 0, &varStartupInfo, 0); wbemServices->ExecMethod(CComBSTR( "Win32_Process" ), CComBSTR( "Create" ), 0, NULL, instWin32Process, &pOutParams, &callResult); |
识别标志:
如果用第2个参数 “Win32_Process “和第3个参数 “Create “调用以下函数之一:
-
IWbemServices_ExecMethod(…, BSTR(“Win32_Process”), BSTR(“Create”), …)
-
IWbemServices_ExecMethodAsync(…, BSTR(“Win32_Process”), BSTR(“Create”), …)
那么它就表明该应用程序试图使用规避技术。
反制措施:
如果你使用内核模式的监控器,用PsSetCreateProcessNotifyRoutineEx拦截目标函数或注册进程创建时的回调。
2.2. 通过WMI使用任务计划程序启动进程(Windows 7)
该技术与 “定时 “一章中的 “使用任务计划程序推迟执行 “一节中描述的基本相同。WMI只是提供了另一种安排任务的方式。
你可以通过WMI使用 “Win32_ScheduledJob “类中的 “Create “方法创建一个新的任务。
然而,”Win32_ScheduledJob “WMI类被设计为与AT命令一起使用,而AT命令从Windows 8开始被废弃。
在Windows 8和更高版本中,只有当注册表键 “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\Configuration “有一个REG_DWORD类型的值 “EnableAt”=”1″,你才能用WMI创建预定工作。因此,这种技术不太可能在“正常环境下”成功使用。
代码样本(VB)
1
2
3
4
5
6
|
strComputer = "." Set objWMIService = GetObject( "winmgmts:" & "{impersonationLevel=Impersonate}!\" & strComputer & " \root\cimv2") Set objSWbemDateTime = CreateObject( "WbemScripting.SWbemDateTime" ) objSWbemDateTime.SetVarDate(DateAdd( "n" , 1, Now())) Set objNewJob = objWMIService. Get ( "Win32_ScheduledJob" ) errJobCreate = objNewJob.Create( "malware.exe" , objSWbemDateTime.Value, False , , , True , "MaliciousJob" ) |
识别标志:
如果用第2个参数 “Win32_ScheduledJob “和第3个参数 “Create “调用以下函数之一:
-
IWbemServices_ExecMethod(…, BSTR(“Win32_ScheduledJob”), BSTR(“Create”), …)
-
IWbemServices_ExecMethodAsync(…, BSTR(“Win32_ScheduledJob”), BSTR(“Create”), …)
则表明该应用程序试图使用规避技术。
反制措施:
使用内核模式的监控器,用PsSetCreateProcessNotifyRoutineEx注册进程创建时的回调。
3. 检查最后的启动时间
如果在从快照恢复虚拟机后立即查询最后启动时间,WMI 数据库可能包含创建虚拟机快照时保存的值。如果快照是一年前创建的,即使沙盒更新了最后的启动时间,计算出的系统正常运行时间也是一年。
这一事实可以用来检测从快照中恢复的虚拟机。另外,最后一次启动时间的任何异常情况都可以作为沙盒指标:
-
系统正常运行时间太长(几个月甚至几年)。
-
系统正常运行时间太短(少于几分钟)。
-
使用其它方法获得的最后一次启动时间与使用WMI获得的最后一次启动时间不同
代码样本 (VB):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
strComputer = "." Set objWMIService = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\" & strComputer & " \root\cimv2") Set colOperatingSystems = objWMIService.ExecQuery ( "Select * from Win32_OperatingSystem" ) For Each objOS in colOperatingSystems dtmBootup = objOS.LastBootUpTime dtmLastBootUpTime = WMIDateStringToDate(dtmBootup) dtmSystemUptime = DateDiff( "n" , dtmLastBootUpTime, Now) Wscript.Echo "System uptime minutes: " & dtmSystemUptime Next Function WMIDateStringToDate(dtm) WMIDateStringToDate = CDate (Mid(dtm, 5, 2) & "/" & _ Mid(dtm, 7, 2) & "/" & Left(dtm, 4) & " " & Mid (dtm, 9, 2) & ":" & _ Mid(dtm, 11, 2) & ":" & Mid(dtm, 13, 2)) End Function |
代码样本取自微软文档
识别标志:
如果用第3个参数BSTR(“Win32_OperatingSystem”)调用以下函数:
-
IWbemServices_ExecQuery(…, BSTR(“Win32_OperatingSystem”), …)
那么它可能是应用程序试图使用规避技术的一个指标。
反制措施:
-
调整KeBootTime值
-
在调整KeBootTime值后,重置WMI存储库或重新启动 “winmgmt “服务
4. 检查网络适配器的最后重置时间
我们需要检查是否有任何适配器在很久以前被重置过。这可能表明应用程序是在一个从快照恢复的虚拟机中运行。
代码样本 (VB):
1
2
3
4
5
6
7
8
9
10
|
strComputer = "." Set objWMIService = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\" & strComputer & " \root\cimv2") Set colOperatingSystems = objWMIService.ExecQuery ( "Select * from Win32_NetworkAdapter" ) For Each objOS in colNetworkAdapters dtmLastReset = objOS.TimeOfLastReset dtmLastResetTime = WMIDateStringToDate(dtmLastReset) 'WMIDateStringToDate function from the previous example dtmAdapterUptime = DateDiff( "n" , dtmLastResetTime, Now) Wscript.Echo "Adapter uptime minutes: " & dtmAdapterUptime Next |
识别标志:
如果用第3个参数BSTR(“Win32_OperatingSystem”)调用以下函数:
-
IWbemServices_ExecQuery(…, BSTR(“Win32_NetworkAdapter”), …)
那么它可能是应用程序试图使用规避技术的一个指标。
反制措施:
-
确保网络适配器有足够的最后重置时间
-
重置WMI资源库或重启 “winmgmt “服务
暂无评论内容