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. 結構體也是線性型式表示
LM
ReplyDelete