【筆記】【THM】Malware Analysis(惡意軟體分析)

Super_Snow_Sword發表於2024-08-11

【筆記】【THM】Malware Analysis(惡意軟體分析)

探索惡意軟體的世界,分析惡意軟體如何感染系統並造成破壞。

惡意軟體分析就像貓捉老鼠的遊戲。惡意軟體的作者一直在設計新的技術來躲避惡意軟體分析師的眼睛,而惡意軟體分析師也一直在尋找識別和抵消這些技術的方法。在這個模組中,我們將開始學習惡意軟體分析的旅程,從基礎知識到理解惡意軟體作者使用的常見技術。最後,我們將學習一些工具,這些工具使惡意軟體分析師能夠在識別惡意軟體作者的意圖並擊敗他們方面獲得立足點。

img

x86體系結構概述

本文相關的TryHackMe實驗房間連結:TryHackMe | x86 Architecture Overview

本文相關內容:x86架構的速成課程,使我們能夠進行惡意軟體逆向工程。

Room Banner

介紹

img

惡意軟體通常透過濫用系統的設計方式來工作。因此,為了理解惡意軟體的工作原理,我們必須知道它們執行的系統的架構。在這個房間裡,我們將從惡意軟體分析的角度對x86架構進行簡要概述。請注意,我們可能會跳過很多關於x86架構的細節,但這是因為它們與惡意軟體分析無關。

(補充:X86架構(The X86 architecture)是微處理器執行的計算機語言指令集,指一個intel通用計算機系列的標準編號縮寫,也標識一套通用的計算機指令集合。)

學習目標

總而言之,我們將在這個房間裡討論以下主題。

  • CPU體系結構及其組成概述
  • 不同型別的CPU暫存器及其使用
  • 程式檢視的記憶體佈局
  • 棧佈局和棧暫存器

現在,讓我們深入討論並瞭解上述主題。

CPU架構概述

目前使用最廣泛的CPU體系結構來源於馮·諾依曼體系結構。下圖展示了該架構的簡要概述。

An image showing a CPU containing all its components, the ALU, the Control Unit and the Registers, and the Main Memory and I/O devices, which are outside the CPU

這個圖顯示了中央處理器(CPU)由三個組成部分:算術邏輯單元(ALU),控制單元(CU)和暫存器。CPU與CPU外部的記憶體和I/O裝置互動。

讓我們瞭解一下上圖中提到的每個元件。

控制單元(Control Unit):

控制單元從主記憶體中獲取指令,如圖所示,主記憶體在CPU外部。要執行的下一條指令的地址儲存在一個稱為指令指標或IP的暫存器中。在32位系統中,這個暫存器稱為EIP,而在64位系統中,它稱為RIP。

算術邏輯單元(Arithmetic Logic Unit):

算術邏輯單元執行從儲存器中取出的指令。然後,執行指令的結果儲存在暫存器或記憶體中。

暫存器(Registers):

暫存器是CPU的儲存器。暫存器通常比位於CPU外部的主記憶體小得多,透過直接訪問CPU來放置重要資料,有助於節省執行指令的時間。

記憶體(Memory):

記憶體,也稱為主存或隨機存取儲存器(RAM),包含程式執行所需的所有程式碼和資料。當使用者執行一個程式時,它的程式碼和資料被載入到記憶體中,CPU從記憶體中一次訪問一條指令。

I / O裝置(Input/Output devices):

I/O裝置或輸入/輸出裝置是與計算機互動的所有其他裝置。這些裝置包括鍵盤、滑鼠、顯示器、印表機、大容量儲存裝置(如硬碟和usb)等。

簡而言之,當一個程式必須被執行時,它被載入到記憶體中。從那裡,控制單元每次使用指令指標暫存器獲取一條指令,算術邏輯單元執行它。結果儲存在暫存器或記憶體中。

問題

1.程式執行所需的程式碼和資料儲存在計算機體系結構的哪一部分?

2.CPU的哪一部分儲存少量資料?

3.算術運算在哪個單元中執行?

WP

1.程式執行所需的程式碼和資料儲存在記憶體中

2.CPU的暫存器儲存少量資料

3.算術運算在算術邏輯單元中執行

image-20240808160152404

暫存器概述

暫存器是CPU的儲存介質。CPU可以比任何其他儲存介質更快地從暫存器訪問資料;然而,它有限的大小意味著必須有效地使用它。為此,暫存器分為下列不同型別。

  • Instruction Pointer 指令指標
  • General Purpose Registers通用暫存器
  • Status Flag Registers 狀態標誌暫存器
  • Segment Registers 段暫存器

讓我們在下面逐一檢視這些暫存器:

指令指標:

指令指標是一個暫存器,包含了CPU要執行的下一條指令的地址。它也稱為程式計數器。它最初是Intel 8086處理器(術語x86源於此)中的一個16位暫存器,縮寫為IP。在32位處理器中,指令指標變成32位暫存器,稱為EIP或擴充套件指令指標。在64位系統中,這個暫存器成為稱為RIP(這裡的R代表暫存器)的64位暫存器。

通用暫存器

x86系統中的通用暫存器都是32位暫存器。顧名思義,它們在CPU執行指令期間使用。在64位系統中,這些暫存器被擴充套件為64位暫存器。它們包含下列暫存器。

an Image showing the breakdown of the different general-purpose registers

EAX或RAX:

這是累加器暫存器。算術運算的結果通常儲存在這個暫存器中。在32位系統中,存在32位EAX暫存器,而在64位系統中存在64位RAX暫存器。這個暫存器的最後16位可以透過定址AX來訪問。類似地,它也可以在8位中定址,透過使用AL為低8位,AH為高8位。

EBX或RBX:

該暫存器也稱為基址暫存器,通常用於儲存基址以引用偏移量。與EAX/RAX類似,它可以被定址為64位RBX、32位EBX、16位BX、8位BH和BL暫存器。

ECX或RCX:

該暫存器也稱為計數器暫存器,常用於迴圈等計數操作。與上述兩個暫存器類似,它可以被定址為64位RCX、32位ECX、16位CX和8位CH和CL暫存器。

EDX或RDX:

該暫存器也稱為資料暫存器。它經常用於乘法/除法運算。與上述暫存器類似,它可以被定址為64位RDX、32位EDX、16位DX和8位DH和DL暫存器。

ESP或RSP:

這個暫存器稱為棧指標(Stack Pointer)。它指向棧的頂部,與棧段暫存器聯合使用。它是一個32位暫存器,在32位系統中稱為ESP,在64位系統中稱為RSP。它不能用較小的暫存器定址。

EBP或RBP:

這個暫存器稱為基指標(Base Pointer)。它用於訪問棧傳遞的引數。它也與棧段暫存器聯合使用。它是一個32位暫存器,在32位系統中稱為EBP,在64位系統中稱為RBP。

ESI 或 RSI:

這個暫存器稱為源索引暫存器。它用於字串操作。它與資料段(DS)暫存器一起用作偏移量。它是一個32位暫存器,在32位系統中稱為ESI,在64位系統中稱為RSI。

EDI 或 RDI

該暫存器稱為目標索引暫存器。它也用於字串操作。它與額外的Segment (ES)暫存器一起用作偏移量。它是一個32位暫存器,在32位系統中稱為EDI,在64位系統中稱為RDI。

R8-R15:

這些64位通用暫存器在32位系統中不存在。它們被引入64位系統。它們還可以以32位、16位和8位模式定址。例如,對於R8暫存器,我們可以使用R8D進行低32位定址,使用R8W進行低16位定址,使用R8B進行低8位定址。在這裡,字尾D代表Double-word, W代表Word, B代表Byte。

問題

1.哪個暫存器儲存要執行的下一條指令的地址?

2.32位系統中的哪個暫存器也稱為計數器暫存器?

3.上面討論的暫存器中,哪些不存在於32位系統中?

WP

1.指令指標儲存要執行的下一條指令的地址

2.32位系統中的ECX暫存器也稱為計數器暫存器

3.上面討論的暫存器中,R8-R5不存在於32位系統中

image-20240810232215938

暫存器-續

狀態標誌暫存器:

執行命令時,有時需要一些關於執行狀態的指示。這就是狀態標誌的作用。用於32位系統的一個32位狀態標誌暫存器,稱為“EFLAGS”;它在64位系統中擴充套件為64位,在64位系統中稱為“RFLAGS”。狀態標誌暫存器由單個位標誌組成,可以是1或0。下面討論一些必要的標誌。

Zero Flag零標誌:

縮寫由ZF表示,表示最後執行的指令的結果是0。例如,如果執行一條從自身減去一個RAX的指令,結果將是0。在這種情況下,ZF將被設定為1。

Carry Flag進位標誌:

縮寫由CF表示,表示最後執行的指令導致的數字對目標來說太大或太小。例如,如果我們將0xFFFFFFFF和0x00000001相加,並將結果儲存在一個32位暫存器中,那麼結果對暫存器來說就太大了。在這種情況下,CF將被設定為1。

Sign Flag符號標誌:

縮寫由SF表示,表示操作的結果是否為負數或最高有效位是否設定為1。如果滿足這些條件,SF設定為1;否則,將其設定為0。

Trap Flag陷阱標誌:

縮寫由TF表示,表示處理器是否處於除錯模式。設定TF時,CPU將出於除錯目的一次執行一條指令。這可以被惡意軟體用來識別它們是否在偵錯程式中執行。

通用暫存器 段暫存器 狀態暫存器 指令指標
RAX, EAX, AX, AH, AL CS EFLAG EIP,RIP
RBX, EBX, BX, BH, BL SS
RCX, ECX, CX, CH, CL DS
RDX,EDX,DX,DH,DL ES
RBP, EBP, BP FS
RSP, ESP, SP GS
RSI、ESI、SI
RDI, EDI, DI
R8-R15

段暫存器:

段暫存器是16位暫存器,它將平面記憶體空間轉換為不同的段,以便於定址。有6個段暫存器,解釋如下:

  • 程式碼段(Code Segment, CS):程式碼段暫存器指向記憶體中的程式碼段。
  • 資料段:資料段(Data Sgment, DS)暫存器指向記憶體中程式的資料段。
  • 棧段(Stack Segment, SS):棧段暫存器指向程式在記憶體中的棧。
  • 額外段(ES、FS和GS):這些額外的段暫存器指向不同的資料段。這些和DS暫存器將程式的記憶體劃分為四個不同的資料段。

問題

1.程式使用哪個標誌來標識它是否在偵錯程式中執行?

2.當操作中的最高位設定為1時,將設定哪個標誌?

3.哪個段暫存器包含了指向記憶體中程式碼段的指標?

WP

1.程式使用陷阱標誌來標識它是否在偵錯程式中執行

2.當操作中的最高位設定為1時,將設定符號標誌

3.程式碼段暫存器包含了指向記憶體中程式碼段的指標

image-20240810234051504

記憶體概述

當一個程式被載入到Windows作業系統的記憶體中時,它看到的是記憶體的一個抽象檢視。這意味著程式不能訪問整個記憶體;相反,它只能訪問自己的記憶體。對於這個程式來說,這就是它所需要的所有記憶體。為簡潔起見,我們不會深入作業系統如何執行抽象的細節。我們將從程式的角度來看待記憶體,因為這與我們進行惡意軟體的逆向工程更相關。

An image showing memory layout including stack, heap, code, and data

這裡的圖表是一個程式的典型記憶體佈局的概述。可以看到,記憶體分為不同的部分,即棧、堆、程式碼和資料。雖然我們已經以特定的順序展示了這四個部分,但這可能與它們在任何時候的順序不同,例如,程式碼部分可以位於資料部分之下。

我們可以在下面找到這四個部分的簡要概述。

Code程式碼:

程式碼部分,顧名思義,包含程式的程式碼。具體來說,本節指的是可移植可執行檔案中的text部分,其中包括CPU執行的指令。這部分記憶體具有執行許可權,這意味著CPU可以執行程式記憶體中的這部分資料。

Data資料:

Data部分包含了已初始化的資料,這些資料不是變數,而是常量。它指的是可移植可執行檔案中的data部分。它通常包含全域性變數和其他在程式執行期間不應該改變的資料。

Heap堆:

堆,也稱為動態記憶體,包含了程式執行過程中建立和銷燬的變數和資料。建立變數時,會在執行時為該變數分配記憶體。當該變數被刪除時,記憶體被釋放。因此命名為動態記憶體。

Stack棧:

從惡意軟體分析的角度來看,棧是記憶體的重要組成部分之一。這部分記憶體包含區域性變數、傳遞給程式的引數,以及呼叫該程式的父程序的返回地址。由於返回地址與CPU指令的控制流相關,棧經常成為惡意軟體劫持控制流的目標。您可以檢視緩衝區溢位空間來了解這是如何發生的。我們將在下一個任務中介紹有關棧的更多細節。

問題

1.當程式載入到記憶體中時,它是否有系統記憶體的完整檢視?

2.記憶體中的哪一部分包含程式碼?

3.哪個記憶體部分包含與程式控制流相關的資訊?

WP

1.當程式載入到記憶體中時,它沒有系統記憶體的完整檢視

2.記憶體中的Code部分包含程式碼

3.記憶體Stack部分包含與程式控制流相關的資訊

image-20240810234913386

堆疊的佈局

棧是程式記憶體的一部分,其中包含傳遞給程式的引數、區域性變數和程式的控制流。這使得該棧在惡意軟體分析和逆向工程方面非常重要。惡意軟體經常利用棧劫持程式的控制流。因此,理解棧、它的佈局及其工作方式非常重要。

棧是後進先出(LIFO)記憶體。這意味著最後壓入棧的元素是第一個彈出的元素。例如,如果我們將A、B和C壓入棧中,當我們彈出這些元素時,第一個彈出的將是C,然後才是B和A。CPU使用兩個暫存器來跟蹤堆疊。一個是棧指標(ESP或RSP),另一個是基指標(EBP或RBP)。

An image of the stack layout including local variables, Stack Pointer, Base Pointer, Return address, and Arguments, in reference to the memory address space

The Stack Pointer棧指標:

棧指標指向棧的頂部。當有新元素被壓入棧時,棧指標的位置會改變,以考慮剛被壓入棧的新元素。類似地,當一個元素從棧彈出時,棧指標會調整自己以反映這一變化。

The Base Pointer基指標:

任何程式的基指標都是不變的。這是當前程式棧跟蹤其區域性變數和引數的引用地址

Old Base Pointer and Return Address舊基指標和返回地址:

基指標下面是呼叫程式(呼叫當前程式的程式)的舊基指標。在舊基指標下面是返回地址,即當前程式執行結束後,指令指標將返回的地址。

劫持控制流的一種常見技術是溢位棧上的區域性變數(Local Var),從而用惡意軟體作者選擇的地址覆蓋返回地址。這種技術稱為棧緩衝區溢位(Stack Buffer Overflow)。

Arguments引數:

傳遞給函式的引數在函式開始執行之前被壓入棧。這些引數就在棧上的返回地址下面。

函式序言和尾聲:

當函式被呼叫時,棧已經為函式的執行做好了準備。這意味著引數在函式開始執行之前被壓入棧。之後,返回地址和舊基指標被壓入棧。一旦這些元素被壓入,基指標的地址就會改變到棧的頂部(此時將是呼叫函式的棧指標)。在函式執行時,棧指標會根據函式的需求移動。這部分程式碼將引數、返回地址和基指標壓入棧中,並重新排列棧和基指標,這部分程式碼稱為函式序言。

類似地,當函式退出時,舊的基指標從棧彈出到基指標上。返回地址彈出到指令指標,棧指標重新排列,指向棧頂。執行該操作的程式碼部分稱為函式尾聲(Function Epilogue)。

點選任務頂部的View Site按鈕,在分屏檢視中啟動靜態站點。現在,跳到附加的靜態站點並透過正確地排列堆疊找到標誌。

問題

按照附接的靜態站點中的說明找到flag

WP

開啟網址啟動靜態站點

image-20240811005131908

image-20240811005308778

按照順序排列即可得到flag

image-20240811005240805

相關文章