勒索軟件最新趨勢——使用NSIS安裝程序逃避檢測。惡意軟件家族在不斷尋求隱藏代碼、阻止復制及逃避檢測的新方法。勒索軟件遞送的最新趨勢是使用帶加密有效載荷的Nullsoft腳本安裝系統(NSIS)。很多知名勒索軟件均采用該技術,比如Cerber、Locky、Teerac、Crysis、CryptoWall及CTB-Locker。
我們很少看到多個家族一直使用相同的打包方法。在本文所述情況中,有效載荷依賴安裝程序來執行,解密的惡意軟件有效載荷不會接觸磁盤。使用NSIS打包方法使我們較難采用批量采集技術采集和發現惡意軟件。傳入的樣本可能只包含負責解壓縮的DLL,不包含加密的有效載荷或NSIS安裝程序。在本文中,我們將看看該種遞送機制如何運作,為何使用這樣的機制,及這種機制對試圖研究惡意軟件的研究人員提出的挑戰。
這種遞送方法為何很流行?
該攻擊途徑以垃圾郵件下載器的有效載荷為起始。不知情的用戶打開包含惡意JavaScript或Word文檔的電子郵件附件。惡意安裝程序(檢測為NSIS / ObfusRansom。*)在%TEMP%中下載、啟動并釋放一個DLL文件和一個加密數據文件。安裝程序隨后加載負責解密和執行加密有效載荷的DLL。解包器DLL從NSIS安裝程序的導入地址表中竊取五個API。然后,DLL將加密文件讀入內存,轉到文件中的隨機硬編碼偏移量,并解密解壓縮、寫入內存及執行加密惡意軟件有效載荷所需的其他API。這種依賴性使得靜態分析、仿真及復制變得更加困難,并產生了一種解密勒索軟件不接觸磁盤的遞送系統。在分析這些打包器時,我們未發現提交到任何知名樣品處理網站(比如VirusTotal)的解密的惡意軟件可執行的樣本。
打包器執行
以上流程圖總結了該打包器的基本執行流程,發現各種水平的混淆均采用該流程,但功能上等同。我們選擇了一個混淆程度較低的樣本(MD5: F9AE740F62811D2FB638952A71EF6F72),以方便技術解釋。
大多數版本還嘗試一定的代碼流混淆來延遲靜態分析。我們觀察到的兩種常見的代碼流混淆方法是結合可報警Sleep調用的QueueUserAPC:
或結合除零的結構化異常處理:
這些方法均不是該遞送方法所獨有,在執行靜態分析時也不是很難看到。一旦進入主函數,惡意軟件首先進行反混淆三個亂碼字符串。在某些情況下,在樣本上運行“字符串”即可查看,如以下截圖所示:
大多數情況下,這些字符串包含“Kernel32”( Microsoft API調用)和由安裝程序釋放的加密文件的名稱。以下是正在解密的Kernel32的樣本。所有這三個字符串都以類似的方式進行反混淆。
反混淆算法:
混淆字符串內存:
反混淆字符串內存:
字符串被反混淆后,惡意軟件接下來會創建一個指向安裝程序內存空間的指針,并保存FirstThunk和OriginalFirstThunk的偏移量(“thunk”是一個自動生成的代碼段,用于協助調用另一個子例程)。本質上,OriginalFirstThunk是導入名稱表,FirstThunk是導入地址表。
解包器DLL然后遍歷OriginalFirstThunk,查找直接從相應的FirstThunk條目竊取和保存其地址所需的五個API的名稱。該循環使用一些基于字符串大小和字母位置的基本邏輯來準確獲取其所需的API。
GetProcAddress:
GetModuleHandle:
GetFileSize:
GlobalAlloc:
ReadFile:
這五個竊取的API用于將加密的文件讀入內存,然后在其中解密其所需的第二層API。
打包器接下來準備有效載荷。當父NSIS安裝程序運行時,其釋放的其中一個文件是加密和壓縮的文件。該文件是打包器正準備啟動的惡意軟件的主要有效載荷。正如我們提到的,我們的研究表明,該有效載荷可以是各種惡意軟件(包括若干勒索軟件變體)的有效載荷。
惡意軟件首先使用CreateFile API打開有效載荷的文件句柄。有效載荷名稱和擴展名是已經反混淆的字符串之一。
ECX值(文件名):
惡意軟件獲取解密和讀取文件所需的文件大小。然后使用文件大小為將要讀入內存的文件新分配一塊內存:
加密的文件現已存儲在內存中,惡意軟件開始通過解密API的名稱來處理這個文件。我們研究的每個樣本都具有API名稱和硬編碼在樣本中的解密密鑰的位置。我們還發現,這兩項通常可以在文件的第一個0x1FFF字節中找到。API字符串的解密使用簡單的算法在一個循環中完成。
加密API:
該代碼混淆程度可能極高(視樣本而定)。我們反編譯了該樣本,并將此循環中使用的解密算法簡化為了如下所示的相關行:
do{
api = *(api_base + counter);
key = ~*(counter + randomoffset);
*(api_base + counter) = api & key | ~key & ~api;
++counter;
}while ( counter
我們可以看到此處的“加密”是非常基礎的。我們發現的一些樣本具有稍微不同的解密算法,但都是對存儲的密鑰的非常基本的算術運算。該函數對密鑰和加密值進行按位AND一次,然后再對這些值NOTed。然后對結果按位ORed。在我們的樣本組中,被解密的字符串總是相同的,因此迭代次數保持恒定,為0x14A (330)。
解密的API:
下一個主要任務是有效載荷本身的解密。下圖顯示了加密有效載荷的內存位置:
整個文件不經過解密流程(僅可執行文件本身經過)。惡意軟件使用從GetFileSize收集的大小和硬編碼值來確定要解密的字節數。
我們樣本中有效載荷的解密算法與API解密算法相同。
基于循環結束時間,與API解密流程有一個小的明顯不同之處。如上所示,ebx保存要解密的字節數,而現在充當計數器。
解密的有效載荷:
文件和API現已解密,隨后惡意軟件解壓縮其有效載荷。惡意軟件作者使用標準Windows API執行壓縮,并在解密后通過調用RtlDecompressBuffer再次使用。在這個API中,推送到棧上的“2”表示使用的壓縮類型。根據Microsoft文檔,2代表LZ解壓縮。
有效載荷在內存中完全解密和解壓縮后,我們現在可以使用Windbg的“.writemem”函數轉儲功能完整的獨立有效載荷。這讓我們可以研究有效載荷并確定其是否是已知的勒索軟件變體,但是,這些具體的有效載荷尚未被常見的惡意軟件研究網站觀察到。
現在需要進行設置,以在內存中執行此有效載荷。解密的有效載荷從不接觸磁盤,有助于降低被檢測到的可能性。第一步是調用處于掛起狀態的CreateProcess。惡意軟件在此進程中執行:
CreateProcess API后,惡意軟件使用標準的進程空白技術。在準備將其有效載荷寫入新線程過程中使用了VirtualAlloc、GetThreadContext、ReadProcessMemory及NtUnmapViewofSection。WriteProcessMemory將未加密的有效載荷復制到新線程中。接下來一個Sleep和ResumeThread調用啟動線程。線程啟動后,惡意軟件立即終止父線程。
總結
這些樣本的核心功能非常簡單,未展現任何新的行為,但遞送方法提出了一個新的有意思的挑戰。在帶加密有效載荷的NSIS安裝程序中遞送勒索軟件已被證明是遞送各種惡意軟件的獨特而有效的方法。目前,已研究的所有樣本都只包含勒索軟件的變體,但我們可以猜測,其他家族的惡意軟件也在使用這種技術。我們已經觀察到了廣泛的反仿真方法、強的代碼混淆技術及硬編碼值的差異。字段和API所用的加密通常非常弱,并不是逆向或檢測的主要挑戰。原因很可能是一個威脅實施者在分發多種形式的勒索軟件,或者是多個威脅實施者在使用相同的組來分發其勒索軟件。
|