Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86376213

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

微信截图_20230319161953.png

新版DotRunpeX完整的技術分析為了分析dotRunpeX的新版本,使用了示例SHA256:“44a11146173db0663a23787bffbb120f3955bc33e60e73ecc798953e9b34b2f2”。這個示例是一個用.NET編寫的64位可執行文件“.exe”,受KoiVM保護。版本信息與舊版本的DotRunpeX的情況相同,並且在CPR分析的所有示例中都是一致的。 CPR可以再次注意到ProductName – RunpeX.Stub.Framework 。

33.png

新DotRunpeX版本的信息

在dnSpyEx中打開示例並導出入口點函數_sb()方法後,CPR可以立即確認此新版本的DotRunpeX受到KoiVM虛擬程序的保護。儘管大多數IL代碼都是虛擬化的,但CPR仍然可以發現P/Invoke定義的CreateProcess方法的調用,該方法以某種方式創建一個處於掛鉤狀態的進程——通常用於代碼注入技術“Process Hollowing”。

34.png

創建掛鉤的流程作為Process Hollowing技術的一部分

在進一步研究了.NET元數據(特別是ImplMap表)中剩餘的內容之後,找出了定義為P/Invoke並很可能被這個示例使用的其他方法,CPR得到了比舊版本dotRunpeX更令人興奮的發現。顯然,該示例不僅執行代碼注入,還執行加載和與驅動程序通信。

35.png

ImplMap表——DotRunpeX的新版本

CPR立即註意到的下一個是使用了與舊版本相同的資源名——BIDEN_HARRIS_PERFECT_ASSHOLE——它包含要注入的加密有效負載。資源名稱在CPR分析的所有樣本中都是一致的。很明顯,解密例程隱藏在代碼虛擬化之後,但通過猜測,他們可以得到一個簡單的異或解密例程,它使用了一個表示開發者秘密願望的密碼——I_LOVE_HENTAIU2。

36.png

使用密碼“I_LOVE_HENTAIU2”對.NET資源進行簡單異或解密

不過,由於DotRunpeX仍處於開發階段,並添加了新功能,使用該注入器的最新示例改變了解密方案(不再是簡單的XOR),從而省略了嵌入式有效負載的靜態提取。

如上所述,IL代碼受到KoiVM虛擬程序的保護,因此為了繼續分析,CPR需要想出一些方法來處理受保護的代碼,並在合理的時間內從中獲得一些有意義的東西。首先,CPR想到的是使用一個名為OldRod的公開開源KoiVM去虛擬程序。這個工具完全適用於KoiVM的普通版本。它的開發方式甚至要優於KoiVM原始版本的一些簡單修改(例如VMEntry類中方法的簽名修改或默認#Koi流名稱的修改)。

不過,CPR正在處理一個自定義版本的KoiVM,它以一種不那麼容易被發現的方式修改了保護程序。 KoiVM的原始實現定義了119個用於虛擬化代碼的常量變量。這些常量用於定義寄存器、標誌、操作碼等。這些常量的指定值用於正確執行虛擬化代碼,也是去虛擬化過程所需的。

37.png

KoiVM的原始實現定義了119個常量

在使用普通版本的KoiVM時,在constants類內已編譯的、受保護的示例中,生成的常量以完全相同的順序顯示為字段,並帶有升序標記值。在編譯後的二進製文件中,常量及其對應的標記的順序是OldRod所依賴的。

38.png

OldRod源代碼——常量的自動檢測

儘管OldRod工具是一個非常好用的工具,並且可以在通過配置文件(——config選項)提供自定義常量映射時處理常量的自定義順序,但找出這些常量的正確映射並不像聽起來那麼簡單。有時,當一個常量的順序是手工修改時,通過分析它們在代碼中的使用來正確地映射它們可能並不難。但更糟糕的是,它們以一種非常有效的方式被打亂,使得正確的映射非常困難,以至於認為這種方法無法在合理的時間內獲得一些結果。

39.png

OldRod源代碼——常量的自動檢測

通過精確的代碼分析和通過適當的處理程序映射常量期間的一些困難時刻,CPR還是能夠完全去虛擬化代碼。不過,就算有了完全去虛擬化的代碼,但還是一個不能完全運行的.NET程序集,它仍然被ConfuserEx混淆器混淆了。

下圖是與驅動程序例程相關的完全去虛擬化和去混淆的代碼。

驅動程序裝載/卸載:

40.png

負責加載/卸載驅動程序的虛擬化和非虛擬化代碼

與procexp設備的通信:

41.png

負責與procexp設備通信的去虛擬化和去混淆的代碼

為了講解方便,本文不討論去虛擬化和去混淆的過程。

通常,當不可能在合理的時間內對代碼進行反虛擬化時,CPR仍然沒有其他選擇。第一個選項(處理虛擬化代碼時非常常見的方法)是使用調試器、DBI(動態二進制檢測)、掛鉤和WIN API跟踪進行動態分析。當CPR處理dotnet代碼時,另一種方法可能是使用一些來自.NET內部世界的知識進行PoC。 CPR決定將這兩種方法結合起來,從而開發出了一種非常有效的新工具。

為了獲得更多關於代碼功能的信息,CPR從使用x64dbg的動態分析方法開始。正如CPR之前指出的,包含P/Invoke定義的方法的ImplMap表似乎是在調試器中設置斷點的一個很好的起點。通過自動解析P/Invoke定義的方法並將其轉換為x64dbg腳本,CPR開發了第一個工具,稱為“ImplMap2x64dbg”。

ImplMap2x64dbg使用dnfile模塊正確解析.NET可執行文件及其元數據的Python腳本,此工具創建一個x64dbg腳本,用於在.NET可執行文件的已定義ImplMap (P/Invoke)方法上設置斷點。

42.png

使用' ImplMap2x64dbg '處理DotRunpeX示例將生成x64dbg腳本:

43.png

CPR主要關注某些WIN/NT API,如CreateProcessW、NtWriteVirtualMemory、CreateFileA、CreateFileW、NtLoadDriver、NtQuerySystemInformation和DeviceIoControl,因為它們是與驅動程序和進程注入例程相關的有趣API。

我們能看到的第一個有趣的WIN API調用是CreateFileW,它用於在路徑C:\Users\XXX\AppData\Local\Temp\Иисус.sys中創建一個文件。

44.png

CreateFileW用於創建文件“Иисус.sys”

如果CPR檢查創建的文件Иисус.sys(俄語翻譯為“jesus.sys”),就會立即發現它是一個有效的進程資源管理器驅動程序,版本為16.43。

45.png

創建的文件“Иисус.sys”是有效的進程資源管理器驅動程序,版本16.43

CPR可以看到負責加載此驅動程序的例程NtLoadDriver,其中參數指向DriverServiceName–\Registry\Machine\System\CurrentControlSet\Services\TaskKill,它指定了驅動程序註冊表項的路徑。

46.png

NtLoadDriver用於通過其關聯的註冊表項加載procexp驅動程序

47.png

驅動程序註冊表項“\registry\Machine\System\CurrentControlSet\Services\TaskKill”的內容

掛鉤到進程資源管理器設備如下。

48.png

獲取進程資源管理器設備的句柄

DotRunpeX逃避殺毒軟件技術之一是在進程資源管理器驅動程序(procexp.sys)的幫助下阻止一個硬編碼的反惡意軟件服務列表。使用進程資源管理程序驅動程序背後的原因是,反惡意軟件服務通常作為受保護的進程運行,更具體地說是作為PPL,以避免由惡意活動引起的系統保護失效。有可能濫用procexp驅動程序的易受攻擊版本來關閉受保護進程的對象句柄。一旦關閉了足夠多的句柄,特定的受保護進程將被終止。 CPR分析的所有示例都濫用了該驅動程序的16.43版本,這也是最新的易受該技術攻擊的版本。

為了獲得有關對象句柄的信息,DotRunpeX使用具有指定SystemInformationClass0x10的NT API NtQuerySystemInformation,該SystemInformationClass0x10指向未記錄的結構[SYSTEM_HANDLE_information]。通過這種方式,它可以找到屬於受保護進程的所有句柄。

49.png

NtQuerySystemInformation用於獲取未記錄的結構SYSTEM_HANDLE_INFORMATION

為了處理受保護進程的對象句柄,DotRunpeX使用WIN API DeviceIoControl將IOCTL直接發送給易受攻擊的procexp驅動程序。 IOCTL“2201288708”(IOCTL_CLOSE_HANDLE)在RDX寄存器中,處理此請求的procexp驅動程序例程負責關閉指定進程的某些對象句柄,無論指定進程是否受到保護。一旦關閉了足夠多的對象句柄,反惡意軟件服務就會被終止。

50.png

DeviceIoControl用於發送IOCTL“2201288708”以關閉受保護進程的對象句柄

我們還可以看到寄存器R8 (lpInBuffer)指向關閉對象句柄所需的數據。該數據結構可以定義如下:

51.png

讓我們比較一下DotRunpeX示例使用的procexp驅動程序版本(版本16.43,2021.8.17編譯)和最新版本的proceexp驅動程序(版本17.02,2022.11010編譯)。 CPR可以立即發現添加的修復代碼,該代碼負責禁用關閉受保護進程的對象句柄的可能性。

52.png

16.43與17.02版本進程資源管理器驅動程序之間的比較

這種使用進程資源管理器驅動程序關閉受保護流程的對象句柄的技術可以隨時上網查找到,並且是名為Backstab的開源項目的一部分,進程資源管理器驅動程序17.0以上的版本已經被修復。

在阻止特定的受保護進程後,Process Hollowing將使用WIN API CreateProcessW以掛鉤狀態啟動進程(在本例中為C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe),並直接使用NT API NtWriteVirtualMemory將DotRunpeX的嵌入式有效負載寫入新創建的遠程進程。

事實證明,通過一種專注於本機層和WIN/NT API的某些使用的動態分析方法,CPR對這種可用於自動化和大規模處理的虛擬化dotnet注入器獲得了一些有趣的發現:

每個DotRunpeX示例都有一個要注入的特定惡意軟件家族的嵌入式有效負載;

每個DotRunpeX示例都有一個嵌入式procexp驅動程序來終止受保護的進程;

虛擬化代碼背後很可能隱藏著某種配置,它指定了process Hollowing的目標進程、要阻止的受保護進程列表(反惡意軟件服務),以及其他有趣的可配置內容;

除此之外,CPR可以利用.NET內部世界的知識來實現一些自動化。當談論dotnet時,CPR可以立即想到由.NET運行時管理的代碼。越來越多的事情正在被管理,其中特別重要的就是所謂的“內存管理”。 dotnet中的內存類型有堆棧和.NET堆。在網絡世界中,CPR不需要為內存分配/釋放而煩惱,因為這些例程是由.NET運行時和垃圾收集器處理的。網絡的內存管理不知何故需要知道分配什麼、在哪里以及如何分配;解除分配/釋放內存也是如此。一旦討論了從System.Object(類、對象、字符串……)繼承的引用類型,就會在.NET堆上進行分配。這些對象保存在.NET堆上,為了進行自動管理,它們還附帶了某些元數據信息,如類型、引用和大小。另外就是不再引用的對象的自動內存釋放不會立即發生,垃圾收集器會在固定時間間隔內處理這一問題,可能需要幾分鐘。像“靜態對象”這樣的特定對象會在垃圾收集中倖存下來,並一直存持續到應用程序結束。

這意味著,如果CPR可以枚舉.NET堆上的對象,CPR也可以獲得與它們的類型和大小相關的信息,這些信息可以用於它們的適當重建。創建這種工具可能非常耗時,但幸運的是,CPR已經創建了dotnet進程和崩潰轉儲自省(crash dump introspection)開源庫ClrMD Microsoft.Diagnostics.Runtime,該庫由微軟開發,可以精確地用於從.NET堆重建對象。為什麼這很重要?

是因為在dotRunpeX執行的特定時刻,嵌入的有效負載、procexp驅動程序和某種配置必須以解密狀態出現。它們的內容可能會被分配到.NET堆上分配的某個對象。對於這些,CPR可以期望字節blobbyte[]或字符串。這也意味著,如果CPR能夠控制DotRunpeX的執行,並將其掛鉤,使其處於適合重建對象的狀態,那麼CPR將能夠在解密狀態下獲得所需的一切。

掛鉤和自省DotRunpeX進程的正確時機之一可能是調用用於Process Hollowing的WIN API CreateProcessW,這被認為是正確的假設,CPR為此開發了掛鉤庫“CProcessW_Hook”。

CProcessW_Hook使用minhook框架的本地掛鉤庫(適用於Windows的Minimalistic x86/x64 API掛鉤庫)。下面提供的代碼用於掛鉤WIN API函數CreateProcessW,該函數用於DotRunpeX注入器中的進程創建,該注入器後來用作代碼注入(PE Hollowing)的目標。一旦CreateProcessW函數被掛鉤並在目標進程中被調用,整個進程就會被掛鉤進行自省。某些進程創建會被過濾(powershell、conhost),因為它們可以根據配置為DotRunpeX的其他函數生成(例如修改Windows Defender設置)。 CPR只需要在執行代碼注入之前的狀態下暫停進程(其中所有需要的對像都已在.NET堆上解密)。

53.1.png

53.2.png

CPR可以看到,在函數DllMain()中加載這個庫時,所有的掛鉤邏輯都會立即執行。另一件需要注意的重要事情是,CPR定義了導出函數Decoy(),它永遠不會被執行或調用,但在以後的預注入技術中需要它。

有了掛鉤庫“CProcessW_Hook.dll”,CPR可以繼續創建一個注入器和提取器。這就是下面提供的主要工具——DotRunpeX提取器“Invoke-DotRunpeXextract”。

Invoke-DotRunpeXextractPowerShell模塊,支持從DotRunpeX中提取有效負載、procexp驅動程序和配置。該工具是用PowerShell腳本語言編寫的,使用預注入本機掛鉤庫“CProcessW_Hook.dll”(使用AsmResolver)和從.NET堆重建.NET對象(使用ClrMD)。它使用動態方法進行提取,因此樣本以託管方式執行(僅在VM中使用)。使用PowerShell 7.3+, clrMD v2.2.343001 (net6.0), AsmResolver v5.0.0 (net6.0)。

本文提供了該工具的兩個版本,其中一個是創建為多線程的PowerShell模塊,以獲得最佳性能和使用效果。該工具的第二個版本是一個具有相同功能的單線程腳本,可以用於簡單的調試和故障排除,並且可以更容易地創建具有類似功能的多個代碼段。

PowerShell模塊的整個代碼都以易於理解其核心功能的方式進行了註釋,接下來我們將簡要描述該工具的核心功能,如使用AsmResolver的掛鉤庫的預注入技術以及提取背後的實現邏輯。

首先,該工具使用AsmResolver修改DotRunpeX的PE結構。 AsmResolver以其檢查dotnet可執行文件及其相關元數據的功能而聞名,但它也允許訪問PE的底層結構來修改它們。這些PE結構修改用於實現上述PoC技術,目的是將dll預注入64位的dotnet可執行文件。 CPR正在討論將本機掛鉤庫的新導入條目添加到.NET程序集中。由於DotRunpeX是一個64位可執行文件,而且與32位的dotnet可執行文件不同,64位的dotRunpe