如何破解MassLogger使用的反分析策略
FLARE團隊最近剛剛完成了對MassLogger的分析,MassLogger是一個相當新的憑證竊取軟件。盡管MassLogger缺少新穎的功能,但還是采用了一種復雜的技術,該技術在運行時取代了Microsoft中間語言(MSIL),從而阻礙了靜態分析。截至發稿時,只有一篇文章詳細介紹過MassLogger的混淆技術。本文,看看FLARE團隊是如何深入研究MassLogger憑證竊取程序和.NET運行時的。
MassLogger的基本情況
MassLogger是一個.NET憑證竊取軟件,它從啟動程序(6b975fd7e3eb0d30b6dbe71b8004b06de6bba4d0870e165de4bde7ab82154871)開始發起攻擊,該啟動程序使用簡單的反調試技術,在識別時可以輕松繞開安全監控。此第一階段加載程序最終會對第二階段程序集進行XOR處理,然后解密、加載并執行名為Bin-123.exe的最終MassLogger有效載荷(bc07c3090befb5e94624ca4a49ee88b3265a3d1d288f79588be7bb356a0f9fae)。最終的有效載荷可以輕松提取并獨立執行。因此,我們將專門關注使用主要反分析技術的最后有效載荷。
基本的靜態分析是不會發現什么有價值的東西的,不過我們注意到了一些有趣的字符串,但它們不足以為我們提供有關該惡意軟件功能的任何提示。在受控環境中執行有效載荷表明,該示例刪除了一個日志文件,該文件標識了惡意軟件家族,其版本以及最重要的一些配置選項。圖1中描述了一個示例日志文件,隨著示例的運行,我們還可以從內存中提取一些有趣的字符串。但是,基本的動態分析不足以提取所有基于主機的指標(HBI),基于網絡的指標(NBI)和完整的惡意軟件功能。我們必須進行更深入的分析,以更好地理解樣本及其功能。



MassLogger日志樣本
反編譯處理
與許多其他.NET惡意軟件一樣,MassLogger混淆了其所有方法名稱甚至方法控制流。我們可以使用de4dot自動對MassLogger有效載荷進行混淆處理。但是,查看經過混淆處理的有效載荷后,我們很快發現了一個主要問題:大多數方法幾乎不包含邏輯,如圖2所示。

顯示空方法的dnSpy
在dnSpy的中間語言(IL)視圖中查看原始的MassLogger有效載荷,可以確認大多數方法不包含任何邏輯,只是不返回任何內容。這顯然不是真正的惡意軟件,因為我們已經通過動態分析觀察到該樣本確實在執行惡意活動并記錄到日志文件中。我們只剩下幾個方法,最明顯的是主模塊構造函數中首先調用的帶有標記0x0600049D的方法。

顯示該方法詳細信息的dnSpy IL視圖
方法0x0600049D的控制流已被混淆為一系列switch語句,在dnSpy作為調試器的幫助下,我們仍然可以在某種程度上遵循該方法的高級邏輯。但是,全面分析該方法將非常耗時。相反,當第一次分析此有效載荷時,我會選擇快速掃描整個模塊以尋找提示。幸運的是,我發現了一些在基本靜態分析期間被忽略的有趣字符串:clrjit.dll,VirtualAlloc,VirtualProtect和WriteProcessMemory,如圖4所示。

分散在整個模塊中的有趣字符串
上網快速搜索“clrjit.dll”和“VirtualProtect”,可以迅速了解一種通常稱為“JIT掛鉤( Just-In-Time Hooking)”的技術。本質上,JIT掛鉤涉及在compileMethod()函數上安裝掛鉤,JIT編譯器將在該函數上將MSIL編譯為程序集(x86,x64等)。有了掛鉤,惡意軟件就可以輕松地用包含原始惡意軟件邏輯的真實MSIL替換每個方法體。為了全面了解此過程,讓我們先探索一下.NET可執行文件,.NET方法以及MSIL如何變成x86或x64程序集等問題。
.NET可執行方法
.NET可執行文件只是具有可執行(PE)格式的另一個二進制文件,現在網上有大量資源詳細描述PE文件格式,.NET元數據和.NET令牌表。不過這些并不是本文講解的重點,本書我們會將重點放在.NET方法上。
.NET程序集中的每個.NET方法都由一個令牌標識,實際上,.NET程序集中的所有內容,無論是模塊,類,方法原型還是字符串,都由令牌標識。讓我們看一下由令牌0x0600049D標識的方法,如圖5所示。最有效字節(0x06)告訴我們,這個標記是一個方法標記(類型0x06),而不是模塊標記(類型0x00)、TypeDef標記(類型0x02)或LocalVarSig標記(類型0x11)。三個最低有效字節告訴我們該方法的ID,在本案例中為0x49D(decimal為1181)。此ID也稱為方法ID(MID)或方法的Row ID。rowid是一個用來唯一標記表中行的偽列。它是物理表中行數據的內部地址,包含兩個地址,其一為指向數據表中包含該行的塊所存放數據文件的地址,另一個是可以直接定位到數據行自身的這一行在數據塊中的地址。

方法0x0600049D的方法細節
要查找有關此方法的更多信息,請查看.NET元數據目錄中.NET元數據流的“#~”流的表中查找,如圖6所示。我們遍歷該條目的編號1181或0x49D用于查找方法元數據的方法表,該方法元數據包括方法體的相對虛擬地址(RVA),各種標志,指向方法名稱的指針,指向方法簽名的指針,最后是這種方法指向用于以下參數的參數規范的指針。請注意,MID從1而不是0開始。

來自PE文件頭的方法細節
對于方法0x0600049D,方法體的RVA為0xB690。該RVA屬于.text部分,其RVA為0x2000。因此,此方法體從.text部分中的0x9690(0xB690 – 0x2000)字節開始。 .text部分根據標題從文件的0x200字節開始。結果,我們可以在文件中偏移0x9890(0x9690 + 0x200)字節的位置找到方法體。我們可以在圖7中看到方法體。

十六進制編輯器中的方法0x0600049D體
NET方法體
NET方法體以方法體標頭開頭,后跟MSIL字節。 .NET方法有兩種類型:小方法和大方法。查看方法體標頭的第一個字節,這兩個最低有效位會告訴我們該方法是小的(最后兩位為10)還是大的(最后兩位為11)。
NET 小方法
讓我們看一下方法0x06000495,按照前面所述的相同步驟,我們檢查方法表的行號0x495(decimal為1173,對SQL Server而言,Decimal可用來保存具有小數點而且數值確定的數值,它不像float和real是用來保存近似值。),發現方法體RVA為0x7A7C,它轉換為0x5C7C作為文件的偏移量。在此偏移量下,方法體的第一個字節為0x0A(二進制格式為10 1010)。

方法0x06000495元數據和體
由于兩個最低有效位是10,因此我們知道0x06000495是一個小的方法。對于一個小方法,方法正文標頭只有一個字節長。兩個最小有效位是10,表示這是一個小方法,六個最有效位告訴我們要跟蹤的MSIL的大小(即MSIL的長度)。在本例中,六個最有效的位是000010,這告訴我們方法體有兩個字節長。0x06000495的整個方法主體是0A 16 2A,后跟一個NULL字節,該字節已由dnSpy分解,如圖9所示。

dnSpy IL視圖中的方法0x06000495
NET大方法
返回到偏移量為0x9890到文件(RVA 0xB690)中的方法0x0600049D(條目號1181),方法體的第一個字節為0x1B(或二進制數0001 1011)。最低兩位是11,表示0x0600049D是大方法。 大方法體標頭的長度為12個字節,不過對其結構的介紹超出了本博客文章的范圍。我們真正關心的字段是此大標頭中偏移量為0x04字節的四字節字段。該字段指定此方法正文標頭之后的MSIL的長度。對于方法0x0600049D,整個方法體標頭為“1B 30 08 00 A8 61 00 00 75 00 00 11”,后面的MSIL長度為“A8 61 00 00”或0x61A8(decimal為25000)字節。

十六進制編輯器中的方法0x0600049D體
JIT編譯
無論一個方法是小的還是大的,它都不是按原樣執行的。當.NET運行時需要執行一個方法時,它將完全按照前面所述的過程查找方法體,該體包括方法體標頭和MSIL字節。如果這是第一次運行該方法,則.NET運行時將調用即時編譯器,該編譯器將MSIL字節提取并將其編譯為x86或x64程序集,具體取決于當前進程是32位還是64位。經過一些準備,JIT編譯器最終將調用compileMethod()函數。整個.NET運行時項目是開源的,可以在GitHub上獲得。我們可以很容易地發現compileMethod()函數具有以下原型(圖11):

compileMethod()函數原型
下圖顯示了CORINFO_METHOD_INFO結構。

CORINFO_METHOD_INFO結構
ILCode是指向要編譯的方法的MSIL的指針,而ILCodeSize告訴我們MSIL的具體時間。 compileMethod()的返回值是一個錯誤代碼,指示成功或失敗。如果成功,nativeEntry指針將使用包含從MSIL編譯的x86或x64指令的可執行內存區域的地址填充。
MassLogger JIT掛鉤
讓我們回到MassLogger,一旦主模塊初始化運行,它將首先解密其他方法的MSIL。然后,它安裝一個掛鉤以執行自己的compileMethod()版本(方法0x06000499)。此方法將真實的惡意軟件的MSIL字節替換為原始compileMethod()的info參數的ILCode和ILCodeSize字段。
除了替換MSIL字節外,MassLogger還在模塊初始化時修補方法體標頭。從圖13中可以看到,磁盤上的方法0x060003DD的方法體標頭(文件偏移為0x3CE0)與內存中的標頭(RVA 0x5AE0)不同。唯一保持一致的兩件事是最不重要的兩個位,它表示方法是小的還是大的。要成功地擊敗這種反分析技術,我們必須恢復真實的MSIL字節以及正確的方法體標頭。

駐留在磁盤上與加載到內存中時具有不同標頭的相同方法體
擊敗JITM的JIT方法體替換
為了自動恢復MSIL和方法體標頭,另一位FLARE團隊成員建議的一種可能方法是在加載并允許MassLogger模塊構造函數運行之前,在compileMethod()函數上安裝我們自己的掛鉤。使用托管掛鉤(新的compileMethod()是用C#編寫的托管方法)和本機掛鉤(新的compileMethod()是用C或C ++編寫的本機掛鉤),有許多關于掛鉤compileMethod()的教程和開源項目。但是,由于MassLogger掛鉤compileMethod()的獨特方式,我們無法使用許多上述項目實現的vtable掛鉤技術。除掛鉤外,JITM還包括.NET加載程序。此加載程序首先加載本機掛鉤DLL(jitmhook.dll)并安裝該掛鉤。然后,加載程序加載MassLogger有效載荷并執行其入口點。這將導致MassLogger的模塊初始化代碼執行并安裝自己的掛鉤,但是鉤住的是jitmhook.dll代碼而不是原始的compileMethod()。執行MassLogger入口點的另一種方法是調用RuntimeHelpers.PrepareMethod()API強制JIT編譯器在所有方法上運行。這種方法更好,因為它避免了運行惡意軟件,并且有可能恢復樣本自然代碼路徑中未調用的方法。但是,這需要額外的工作來強制所有方法正確編譯。
要加載和恢復MassLogger方法,請運行以下命令(圖14):

運行jitm的命令
超時結束后,你應該看到在當前目錄中創建的文件jitm.log和jitm.json。 jitm.json包含從Bin-123.exe恢復的所有方法的方法令牌,方法體標頭和MSIL。剩下要做的唯一事情就是重建.NET元數據,以便我們可以執行靜態分析。

示例jitm.json
重新構建
由于解密的方法體標頭和MSIL可能不適合原始.NET程序集,因此最簡單的方法是向MassLogger添加一個新部分和對應的標頭。JITM還包括以下Python 2.7幫助程序腳本以自動執行此過程:Script\pydnet.py。
通過將方法體標頭和每種方法的MSIL添加到新的PE部分(如XXX所示),我們可以輕松地解析.NET元數據并修復每種方法的RVA以指向新部分中的正確方法體。不幸的是,我沒有找到任何Python庫來輕松解析.NET元數據和MethodDef表。因此,JITM還包括部分實現的.NET元數據解析器:Script\pydnet.py。該腳本使用pefile和vivisect模塊,并將PE文件解析到Method表,以提取所有方法及其關聯的RVA。

在添加名為FLARE的其他部分之前和之后的Bin-123.exe
最后,為了將所有內容捆綁在一起,JITM提供了Script \ fix_assembly.py來執行以下任務:
1.將在jitm.json中恢復的每個方法的方法體標頭和MSIL寫入一個名為“section.bin”的臨時二進制文件中,同時記住相關的方法標記和到section.bin中的偏移量。
2.使用addsection.py將section.bin添加到Bin-123.exe中,并將數據保存到新文件中,例如Bin-123.fixed.exe。
3.使用pydnet.py解析Bin-123.fixed.exe并更新MethodDef表中每個方法項的RVA字段,以將指向正確的RVA指向新部分。
最終結果是部分重構的.NE程序集,盡管要使程序集正確運行還需要進行其他工作,但足以進行靜態分析以了解惡意軟件的高級功能。
讓我們看一下重構的方法0x0600043E,該方法為惡意軟件配置實現了解密邏輯。與原始MSIL相比,重建的MSIL可以顯示出,該惡意軟件在CBC模式下使用帶有PKCS7填充的AES-256。通過動態分析和靜態分析的組合,我們還可以輕松地將密鑰標識為“ Vewgbprxvhvjktmyxofjvpzgazqszaoo”,并將IV用作作為參數傳遞的Base64編碼緩沖區的一部分。

在修復程序集之前和之后的方法0x0600043
有了這些知識,我們就可以編寫一個簡單的工具來解密惡意軟件配置并恢復所有HBI和NBI(圖18)。


解密的配置
總結
使用JIT編譯器掛鉤替換MSIL是一項強大的反分析技術,安全人員幾乎無法對其進行靜態分析。盡管這項技術不是新技術,但我還沒有看到很多.NET惡意軟件使用它。希望通過這篇文章,分析人員將擁有分析MassLogger或使用類似技術的任何惡意軟件。
本文翻譯自:https://www.fireeye.com/blog/threat-research/2020/08/bypassing-masslogger-anti-analysis-man-in-the-middle-approach.html如若轉載,請注明原文地址。