PE文件結構綜覽:程序員
首先上圖片:windows
看到上面的圖片能夠清晰的看到PE結構複雜結構式什麼樣子的。有DOS首部,PE頭部,PE節表,不少的表塊,最後就是一些調試信息。數據結構
DOS頭由DOS 'MZ' HEADER 和DOS stub組成,DOS "MZ"頭中的MZ是PE文件的一個標誌之一。後期咱們在寫PE小工具的時候這個會被咱們用於去識別PE文件。ide
首先咱們來理解DOS頭。咱們知道Windows系統主體是由C去完成的。全部咱們能夠在windows中去找到用C描述的DOS頭結構。工具
DOS頭分析:spa
第一個就是WinNT.h在我計算機中位置。打開後咱們就能看到咱們想要的DOS頭數據結構了。3d
1 typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header 2 +0 WORD e_magic; // Magic number 3 +2 WORD e_cblp; // Bytes on last page of file 4 +4 WORD e_cp; // Pages in file 5 +6 WORD e_crlc; // Relocations 6 +8 WORD e_cparhdr; // Size of header in paragraphs 7 +A WORD e_minalloc; // Minimum extra paragraphs needed 8 +C WORD e_maxalloc; // Maximum extra paragraphs needed 9 +E WORD e_ss; // Initial (relative) SS value 10 +10 WORD e_sp; // Initial SP value 11 +12 WORD e_csum; // Checksum 12 +14 WORD e_ip; // Initial IP value 13 +16 WORD e_cs; // Initial (relative) CS value 14 +18 WORD e_lfarlc; // File address of relocation table 15 +1A WORD e_ovno; // Overlay number 16 +1C WORD e_res[4]; // Reserved words 17 +24 WORD e_oemid; // OEM identifier (for e_oeminfo) 18 +26 WORD e_oeminfo; // OEM information; e_oemid specific 19 +28 WORD e_res2[10]; // Reserved words 20 +3C LONG e_lfanew; // File address of new exe header 21 } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
咱們能夠看到這樣一個結構體這個結構體就是DOS 頭結構體,Windows不少數據都是經過這樣的結構體去組織的。前面的"+數字"是我添加上去的,WinNT.H頭文件中沒有的,這個表示偏移地址。在這裏我默認狀況是你知道什麼是偏移地址,Windows的內存基址。不然一些東西你是沒法理解的。固然這個數字是16進製表示的。調試
咱們用一個UE打開一個PE文件,也就是exe程序。(固然DLL也是PE文件,遵循PE結構。可是咱們這裏默認就是EXE程序),我打開我收集的一個內存查看工具:code
入下圖:orm
能夠看+0H這個位置開始的2個字節(我在這裏假設了解windows下的WORD類型是兩個字節)。這兩個字節也就是e_magic中的內容是MZ。DOS頭中咱們關注的另外一個內容就是最後一個成員也就是+3Ch這個位置,也就是佔四個字節的e_lfanew。(你們要知道32位機器中long型和DWORD型是同樣的4個字節),DOS頭中咱們關注這兩個內容。e_lfanew這個是爲了存儲PE頭的偏移地址。那爲何要這個呢??DOS頭後面不就是PE頭了麼?也就是+3Ch位置後面不就是PE頭了麼?其實不是我麼這裏的DOS頭不是廣義上的。廣義上的DOS頭還有一個。DOS stub 這個DOS stub的大小是不固定的,既然這個不固定那麼廣義上的DOS頭的大小也就是不固定。廣義DOS頭不固定,那咱們怎麼定位PE頭,那就離不開這個四字節的e_lfanew了。e_lfanew中存儲了PE頭的偏移地址。e_lfanew的位置在+3Ch位置。由於小端存儲方式。因此就是上面圖中畫紅線框中的倒過來,那麼PE頭的開始位置是 "0x00 00 0100",也就是16進制的100處。這樣咱們很容易的就定位到了PE頭。
這裏就提早讓你們看一下PE頭結構吧:
1 typedef struct _IMAGE_NT_HEADERS { 2 +00h DWORD Signature; 3 +04h IMAGE_FILE_HEADER FileHeader; 4 ??? IMAGE_OPTIONAL_HEADER32 OptionalHeader; 5 } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
這個是廣義上的PE頭結構。這個結構的+00h處其實就是e_lfanew中偏移指向的位置總PE文件開始處的+3Ch處就是這個Signature相對文件開始的偏移(咱們稱FOA,也就是文件相對偏移地址,這個要和虛擬地址相對偏移RVA區分開,後續我會介紹FOA和RVA的裝換方式,這樣咱們就能夠在內存中定位數據了)。Signature中的四個字節內容其實就是"PE00",也就是+3Ch中的內容"0x00 00 0100"所指向的位置中的內容,100h位置中的四個字節中ASIIC就是「PE00」,這個是PE文件的標誌符,e_magic,+0地址開始的2個字節中的「MZ」,和Signature 的+3C開始位置的四個字節內容「PE00」共同標誌這就是PE文件。咱們後期寫的PE工具,判斷PE就是有這兩個位置的數據去區分是否是Windows PE文件。
這一節到此位置。後面將和你們探討PE head結構。