文章目錄
- 一.什麼叫PE檔案
- 1.位址
- 1.1虛拟記憶體位址:
- 1.2相對虛拟記憶體位址:
- 1.3檔案偏移位址:
- 1.4特殊位址:
- 2.指針
- 3.資料目錄
- 4.節
- 5.對齊
- 6.Unicode字元串
- 二.PE檔案的結構
- 1. DOS頭
- 2. PE頭
- 2.1 第一部分:PE頭辨別Signature
- 2.2 第二部分:标準PE頭IMAGE_FILE_HEADER
- 2.3 第三部分:擴充PE頭,IMAGE_OPTIONAL_HEADER32
- 2.4 PE頭中的資料目錄項:IMAGE_DATA_DIRECTORY
- 3 節表項IMAGE_SECTION_HEADER
- 4 節内容(區塊)
一.什麼叫PE檔案
PE (Portable Executeable File Format,可移植的執行體檔案格式),使用該格式的目的是使連接配接生成的EXE檔案能在不同的CPU指令下工作。
Windows中可執行程式有很多種,COM,PIF,SCR,EXE等,這些檔案的格式大部分都繼承于PE。其中EXE是最常見的PE檔案,動态連結庫(大部分以dll為擴充名的檔案)也是PE檔案。
在了解PE檔案格式之前,我們需要學習一下于PE檔案相關的幾個概念
- 位址
- 指針
- 資料目錄
- 節
- 對齊
1.位址
- 虛拟記憶體位址(VA)
- 相對虛拟記憶體位址(RVA)
- 檔案偏移位址(FOA)
- 特殊位址
1.1虛拟記憶體位址:
PE檔案被作業系統加載進記憶體以後,PE對應的程序配置設定了自己獨立4GB虛拟空間,這個空間中地位的位址稱為虛拟記憶體位址(VA),是以虛拟記憶體位址的範圍是 00000000h~ 0fffffffh。在PE中,程序本身的VA被解釋為:程序的基位址+相對虛拟記憶體位址 VA = IMAGE_BASE_ADDRESS + RVA
1.2相對虛拟記憶體位址:
一個程序被作業系統加載到虛拟記憶體空間後,相關的dll也會被加載,加載到記憶體空間的檔案稱為子產品,每一格子產品在加載時都會有一個基位址,也就是告訴作業系統,從哪裡開始存儲該子產品。
RVA于具體的子產品相關,它有一個範圍,此範圍從子產品的開始到結束,脫離這個範圍 RVA是無效無意義的,稱為越界。
RVA是相對子產品而言,VA是相對整個位址空間而言
1.3檔案偏移位址:
與檔案有關與記憶體無關,指某個位置距離檔案頭的偏移
1.4特殊位址:
從某個特定的位置開始算起的特殊情況
2.指針
與C語言中的指針定義類似
3.資料目錄
PE中有一種資料結構稱為資料目錄,其中記錄了所有可能的資料類型,這些類型包括:導出表,導入表,資源表,異常表,屬性證書表,重定位表,調試資料,Architecture,Global Ptr,線程局部儲存,加載配置表,綁定導入表,IAT,延遲導入表,CLR運作時頭部
4.節
節就是存放不同資料類型的地方,不同的節具有不同的通路限權,解釋PE檔案種存放代碼或資料的基本單元。如彙編中的,.data .code僞指令。
5.對齊
- 記憶體對齊
- 檔案對齊
- 資源資料對齊
6.Unicode字元串
unicode 是繼阿斯克碼後的另一種新型字元編碼,ASCII碼每個字元用7位表示,Unicode則使用16位表示一個字元,是以又稱為寬字元串
二.PE檔案的結構
PE檔案,我們可以将其了解為“頭”+“身體”式結構
以32位系統的PE結構為例
1. DOS頭
所有的PE檔案都是以一個64位元組的DOS頭開始。這個DOS頭隻是為了相容早期的DOS作業系統。
typedef struct IMAGE_DOS_HEADER{
WORD e_magic;
WORD e_cblp;
WORD e_cp;
WORD e_crlc;
WORD e_cparhdr;
WORD e_minalloc;
WORD e_maxalloc;
WORD e_ss;
WORD e_sp;
WORD e_csum;
WORD e_ip;
WORD e_cs;
WORD e_lfarlc;
WORD e_ovno;
WORD e_res[4];
WORD e_oemid;
WORD e_oeminfo;
WORD e_res2[10];
DWORD e_lfanew;
}IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
DOS頭共64個位元組
- e_magic:判斷一個檔案是不是PE檔案
- e_lfanew:相對與檔案首的偏移量,常用于定位PE頭位置
PE頭的絕對位置定位:
PE_start = DOS MZ 基位址 + IMAGE_DOS_HEADER.e_lfanew。
PE檔案頭部=DOS頭+PE頭+節表
PE檔案身體=節内容。
2. PE頭
IMAGE_NT_HEADERS
這個結構是廣義上的PE頭,在标準的PE檔案中,其大小為456個位元組,是接下來三個小節提到的資料結構的組合
PE頭的資料結構被定義為IMAGE_NT_HEADERS。包含三部分,其結構如下:
typedef struct IMAGE_NT_HEADERS{
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
}IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
2.1 第一部分:PE頭辨別Signature
緊跟在DOS Stub之後,與大部分檔案格式的頭部結果一樣,PE頭部中有一個四位元組的辨別,該辨別位于指針IMAGE_DOS_HEADER.e_lfanew指向的内同。其内容固定,對應于ASCII碼的字元串“PE\0\0”。
2.2 第二部分:标準PE頭IMAGE_FILE_HEADER
标準PE頭,IMAGE_FILE_HEADER緊跟在PE頭辨別之後,記錄了PE檔案的全局屬性,常用于判斷此PE檔案時exe類型還是dll類型
2.3 第三部分:擴充PE頭,IMAGE_OPTIONAL_HEADER32
檔案執行是的入口位址,檔案被作業系統裝入到記憶體後的預設基位址,以及節在磁盤和記憶體中的對齊機關等資訊都可以在此結構中找到,其内容比标準PE頭還要多,對于該結果中的某些數值的改動可能導緻PE檔案加載或運作失敗
2.4 PE頭中的資料目錄項:IMAGE_DATA_DIRECTORY
該字段定義了PE檔案中所有不同類型資料的目錄資訊
IMAGE_DATA_DIRECTORY STRUCT
VirtualAddress DWORD ?;
isize DWARD ?;
IMAGE_DATA_DIRECTOR ENDS
兩個字段依次為VirtualAddress和isize
3 節表項IMAGE_SECTION_HEADER
PE頭的IMAGE_NT_HEADER後緊跟着節表,有許多個節表項組成,節表項的資料結構詳細如下,每個節的結構也是類似于“頭”+“身體”結構,節表項就是這個結構的“頭”
IMAGE_SECTION_HEADER
Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?);
union Misc
PhysicalAddress dd ?;
VirtualSize dd ?;
ends
VirtualAddress dd ?; //節内容的RVA
SizeofRawData dd ?; //節内容檔案中對齊後的大小
PointerToRawData dd ?; //在檔案中的偏移
PointerToRelocations dd ?;
PointerToLinenumbers dd ?;
NumberOfRelocations dw ?;
NumberOfLinenumbers dw ?;
Characteristics dd ?; //區塊屬性,如可讀,可寫,可執行等
IMAGE_SECTION_HEADER ENDS
注:IMAGE_OPTION_HEADER32.AddressOfEntryPoint
雙字,該字段的值是一個RVA,他記錄了啟動代碼距離該PE加載後的起始位置到底有多少個位元組,我們可以修改這裡的值,使之指向自己代碼的位置,然後…進行一些操作,然後繼續跳轉執行原來的代碼。
許多病毒程式,加密程式,更新檔程式都是用的這個法子
4 節内容(區塊)
名稱 | 描述 |
.text | 預設的代碼區域,内容全是指令代碼 |
.data | 預設的讀/寫資料塊,全局變量,靜态變量一般存在這個區域 |
.rdata | 預設隻讀資料塊 |
.idata | 包含其他外來的DLL的函數及資料資訊,即輸入表 |
.edata | 輸出表,當建立一個輸出API或資料的可執行檔案時,連接配接器會建立一個.EXP檔案,這個.EXP檔案會包含一個.edata區塊,其會被加載到可執行檔案中,經常被合并到.text或.rdate區域中 |
.rsrc | 資源,包括子產品的全部資源,圖示,菜單,位圖 |
.bss | 未初始化的資料 |
.crt | 用于C++運作時(CRT)所添加的資料 |
.tls | 線程局部儲存器 |
.reloc | 可執行檔案的機制重定位 |
.sdate | 相對于全局指針的可被定位的,短的讀寫資料 |
.pdata | 異常表 |