飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2767|回复: 4

[病毒分析] [翻译]规避技术: WMI

  [复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2021-6-3 11:51:54 | 显示全部楼层 |阅读模式
    备注
    原文地址: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. 通过接口实例连接到特定的服务,其功能如下。
    • 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温度信息是否可用

    代码样本:
    [Visual Basic] 纯文本查看 复制代码
    /*
    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):
    [Visual Basic] 纯文本查看 复制代码
    (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
    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 "方法来创建一个新的进程。
    代码样本:
    [Visual Basic] 纯文本查看 复制代码
    // 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)
    [Visual Basic] 纯文本查看 复制代码
    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):
    [Visual Basic] 纯文本查看 复制代码
    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):
    [Visual Basic] 纯文本查看 复制代码
    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 "服务

    反制措施
    反措施在上述适当的分节中提出。
    归功于


    评分

    参与人数 1威望 +1 飘云币 +1 收起 理由
    zhczf + 1 + 1 PYG有你更精彩!

    查看全部评分

    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    6 小时前
  • 签到天数: 112 天

    [LV.6]常住居民II

    发表于 2021-6-3 12:43:56 | 显示全部楼层
    PYG有你更精彩!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2023-5-13 23:22
  • 签到天数: 853 天

    [LV.10]以坛为家III

    发表于 2021-6-3 22:19:56 | 显示全部楼层
    感谢楼主分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    3 天前
  • 签到天数: 1364 天

    [LV.10]以坛为家III

    发表于 2021-6-5 08:56:16 | 显示全部楼层
    感谢楼主分享!!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2023-11-13 18:32
  • 签到天数: 325 天

    [LV.8]以坛为家I

    发表于 2021-6-12 21:35:20 | 显示全部楼层
    感谢楼主分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表