Window安全之PE結構(一)詳解DOS頭
PE文件(*.exe/ *.sys / *.dll)
PE文件是在WINDOWS平台下一個十分重要的數據結構,在本地較小此類文檔,特此記錄一下
PE32 是WINDOWS 32BIT下的PE格式
PE32+ 是WINDOWS 64BIT下的PE格式
不過64BIT與32BIT的分別只在於把原本32位的值改為64位而已
為了對齊所有段,實現內存分頁機制 PE加載器 會把 PE文件由硬盤映射到內存(要注意的是在每段之間 相距512字節(byte),4096字節(byte) = 4KB)
內存分頁機制 主要由於磁盤與內存的傳輸單位以頁為主。
PE文件到內存的映射
CPU不會直接從硬盤讀取數據, 而是從物理內存讀取數據, 因此PE文件需要映射到內存供CPU執行
WINDOWS不會一次把整個PE文件映射到內存
CPU需要讀到什麼資源,才從磁盤提交到物理內存
映射後完全相同
預處理 重定位
PE格式大致分為以下段落:
基本名詞:
Imagebase // 表示PE文件加載後的原始地址 加載器會首先嘗試加載到0X40000000H地址
// 可以透過GetModuleHandle(LPCTSTR lp)獲取地址,該參數為路徑
VA //虛擬地址(Virtual address) 在PE文件加載後的4GB虛擬內存的任意地址
RVA //相對偏移地址(relative virtual address) 由任一虛擬地址與ImageBase 之差
//RVA = VA - ImageBase
留意:
DWORD 是四個字節(4Byte)
WORD 是兩個字節(2Byte)
WORD e_magic // "MZ" DOS頭特微碼 ,4D5Ah (h為16進制表示) , 在記憶體中代表該PE文件的DOS頭部;
WORD e_lfanew // NT_HEADER基地址的偏移量, 加載後存放在DOS頭後的0x00000003Ch位置
Address of PE_HEADER = Imagebase+e_lfanew // 由於PE文件在加載後,東西是以線性形式保存在4GB虛擬地址中,因此要把基址(ImageBase)加上偏移量 得出PE_HEADER的地址
----------------------------------------------------------------------------------------------------------
順著記憶體下去接著的結構就是 IMAGE_NT_HEADER
AddressOfEntryPoint 字段 - 這是一個RVA, 如果需要附加一個代碼 只需要修改這個入口地址 指向附加代碼 就可以改變了;
ImageBase - DLL與EXE不同 EXE每個文件都有獨立的4GB虛擬空間, 不需要重定位(Relocation) 因為EXE類的PE文件都是有獨立的空間, 但DLL就需要重定位, 因為不可能確保每
一次在4GB內的虛擬地址 沒有被其他人所佔用, 一般exe文件預設加載地址為00400000h,dll文件預設為10000000h
SectionAlignment 和 FileAlignment
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 存放十六個重要地址的數組 當我們需要在exe檔中獲取任何信息 在這個數組裡可獲取基址
DataDirectory[0] - 導出表 (Export Address Table,EAT) //把函數導出給其他程序使用
DataDirectory[1] - 導入表 (Import Address Table,IAT) //把外面函數導入自身程序使用
DataDirectory[5] - 重定位表 (IMAGE_DIRECTORY_ENTRY_RELOCATION)
說了一大堆的理論,定義和機制... 還是隨手找個Firefox.exe來證實一下以後的章節也使用Firefox.exe作為例子...
幾個重點
1. 4D5AH 作為整個PE文件最先加載的內容,為MZ 即DOS頭
2. 在0x0000003C中(這是一定)存放了NT_HEADER的RVA(相對地址)
3. 結構體也是線性型式表示
PE文件是在WINDOWS平台下一個十分重要的數據結構,在本地較小此類文檔,特此記錄一下
PE32 是WINDOWS 32BIT下的PE格式
PE32+ 是WINDOWS 64BIT下的PE格式
不過64BIT與32BIT的分別只在於把原本32位的值改為64位而已
為了對齊所有段,實現內存分頁機制 PE加載器 會把 PE文件由硬盤映射到內存(要注意的是在每段之間 相距512字節(byte),4096字節(byte) = 4KB)
內存分頁機制 主要由於磁盤與內存的傳輸單位以頁為主。
PE文件到內存的映射
CPU不會直接從硬盤讀取數據, 而是從物理內存讀取數據, 因此PE文件需要映射到內存供CPU執行
WINDOWS不會一次把整個PE文件映射到內存
CPU需要讀到什麼資源,才從磁盤提交到物理內存
映射後完全相同
預處理 重定位
PE格式大致分為以下段落:
基本名詞:
Imagebase // 表示PE文件加載後的原始地址 加載器會首先嘗試加載到0X40000000H地址
// 可以透過GetModuleHandle(LPCTSTR lp)獲取地址,該參數為路徑
VA //虛擬地址(Virtual address) 在PE文件加載後的4GB虛擬內存的任意地址
RVA //相對偏移地址(relative virtual address) 由任一虛擬地址與ImageBase 之差
//RVA = VA - ImageBase
留意:
DWORD 是四個字節(4Byte)
WORD 是兩個字節(2Byte)
//DOS頭, 不是全部定義也需要理會, 需要留意的只有兩個成員變量
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
0 WORD e_magic; // Magic number
2 WORD e_cblp; // Bytes on last page of file
4 WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
24 WORD e_oemid; // OEM identifier (for e_oeminfo)
26 WORD e_oeminfo; // OEM information; e_oemid specific
28 WORD e_res2[10]; // Reserved words
3c LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
在此IMAGE_DOS_HEADER,不是所有成員變量都重要
WORD e_magic // "MZ" DOS頭特微碼 ,4D5Ah (h為16進制表示) , 在記憶體中代表該PE文件的DOS頭部;
WORD e_lfanew // NT_HEADER基地址的偏移量, 加載後存放在DOS頭後的0x00000003Ch位置
Address of PE_HEADER = Imagebase+e_lfanew // 由於PE文件在加載後,東西是以線性形式保存在4GB虛擬地址中,因此要把基址(ImageBase)加上偏移量 得出PE_HEADER的地址
----------------------------------------------------------------------------------------------------------
順著記憶體下去接著的結構就是 IMAGE_NT_HEADER
IMAGE_NT_HEADER STRUCT{
DWORD Signature // "PE00" NT頭特微碼, 50 45 00 00
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader ;
}
IMAGE_FILE_HEADER{
WORD Machine; //運行平台, 目標CPU類型 X86,X64...等等
WORD NumberOfSection; //文件的區塊數目(區塊表是緊接著IMAGE_NT_HEADER後面的)
DWORD TimeDateStamp; //文件創建時間和日期
DWORD PointerToSymbolTable; //指向符向表(主要用於調試)
DWORD NumberOfSymbols; //符號總數(同於調試)
WORD SizeOfOptionalHeader; //IMAGE_OPTIONAL_HEADER32 結構大小
WORD Characteristics; //文件屬性
}IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER32
{
+10h WORD Magic; //標志號 ROM映像 (0107H) 普通可執行文件(010BH)
+1Ah BYTE MajorLinkerVersion; //連接器版本號
+1Bh BYTE MinorLinkerVersion; //連接器次版本號
+1Ch DWORD SizeOfCode; //所有代碼的節的總大小
+20h DWORD SizeOfInitializedData; //所有已初始化的數據的節的總大小
+24h DWORD SizeOfUninitializedData; //所有未被初始化的節的大小
+28h DWORD AddressOfEntryPoint; //程序執行入口RVA
DWORD BaseOfCode; //代碼的區塊的起始RVA
DWORD BaseOfData; //數據的區塊的起始RVA
// NT 外加的領域
DWORD ImageBase; //程序優先的裝載基址
DWORD SectionAlignment; // 內存中的區塊的對齊大小
DWORD FileAlignment; //文件中的區塊的對齊大小
WORD MajorOperatingSystemVersion; //OS版本號
WORD MinorOperatingSystemVersion; //OS2之版本號
DWORD SizeOfImage ; //映像裝入內存後的呎寸
DWORD SizeOfHeaders; //所有頭+區塊表的呎寸大小
DWORD CheckSum; //映像的校驗和
WORD Subsystem; //可執行文件期望的子系統
WORD DllCharacteristics; //默認為0 DLLmain函數何時被調用
DWORD SizeOfStackReserve; //初始化時的Stack大小
DWORD SizeOfStackCommit; //初始化時實際提交的Stack大小
DWORD SizeOfHeapReserve; //初始化時Heap大小
DWORD SizeOfHeapCommit; //初始化時實際提交的Heap大小
DWORD LoaderFlags; //與調試有關 默認為0
DWORD NumberOfRvaAndSizes; //下邊數據目錄的項數 這個字段自win NT發布一直留為16
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; //十分重要的一個成員變量
}IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
AddressOfEntryPoint 字段 - 這是一個RVA, 如果需要附加一個代碼 只需要修改這個入口地址 指向附加代碼 就可以改變了;
ImageBase - DLL與EXE不同 EXE每個文件都有獨立的4GB虛擬空間, 不需要重定位(Relocation) 因為EXE類的PE文件都是有獨立的空間, 但DLL就需要重定位, 因為不可能確保每
一次在4GB內的虛擬地址 沒有被其他人所佔用, 一般exe文件預設加載地址為00400000h,dll文件預設為10000000h
SectionAlignment 和 FileAlignment
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 存放十六個重要地址的數組 當我們需要在exe檔中獲取任何信息 在這個數組裡可獲取基址
DataDirectory[0] - 導出表 (Export Address Table,EAT) //把函數導出給其他程序使用
DataDirectory[1] - 導入表 (Import Address Table,IAT) //把外面函數導入自身程序使用
DataDirectory[5] - 重定位表 (IMAGE_DIRECTORY_ENTRY_RELOCATION)
IMAGE_DATA_DIRECTORY {
VirtualAddress DWORD ?, RVA
iszie DWORD?, 長度
}
說了一大堆的理論,定義和機制... 還是隨手找個Firefox.exe來證實一下以後的章節也使用Firefox.exe作為例子...
幾個重點
1. 4D5AH 作為整個PE文件最先加載的內容,為MZ 即DOS頭
2. 在0x0000003C中(這是一定)存放了NT_HEADER的RVA(相對地址)
3. 結構體也是線性型式表示
.gif)

LM
ReplyDelete