這篇文章是在讀書時做出一些整理與想法,之後也可以快速複習。所以些許略過基礎的部分。如文中有錯誤敬請指正。
書籍 : Windows-APT-Warfare
開源程式碼 : https://github.com/aaaddress1/Windows-APT-Warfare
聲明 : 本文使用書中程式碼作為研究對象, 並接受 GNU 3.0 授權條款。
這章需要用到一些基本 OS 與 計算機組織理論 ,不會太難。
先來看看我最可愛的 ななひら <3
這模型還在設計中,之後會更漂亮
程式之路
我們都學過程序語言分成高階語言、組合語言、指令碼等等的,當一份高階語言要執行時,就會透過一系列步驟變成指令碼,再經過指令週期後就能達成我們的任務。
用 C 程式簡略做為示範 :
```
#include <windows.h>
int main()
{
MessageBoxA(0,"hello world","title",0);
return 0;
}
```
這個程序會生出一個寫 hello world 的視窗。
然後 IDE 會根據 calling convention 來生成一段組合語言 :
```
;caller 將參數推入記憶體
push 0
push "title"
push "hello world"
push 0
;callee 調用這個函數對記憶體回收
call MassageBoxA
mov eax,0
ret
```
太好了,我們把他轉成機器碼前做幾件事來封裝他 :
1. 把字串存起來,放到 .rdata ( 唯獨資料 )
title -> 6 byte 放到 .rdata + 0
hello world ->12 byte 放到 .rdata +6
2. MassageBoxA 這東西晶片看不懂在哪裡,所以放入 .idata ( Import Address Table)
註 : 有些 IDE 會把這放到 .rdata ,所以也不一定
3. 把程式碼放入 .text
然後幾點要注意的 :
+ 程式不只包含一個 PE model ,所以掛載的 process 都依 PE 格式封裝
+ 裝上的 model 會有一個 image base ( 跟 virtual address 很像 ),指向該 model 內容
+ x32 的 image base 通常是 0x400000
然後把這些轉換成機器碼,這部分好麻煩,有興趣可以看白算盤跟MIPS指令集來算算看。
結果如下 ( 須注意 Little / Big endian ) :
然後把它組譯成 COFF 格式,就是組譯器生產的封裝檔案。
執行 g++ -c main.cpp 生成 main.o ( 他就是COFF格式 )
用 PEview 看它的結構
然後透過 linker 為這個 COFF登dua郎,就變成 EXE程式了
我們來看看 登dua郎 linking loader 中會用到的步驟 :
+ Binding ( 決定 Process 起始位置 ),而在 linker loader 時做 Binding 產生出 obj 的稱為 "relocatable object file"
+ linker 把必要資料依 PE 格式寫入 OptionalHeader
+ 向 OS 要求起始位置
+ 依 Complier 交辦 linking 修正資訊做出 linking 修正
+ Relocation 修正
等等步驟。
我們剛剛做的事可以用下圖來整理。
延伸 : 假如你在 Compiling time 做 Binding ( 通常用於 com 命令檔 )則如下
太棒了,你現在有了一份 EXE 檔案了 OwO/
當你運行這個 EXE 時,就會由靜態檔案變成 process
那運行時發生了甚麼呢?
比如說我在 cmd.exe 輸入 msgbox.exe,會發生以下步驟
1. 父程序 cmd.exe 發出 system call 請求子程序
2. 到 kernel mode 。OS 生成 Thread 給子程序,並在 userland 紀錄 PEB ( Process environment block ) 跟 TEB ( Thread environment block )。
3. 到 user mode 。然後對 Thread 初始化,這部分好複雜不太懂,大概是把 PE 裝到 memory 還有 PE model 修正。
4. application loader 修正完後把 EIP 送到 Entry point ,開始程序。
整理就到這邊,下一章來解析 PE 靜態內容。