殺軟淺析
由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,雷神眾測及文章作者不為此承擔任何責任。
雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經雷神眾測允許,不得任意修改或者增減此文章內容,不得以任何方式將其用于商業目的。
NO.1 概述
這次和大家一起淺析常見殺軟。有什么不足之處還請師傅們指出,謝謝大家。
NO.2 殺軟常見查殺技術
? 靜態查殺:主要基于hash和特征碼,hash可以是文件的hash或導入表之類的hash,特征碼可以是PE頭、pdb、全局字符串、互斥體之類的信息。
? 動態查殺:基于API的監控和沙箱執行,殺軟會通過對ntdll的關鍵API進行hook,實現對程序的API監控。另外可以在內核中注冊一系列的回調函數實現對行為的監控。
? 啟發式:就是一套加減分的規則,用于檢測程序的潛在惡意行為,如程序中有操作端口和通訊的函數,并將自身加載到啟動項中等上述行為,則很有可能被判定為惡意。
NO.3 殺軟行為淺析
依據下圖,可見殺軟已經在system進程中加載了不同功能的驅動:

我們可以簡單瞅瞅里面的驅動,先以360FsFlt.sys為例:
根據導入表中的回調函數可見,該驅動對進程、線程、模塊、對象及注冊表均進行了相應的監控操作


然后根據一系列Flt系列的函數,可見該驅動是Minifilter文件監控:

其中FltRegisterFilter()是用來注冊為過濾器的(注意第二個參數是一個微過濾器注冊結構體),然后通過FltCreateCommonicationProt()注冊通訊端口與用戶態通訊,最后調用FltStartFiltering()開始過濾操作:


微過濾器注冊結構體,注意其第五個屬性Operation Registion,為文件操作的回調函數注冊的地方。

我們再往后看,像比較敏感的explorer、wscript等程序運行時也會掛載相應的dll:


當我們的文件落盤后,360的托盤程序也會拉起:


我們自身的程序在雙擊運行后,360的托盤程序也同樣會拉起:

對我們所運行的程序進行一系列文件相關的操作:

我們可以觀察其調用堆棧,由此可以判斷出每次createFile是由那個dll拉起的:


同樣我們可以使用Autorun 過濾關鍵字得知360在注冊表哪些地方做了持久化:
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run:

HKLM\System\CurrentControlSet\Services:

HKLM\System\CurrentControlSet\Services:

Ntdll HOOK
Edr通常會hook住ntdll,是程序后續的操作走入edr的流程,下面在edr中是被hook住的函數:

下面圖片中紅色框中的是正常的NtWriteVirtualMemey()流程,而在下方的NtWriteVirtualMemory()已經被hook住了 jmp指令跳轉到了其他的流程。

內核回調:
內核回調是殺軟檢測出敏感行為的一個重要手段,常用的由進程監控、線程監控、模塊監控、對象監控、文件的過濾器、網絡監控等等,如下圖所示。

NO.4 應對手段
4.1 花指令
花指令本質上是一段可有可無的代碼,插入花指令后會使反匯編器出錯,但不影響程序的實際執行。如下圖,用xor/cmp/jz/jnz方式迷惑了x32dbg,使其不能正確顯示出call eax:


4.2 特征碼定位
特征碼定位是比較經典的技術了,主要用于靜態文件查殺的對抗,常用的工具有myccl、virtest等,其工具原理在保留pe格式下不斷抹去其中的數據(逐塊暴露),最終得到一個免殺的文件,而被抹去的數據就是相應的特征碼。同一個樣本在不同殺軟下定位出來的特征碼是有很大差別的,特征碼可以在數據段、代碼段、導入表、重定位表等地方出現,下面分別以cs生成的bin在wd和火絨作為例子:
在wd環境下定位出3處特征,兩處在代碼段一處在重定位表中,代碼段第一處為FF 15call 調用了writeProcessMemory


第二處是在sub_10009708函數中,其中dword_10039888這個全局變量為被異或后的配置信息:

第三處特征碼在LoadConfigurationDirectory載入配置表中:

在火絨下所定位到的特征,在data段和rdata。

4.3 混淆
混淆包含常見的字符串混淆和控制流混淆等,其中控制流混淆又分為控制流平坦化、虛假控制流和指令替換。常見控制流平坦化,就是在不改變源代碼的功能前提下,將C或C++代碼中的if、while、for、do等控制語句轉換成switch分支語句。如下圖所示:

由上圖可見左圖的單一循環,在控制流平坦化后分成多個case代碼塊和一個入口塊。前驅模塊(case 2)主要是進行基本塊的分發,分發通過改變switch變量來實現。后繼模塊(case3)也可用于更新switch變量的值,并跳轉到switch開始處。
項目參考:
https://github.com/obfuscator-llvm/obfuscator/tree/llvm-4.0
4.4 替換敏感的API
通常我們會使用CreateThread去執行shellcode,目前我們可以利用某些函數中的callback填入需要執行的shellcode地址,利用其去執行shellcode。如SetTimer就是這種API函數,其位于user32.dll中,函數原型為:
UINT_PTR SetTimer( HWND hWnd, // 窗口句柄 UINT_PTR nIDEvent, // 定時器ID,多個定時器時,可以通過該ID判斷是哪個定時器 UINT uElapse, // 時間間隔,單位為毫秒 TIMERPROC lpTimerFunc // 回調函數);
我們可以在第四個參數(即回調函數)中填入shellcode地址:

更多的執行方式可以參考這個項目:
https://github.com/S4R1N/AlternativeShellcodeExec
同樣復制shellcode到內存中的操作可以使用不同的API,如LdapUTF8ToUnicode、UuidFromStringA,或者使用掛在pe節,使用系統對其自行加載,我們再執行。
4.5 Syscall對抗ntdll的hook
因為ntdll.dll是普通應用程序從3環進0環的必經之路,而通過hook ntdll中的敏感函數可以使得改程序的后續流程走到殺軟程序,從而對其后續行為做相應的檢測,常用的syscall項目有HellsGate、syswhipers。當程序使用syscall就像紅色的箭頭,直接到達syscall table,繞過了被hook所圈起來的ntdll。

4.6 分離加載對抗沙箱
分離加載(Installer、Code、Loader)的方式,這種三端分離的方式能更好的反沙箱,因為通常情況下只會上傳Loader進沙箱,而Code是可以在偽裝成bmp圖片后另外存放的,Install將加密后的Core隱藏在注冊表、UUID、WMI中,最后Loader在相應空間提取出Core后,再利用保存在自身中的Key將其解密,最后內存加載執行加載。
4.7 執行敏感行為后的操作
在執行CreateProcess(啟動進程)\CreateRemoteThread(遠程注入)或一些網絡行為后,是我們需要對其進行處理的。我們通過openProcess打開其他線程后,再通過VirtualAllocEx、WriteProcessMemory寫入相應的shellcode后,需要使用VirtualProtectEx將其內存屬性設置為PAGE_NOACCESS(而殺軟通常是不會掃描此屬性的內存)。當在CreateRemoteThread創建注入時會觸發相應的檢測機制,所以我們在CreateRemoteThread在創建線程時使用掛起創建,即第六個參數為0x00000004,然后sleep休眠一段時間,待檢測完后主動調用ResumeThread 恢復線程的執行。

參考項目:
https://github.com/plackyhacker/Suspended-Thread-Injection/blob/main/injection.cs
NO.5 參考鏈接
https://github.com/plackyhacker/Suspended-Thread-Injection
https://synzack.github.io/Blinding-EDR-On-Windows/
Antivirus Bypass