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



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

顯示空方法的dnSpy
在dnSpy的中間語言(IL)視圖中查看原始的MassLogger有效載荷,可以確認(rèn)大多數(shù)方法不包含任何邏輯,只是不返回任何內(nèi)容。這顯然不是真正的惡意軟件,因?yàn)槲覀円呀?jīng)通過動(dòng)態(tài)分析觀察到該樣本確實(shí)在執(zhí)行惡意活動(dòng)并記錄到日志文件中。我們只剩下幾個(gè)方法,最明顯的是主模塊構(gòu)造函數(shù)中首先調(diào)用的帶有標(biāo)記0x0600049D的方法。

顯示該方法詳細(xì)信息的dnSpy IL視圖
方法0x0600049D的控制流已被混淆為一系列switch語句,在dnSpy作為調(diào)試器的幫助下,我們?nèi)匀豢梢栽谀撤N程度上遵循該方法的高級(jí)邏輯。但是,全面分析該方法將非常耗時(shí)。相反,當(dāng)?shù)谝淮畏治龃擞行лd荷時(shí),我會(huì)選擇快速掃描整個(gè)模塊以尋找提示。幸運(yùn)的是,我發(fā)現(xiàn)了一些在基本靜態(tài)分析期間被忽略的有趣字符串:clrjit.dll,VirtualAlloc,VirtualProtect和WriteProcessMemory,如圖4所示。

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

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

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

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

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

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

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

compileMethod()函數(shù)原型
下圖顯示了CORINFO_METHOD_INFO結(jié)構(gòu)。

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

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

運(yùn)行jitm的命令
超時(shí)結(jié)束后,你應(yīng)該看到在當(dāng)前目錄中創(chuàng)建的文件jitm.log和jitm.json。 jitm.json包含從Bin-123.exe恢復(fù)的所有方法的方法令牌,方法體標(biāo)頭和MSIL。剩下要做的唯一事情就是重建.NET元數(shù)據(jù),以便我們可以執(zhí)行靜態(tài)分析。

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

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

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


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