當前位置:
首頁 > 新聞 > 從某惡意軟體Dropper樣本,探尋分析.NET惡意軟體的方法

從某惡意軟體Dropper樣本,探尋分析.NET惡意軟體的方法

概述

作為安全專家,我們更喜歡對新型惡意軟體進行分析。每當有安全團隊發布新型攻擊分析報告時,我們都會第一時間閱讀。從這些報告中,我們發現了一個規律,即使是能力最強的攻擊者,也會傾向於使用各種OS工具來執行攻擊,而不會傾向選擇使用某個API。

針對攻擊者,他們不一定需要掌握太多的開發技術,也不一定需要親自編寫惡意軟體才能實現惡意的目的。一個比較恰當的例子就是Fauxpersky惡意軟體,該惡意軟體是用AutoHotKey編寫而成的,這是一個用於自動執行任務的合法工具,攻擊者利用了該工具的特點,將其改裝成了一個能夠有效竊取用戶憑據的惡意軟體。

可能與大多數人的認知相反,安全研究人員並沒有將大量的事件投入到複雜的APT(高級持續威脅)的研究之中。實際上,安全研究人員更多會研究比較常見、沒有那麼高技術含量、卻能產生較大影響的威脅。

接下來,讓我們言歸正傳,首先簡要分析一下.NET。.NET是微軟在21世紀初推出的一個編程框架,其目標是希望讓編程變得更容易。使用.NET時,即使開發者在編寫一個簡單的程序,也可以使用C語言分配和釋放內存,或者使用C++編寫非常複雜的代碼。在.NET語言中,最受歡迎的是C#語言,這是一個面向對象的現代通用語言,並且已經被廣泛使用。從底層來看,C#對Windows、Linux、macOS的支持都非常好,開發過程便捷,語法較為流暢,再藉助Visual Studio的自動完成功能和Windows API調用功能,該語言的編寫能變得更加輕鬆。此外,在編譯項目時,C#將會被編譯為EXE或DLL。

針對.NET的逆向工程

在聽了上面的這些介紹後,你可能會提出疑問,「如果使用.NET編程比使用C或C++更容易,那麼如果我想要在編譯後得到二進位的PE文件,會有什麼問題嗎?」問題在於,得到的文件不是真正的原始可執行文件,如果我們查看該文件,將無法找到X86彙編代碼,原因在於.NET的工作方式不同。

圖片來源:http://www.developingthefuture.net/compilation-process-and-jit-compiler/

在編譯.NET項目時,它實際上被編譯成MSIL語言(Microsoft Intermediate Language )。而我們在使用即時編譯器(JIT)時,實際上就是對代碼進行了編譯。如果大家有興趣了解更多關於.NET編譯的信息,建議參考Microsoft的相關文檔。在這裡,我們可以將MSIL類比成彙編語言,只不過它是在更高的層次上。

那麼,為什麼使用.NET進行編譯會讓分析工作變得如此繁瑣呢?我們來看看使用C/C++編寫的可執行文件與使用.NET編寫的可執行文件二者彙編語言的差異。當我們對一個「普通」(比如用C語言編寫的)可執行文件進行逆向時,反彙編程序將會展示出x86/64彙編代碼。但是,對於使用.NET編譯的可執行文件,「彙編代碼」也能展現,但它卻是截然不同的。將代碼編譯成MSIL,意味著代碼中會包含很多方便反編譯的元數據。事實上,如果想要成功對.NET的代碼進行逆向,我們需要的只是一個.NET反編譯器和一點點耐心。

最近,我在用於測試惡意軟體樣本的主機上發現了一些奇怪的自動運行文件。我很好奇,這些自動運行文件是如何產生的。在追溯這台主機上的所有文件活動時,我注意到Patient Zero是在我發現Autoruns前幾分鐘在這台機器上執行的惡意軟體樣本。因此,我查看了該樣本的原始可執行文件,並發現這個文件是從.NET項目編譯而成的。這就意味著我們需要使用一組完全不同的工具來對它進行分析。我們不能再使用IDA Pro這樣的反彙編程序,而是需要一個.NET反彙編程序。我最喜歡的工具是dnSpy,這是一個很棒的調試器,並且具有良好的用戶界面,這個工具是基於另一個優秀的項目ILSpy開發而成的。

通過使用dnSpy反編譯器,我們能看到明確的代碼,這一代碼非常接近於惡意軟體的源代碼。儘管一些變數、對象和類可能與實際名稱不同,但顯示的代碼依然非常清晰。

反混淆處理

但是,當我們查看反編譯代碼以及類和函數的名稱時,我們發現了一些奇怪的地方,看上去該惡意軟體進行了混淆:

混淆後的命名空間:

混淆並加殼的代碼,看上去沒有任何實際意義:

由於.NET程序可以很容易的反編譯,因此許多開發人員(和惡意軟體作者)會使用各種混淆方法,使逆向工程變得更加複雜。幸運的是,有一些工具能幫助我們進行反混淆處理。

為了簡化反混淆的過程,我們使用了一個名為「Detect It Easy」的工具。我們將文件拖動到相應的窗口,就能夠看到關於該文件的一些重要信息,其中包括其使用的混淆器的信息。經過分析,我們所研究的惡意軟體使用了SmartAssembly混淆工具。

在我們知道所使用的混淆工具之後,我們就開始尋找針對它的反混淆方法。在這裡,我建議使用de4dot,這是一個開源的.NET反混淆器和去殼器。

在運行de4dot之後,我們看到惡意文件已經被去殼,並進行了反混淆:

現在,我們終於得到了這個神秘的惡意軟體樣本。

使用dnSpy打開樣本後,我們發現這回命名空間變得不一樣了,現在是有意義的:

動態分析

首先,這些並不是原始的命名空間名稱。為了保證易讀性,反混淆器自動生成了這些命名空間和其他對象、符號的通用名稱,我們無從得知作者指定的原始名稱。

這個Dropper最初是使用Visual Basic編寫的,但dnSpy允許我們將MSIL代碼轉回VB或C#,我為了讓語法更容易理解,所以選擇了C#。在後續深入分析的過程中,我們看到的所有代碼截圖都是由MSIL轉換而來的C#,儘管該MSIL最初是由VB編寫的代碼編譯而成。

當查看「-」命名空間時,我們可以看到一個名為「Class 14」的類(由反混淆器命名),以及其下面的許多類方法:

通過查看Class14中的代碼,我們可以清楚地看到一些代碼嘗試使用Interaction.Environ調用枚舉環境變數:

我們可以清楚的看到,環境變數實際上是兩個經Base64編碼的字元串連接。當我試圖進行Base64解碼時,我們得到一些無法理解的模糊內容:

在查看代碼的其他部分時,我們發現它調用了一些加密庫和函數:

該樣本中包含著許多麵條代碼(Spaghetti Code,指控制結構複雜、混亂、難以理解的代碼),這些代碼大量引用其他類,使得研究人員難以對其進行靜態分析。在這時,很容易發現Base64解碼後的內容也是加密的,因此我們有兩種方案可以選擇:

1、靜態分析:快速編寫一些代碼,並對代碼中使用的所有密鑰進行解密。

2、動態分析:使用調試器逐步執行程序,並觀察該程序如何對值進行解密和反模糊處理。

我果斷選擇了第二種方案,主要是因為其效率更高,因為代碼已經非常清晰,而且我們逐步執行的並不是討厭的彙編代碼。

dnSpy也可以作為調試器使用,只要點擊相應的行並按下F9,就能輕鬆在代碼中放置斷點。

我在第1081行放置了一個斷點,這是smethod_56()函數的開始位置。如圖中所示,該函數接受一個參數string_0(同樣,字元串變數的名稱也是由反編譯器生成)。

string_0是一個Base64編碼的值。

當我們按F10跳過當前子函數(Step Over)時,可以看到各種對象中都填充著數據。

這樣一來,理解smethod_56()的功能就變得很簡單。該函數從3個不同的變數中創建3位元組的數組:

S2 (1B2c3D4e5F6g7H8)

S (cffffffffffffffffff)

String_0 (Sk1N1W/kLlYPS5rz2GRFew==)

然後,會實例化rfc2898DeriveBytes類,並將這三個參數傳遞給它:

Password:上面截圖中的「nia」,作為密碼;

Bytes2:由s變數產生的位元組數組,作為加鹽(Salt);

2:派生密鑰的迭代次數。

然後,該函數創建另一個位元組數組bytes3,其中包含剛剛生成的密鑰。

該函數將繼續實例化RijndaelManaged類,並調用CreateDecryptor函數,使用bytes3和bytes作為其參數,這兩個參數分別是密鑰和IV。

當我們繼續單步執行(Step Over)時,可以發現有幾個經過混淆和加密的字元串是通過調用smethod_0()來實現解密的,其值需要反混淆和解密:

對每個值進行反模糊處理和解密後,我們可以在下面的變數窗格中看到它的解密值:

在這裡,text2包含可執行文件(當前正在運行)自身的完整路徑。

我們進一步深入分析代碼,發現其他的一些字元串也被反混淆和解密,這些字元串能夠表明該惡意軟體的更多行為特徵。

正如我們在這段代碼中所看到的,幾個混淆/加密的字元串由一個不同的(但非常相似的)函數負責反混淆和解密,也就是smethod_76()。請注意顯示為中文的不同加密密鑰:

如果我們再次查看變數窗格,可以發現有更多路徑被解密。我們可以清楚地看到:sourceFileName代表msbuild.exe的原始路徑,而destFileName包含用戶臨時目錄中名為svhost.exe的文件的路徑:

如果回到代碼,可以看到實際上有一個文件複製的操作:

這意味著,臨時目錄中的svhost.exe實際上就是MSBuild.exe。在分析過程中,我們實際上可以訪問該路徑,並對這個文件進行分析:

Svchost(實際上是msbuild)將用於創建一個非常小的二進位文件,它會修改註冊表值,以創建持久性。

惡意軟體特性:通過注入終止進程

這個Dropper的一個特性是能夠終止研究工具。我在運行Procmon的過程中發現了這一點。當調試器在class_14中執行第2094行時,我的所有研究工具都停止了工作。這樣一來,我開始好奇:這裡究竟發生了什麼?惡意軟體是如何使這些工具關閉的?

通常,當惡意軟體想要關閉特定目標程序時,它會根據一個應用程序列表(列表中可能會有Wireshark、sysinternals等工具),每隔n秒輪詢一次進程列表,如果存在正在運行的特定進程,就會調用TerminateProcess()實現對進程的關閉。

而在這裡,這個惡意軟體Dropper則截然不同。我沒有在代碼中發現任何對TerminateProcess()的直接或間接調用,這裡所說的間接調用是通過GetProcAddress()實現。

在調試惡意軟體的構成中,我注意到ProcessHacker退出,並且在惡意可執行文件終止之前無法再次打開。當然,這似乎是惡意軟體的某種機制,用於防止安全研究人員對其進行動態分析。

其常用的方法是使用Windows API的CreateToolHelp32Snapshot()函數。這個函數將獲取進程的「快照」,以及堆、模塊和其他信息。

對於我們的樣本,它會獲取所有正在運行進程的列表,並在每個進程上調用CreateToolHelp32Snapshot(),然後將結果存儲在數組中。這個數組的每個成員都存儲著正在運行的進程的相關信息。

一旦檢測到安全研究的相關進程,Dropper就會解密下面的代碼,將其注入到相應進程並執行,通過調用NtTerminateProcess()來阻止安全研究工作。

總結

在研究過程中,我們以這一.NET惡意軟體Dropper為例,詳細講解了逆向工程的方法及所需要的工具,並發現了該惡意軟體的一個重要特性。

針對.NET惡意軟體,只需要突破反編譯的瓶頸,隨後的分析過程也就變得順理成章了。

此後,我們還將對這一Dropper投放的惡意軟體進行詳細分析,並嘗試通過靜態分析得到該惡意軟體的全部功能。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

針對間諜軟體InvisiMole的RC2CL模塊分析
如何解密LockCrypt勒索軟體加密的文件

TAG:嘶吼RoarTalk |