這篇文章是在讀書時做出一些整理與想法,之後也可以快速複習。所以些許略過基礎的部分。如文中有錯誤敬請指正。
書籍 : Windows-APT-Warfare
開源程式碼 : https://github.com/aaaddress1/Windows-APT-Warfare
聲明 : 本文使用書中程式碼作為研究對象, 並接受 GNU 3.0 授權條款。
在上一篇我們講述了一份 PE 檔是如何生成的,現在來看看這份 PE 檔裡面裝著甚麼東西,並寫一份 C project 來解析 PE 檔。
在開始前建議讀者可以使用下列工具來解析你的 PE 檔,以此加深印象。
PE BEAR
PE檔解析
我們先上一份看起來很簡單的表
這四個區塊代表著在 PE 檔中的內容分區。而不同的區塊有不同功能,存放各自任務需要的資料。
1. DOS Header : 開頭有一個校驗碼。在 windows NT 架構中大多數欄位用不到了,但是裡面有放 NT Header 的起點位置偏移量 ( 工具人的概念 )。
2. NT Header : 開頭也有一個校驗碼。可以再分成 File header 跟 Optional header,裡面放著要裝載程式所需要的準備與檔案資料。
3. Section Header : 標示出 DATA 部分的資訊,讓編譯器可以知道資料有幾個區塊與資料的位置在哪裡。
4. Section Data : 這邊放著我們寫的資料,像是 .text .data .idata 等等的。
好,現在讓他現出原形。
雖然看起來很複雜,但不過就是上面那幾個區塊的內容,我們來看這些區塊的內容有甚麼含意。
DOS Header
這個部分一開始會有一個校驗碼 ( Magic number ) ,一定會是 4D 5A 00 00 ( M Z 0 0 )。
然後中間這些不用管,那個現在不重要。
其實 Windows NT 之前 Win 是基於 DOS系統,為了向前兼容所以才保留這個格式。
然後在 0x3C 的位置有標示 NT Header 的位置( RVA ),依據這個位置就可以找到 NT Header。
看看在 winnt.h 中這個結構長甚麼樣
裡面的 e_magic 是校驗碼,e_lfanew 是 NT Header RVA 位置要記起來。
NT Header
這個部分一開始也會有一個校驗碼,一定會是 50 45 00 00 ( P E 0 0 )。
裡面三個物件 : 校驗碼、FileHeader、OptionalHeader。
NT Header 的 File Header
這個部分在生成 COFF 檔案時就出現了,記錄編譯時的訊息。
其中這些的意思 :
Machine 機械碼類型,像我是 8664 對應 AMD64
NumberOfSections 代表 Section 中有幾個塊狀區塊
TimeDateStamp 編譯時的時間
SizeOfOptionalHeader 就是 OptionHeader 的大小
Characteristics 紀錄 PE 模組屬性,可以透過 value 來得知意義
NT Header 的 Optional Header
包含連接器補上的紀錄資訊,使 application loader 可以正確裝載程式
有夠長,列出重要的部分 :
ImageBase : PE model 應該要被寫在哪個位置上
Size of Image : 這程式要申請多大的記憶體
SizeOfHeaders : [DOS + NT + Selection] header 有多大
AddressOfEntryPoint : 傑哥程式進入點
SectionAlignment : 動態區段對齊大小
FileAlignment : 靜態區段對齊大小
DataDirectory : 這是一個 list , 紀錄 15 種可能需要的資料的起始與大小。
附上他的結構
NT Header 到這邊結束,接下來是 Section。
Section Header
在編譯時編譯器把程式碼轉成很多塊,為了記錄這些塊狀資料的位置資訊所以有了 Section Header。
看起來很容易理解。首先可以看到很多個區塊,這些區塊的數量在 NT Header -> FileHeader -> NumberOfSections 可以得到。
PointerToRawData : 這個 Block 在靜態檔案的偏移量
SizeOfRawData : Block 所使用的空間
VirtualAddress : 寫入 Image base 的偏移量,也就是 page 中的 Offset。
VirtualSize : 動態空間所需要分配的空間
Characteristics : 紀錄空間在編譯時該區段的使用權利 ( 讀 / 寫 / 執行 )。
PE_Parser PE解析器
在學到 PE 中的內容後,來寫一個自己的 PE解析器吧。
程式連接
1. 讀入檔案
使用參數的方式得到目標檔案的位置,然後讀入檔案。
2. 取得檔案的大小、內容。
可以用 fseek 來操縱指標位置來取得文件大小。
3. 進入重點
建立兩個指標指向 Header,這些物件定義包含在 <winnt.h> ( 使用 <windows.h> 就含在裡面了 )。
DOS Header 的位置就是檔案的位置。
NT Header 的位置偏移量包含在 DOS Header 的 0x3C 位置,位在結構中 .e_lfanew。
所以實際位置是 DOS Header 的位置加上偏移量。
4. 檢查是否正確
可以利用魔術碼來確定 Header 是否正確。
各自的常數應為 IMAGE_DOS_SIGNATURE 跟 IMAGE_NT_SIGNATURE
5. Option Header
當有了 NT Header 後,就可以透過她來取得裡面的 File 跟 Option Header。
由於 File Header 跟 Option Header 操作差不多,這邊演示 Option Header。
然後就可以存取 Header 裡面的資料並輸出。
6. 輸出 Section Header 所有區塊
因為 Section Header 會緊連在 NT Header 之後,所以它的位置就是 NT Header + sizeof( NT Header )
然後就要來遍歷 Section 中的區塊資料。區塊數量是 NT Header 中的 NumberOfSections,就可以由 0 遍歷到最後區塊。
大功告成,那會了這些可以做甚麼呢?
這些知識是逆向工程的基礎,可以透過 PE 解析來得知這份檔案想做甚麼,判定是不是想壞壞。
或許...我們也可以在這些 PE 檔上面搞事?
這篇就到這邊。
最近畢業專題要進入整合期。醫院系統跟實驗室的連線穩定度很差,還有教授回國就聯絡不到了,笑死。