一般我們看到的Windows操作系統,都是在User Mode底下的
相對的,在我們看不到的底層系統運作稱為Kernel Mode
如下,每個程式可以稱之為Process,Process範圍包含User Mode/Kernel Mode
當每個Process執行時,以32位元系統來說會被分配4GB的Ram給Porcess (User/Kernel 各2GB)
64位元則是分配8/248 TB
32位元 | 64位元 | |
---|---|---|
User Mode Address | 0 - 0x7fff ffff | 0 - 0x7ff ffff ffff |
Kernel Mode Address | 0x8000 0000 - 0xffff ffff | 0xffff 0800 0000 0000 - 0xffff ffff ffff ffff |
電腦真的有這麼大的 RAM???
沒有,32位元為例,User Mode中的這2GB是虛擬的,並不會真正佔用這麼多,而Kernel mode是所有processes共用2GB的記憶體
…
主要提的會以User Mode為主
PE: Portable Executable,常見的exe檔案是PE, DLL(待會會提到)也是PE的一種
有自己特別一套架構,跟依照的規範
既然目標是做逆向工程,所以得了解一下PE檔案的架構
針對PE檔案,可以用PE View/CFF Exploror等工具來觀測裡面的資料
在惡意程式分析的時候,常常會遇到一種狀況
攻擊者在一個PE檔案裏面嵌入了另一個PE檔案,等待主檔案執行後釋放出內嵌的exe檔案
下列的特殊字元能幫助識別是否有新的內嵌PE檔案出現在Memory/檔案之中,稱之為Magic byte
DOS Header: 0 -> 5A 4D (MZ - Little Endian)
PE Offset: 0x3C -> 0xF0
再強調一次,這些是微軟定義的
0xF0的Offset -> 45 50 (PE - little endian)
PE檔案當然會帶有更多的東西,包含以下,我們用section來區隔,每個section有不同的功用
.text: 程式碼
.idata: import library列表
.edata: export library列表
.data: Global variable
.rsrc: 程式需要的額外資源
來看看人家WannaCry的資源放了什麼
MZ?? PE???(圖中A4 A5, 19C 19D)
裡頭塞個PE檔
承一開始所說的虛擬位址概念(User Mode 2GB),PE檔案裡面也會標示Sections對應到Virtual Memory的位址
大概是這樣子
再對照一次
Virtual Size: 程式執行放到memory大小,在Debugger裡面也會看到一樣大小
Virtual Address: 在Debugger中,距離Base Address的Offset
Raw Size: PE檔案該Section真實大小
Raw Address: PE檔案該Section的Offset
DLL: 純Library,無法點兩下就自己跑
EXE: 執行檔,會需要DLL的幫忙來執行各種功能
一般想要執行程式如小算盤,通常就是點兩下然後小算盤就出現了
你可以做加加減減,可是,實際到底做了些甚麼事情呢?
一開始的小算盤可能是用C++編寫,經過compile(編譯)之後,會變成shellcode(機械碼)的形式,其實就是hex number
剛剛看到了每個程式,包含小算盤都會有.text
section,儲存程式碼的section,裡面儲存就是很多的Hex number format
當程式開始執行後,CPU會解讀.text
的這些Hex number,搭配對應的指令集去做運算
但是人類無法看懂Hex number,所以需要使用Disassembly等工具,將Hex number轉譯成看得懂的assembly code(組合語言)
為何需要Register?
程式執行時,假設2+3
2跟3都要存在某個地方,讓CPU來相加,暫存2,3的地方就是暫存器
長度 (RBX/RCX/RDX也可套用)
在程式執行時,除了Register之外,還有一個叫Flag的東西紀錄程式的狀態
單純依賴Register做程式計算資料的暫存是不夠的
Windows引進了Stack的概念,stack其實只是一塊記憶體,供程式隨時取用
他的特性以其取用方法如下
雖然假設看本系列的人有一定組合語言基礎,但還是介紹一下常見到的指令以及概念
程式透過編譯器,變成機械碼(真正儲存在執行黨內的東西)
分析師透過反彙編器(IDA/GDB..)打開,看到的是組合語言
機械碼 VS 組合語言
一些常見組合語言,以32位元,intel架構為例
在組合語言中,與一般寫程式無異,都需要有function的存在來幫助程式做重複性的工作
有function就必定會有argument要傳進子function,但是32/64位元的方法有點不一樣
32位元:利用Stack保存進入Function
64位元:主要利用Register保存 RCX, RDX, R8, R9, Stack
return value: RAX/EAX
下列是個32位元小程式,以及他對應的assembly
Example stack layout
重點:
確保Stack用完後,ESP/EBP回到原本值
Stack被使用後並不需要清除成0
64位元的傳值方法不是透過push/pop,而是透過register
還是沒有看懂?
沒關係,這邊有30cm大神的文章 更多資源
更多資訊可以從秋聲大神的書找到,相當推薦
至於識別一些常見的C語言結構,也可以參考 惡意代碼分析實戰 第六章
上述的大概就是要進入逆向工程的一些前置知識,下一篇會介紹在開始分析惡意程式之前所需要的環境
Malware Analysis
Reverse Engineering
tutorials