| 
 
TA的每日心情|  | 开心 2022-1-9 18:41
 | 
|---|
 签到天数: 5 天 [LV.2]偶尔看看I | 
 
| 备注 原文地址:https://evasions.checkpoint.com/techniques/wmi.html
 原文标题:Evasions: WMI
 更新日期:2021年6月3日
 此文后期:根据自身所学进行内容扩充
 因自身技术有限,只能尽自身所能翻译国外技术文章,供大家学习,若有不当或可完善的地方,希望可以指出,用于共同完善这篇文章。
 
 
  
 目录
 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. 通过接口实例连接到特定的服务,其功能如下。
 
 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温度信息是否可用
 代码样本:
 
 复制代码/*
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;
}
该代码样本的作者:al-khaser项目
 代码样本(PowerShell):
 
 复制代码(Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber).SerialNumber
识别标志:
 如果下面的函数包含来自表列 "
 Query"的第3个参数: 
 IWbemServices_ExecQuery(..., query, ...)
 则表明该应用程序试图使用规避技术。
 检查表:
 [tr][/tr]
 
 | 以下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 |  |  | 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 |  |  | 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 "方法来创建一个新的进程。
 代码样本:
 
 复制代码// 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);
代码样本取自InviZzzible工具
 识别标志:
 如果用第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)
 
 复制代码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):
 
 复制代码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):
 
 复制代码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 "服务
 反制措施
 反措施在上述适当的分节中提出。
 归功于
 
 
 
 | 
 |