WMI

描述

Windows 管理接口 (WMI) 查询是获取操作系统和硬件信息的另一种方法。WMI 使用 COM 接口及其方法。

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;
}
使用PowerShell查询:
(Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber).SerialNumber

2.使用WMI逃避跟踪

WMI 提供了一种创建新进程和安排任务的方法。沙箱通常使用CreateProcessInternalW函数挂钩来跟踪子进程。但是当使用 WMI 创建进程时,父进程中不会调用函数CreateProcessInternalW 。因此,使用 WMI 创建的进程可能不会被沙箱跟踪,并且它们的行为也不会被记录。
以使用 WMI 启动进程为例:
// 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);
以通过 WMI 使用任务计划程序启动进程 为例(Windows 7):
#使用“ Win32_ScheduledJob ”类和“ Create ”方法通过WMI创建新任务。然而,“ Win32_ScheduledJob ”WMI 类被设计为与 AT 命令一起使用,该命令自 Windows 8 起已被弃用。
#在 Windows 8 及更高版本中,如果注册表项“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Schedule\Configuration ”具有REG_DWORD类型的值“ EnableAt ”=”1”,则只能使用 WMI 创建计划任务。因此,这种技术不太可能在野外被发现。
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") 

3.查看上次开机时间

如果从快照还原 VM 后立即查询上次启动时间,则 WMI 数据库可能包含创建 VM 快照时保存的值。如果快照是一年前创建的,即使沙箱更新了上次启动时间,计算出的系统正常运行时间也将是一年。
通过该方法可用于检测从快照恢复的虚拟机。此外,上次启动时间中的任何异常都可以用作沙箱指标:
系统正常运行时间太大(数月甚至数年)
系统正常运行时间太短(不到几分钟)
使用其他方法获取(可以参考“定时”)的上次启动时间与使用WMI获取的上次启动时间不同
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

4.检查网络适配器上次重置时间

检查是否有任何适配器的上次重置时间。如果时间过久可能表明应用程序正在从快照恢复的虚拟机中运行。
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