天天看點

PE頭解析

這兩天對于PE的學習總結:

1.PE結構的應用

(1)windows下exe檔案

(2)動态連結庫(大部分是以dll為擴充名得檔案)

2.關于PE分節

(1)節省硬碟空間   (2)一個應用程式多開

對齊  舊式的電腦 新款
硬碟對齊    200h    1000h
記憶體對齊  1000h    1000h

3.PE整體結構

DOS頭              NT頭              節表/塊表              .text塊               .rdata塊                 data塊

(後面這幾個快不确定位置和數量,這些由節表确定)

下面介紹的都是幾個頭中重點的幾個辨別,是以詳細的自己百度

4.    DOS頭(一般運用在16位系統中 )

WORD   e_magic                *                  "MZ标記" 用于判斷是否為可執行檔案.  (即判斷是否在windows上執行)          

DWORD  e_lfanew;             *                  PE頭相對于檔案的偏移,用于定位PE檔案 

DOS頭和NT頭之間由垃圾資料填充

5.NT頭

NT頭分為三部分(1)PE标記(2)标準PE頭(3)可選PE頭

(1)PE标記   

dword   signature   (由DoS頭裡e_lfanew确定位置)

(2)标準PE頭     fileheader 

          WORD    Machine;              *                程式運作的CPU型号:0x0 任何處理器/0x14C 386及後續處理器                        

          WORD    NumberOfSections;     *        檔案中存在的節的總數,如果要新增節或者合并節 就要修改這個值.                   

          DWORD   TimeDateStamp;        *        時間戳:檔案的建立日期和時間(和作業系統的建立時間無關),編譯器填寫的.  

          DWORD   PointerToSymbolTable;                                         

          DWORD   NumberOfSymbols;                                         

          WORD    SizeOfOptionalHeader; *       可選PE頭的大小,32位PE檔案預設E0h 64位PE檔案預設為F0h  大小可以自定義.  

          WORD    Characteristics;      *              檔案屬性,每個位有不同的含義,普通exe檔案值為10Fh 即0 1 2 3 8位置1                                                                                                                                            Dll檔案一般是210Eh

(3)可選pe頭   optionalheader(由标準pe頭裡sizeOfOptionalHeader确定)

WORD    Magic;        *                說明檔案類型:10B 32位下的PE檔案     20B 64位下的PE檔案                        

BYTE    MajorLinkerVersion;                                        

BYTE    MinorLinkerVersion;                                        

DWORD   SizeOfCode;*                所有代碼節的和,必須是FileAlignment的整數倍 編譯器填的  沒用                        

DWORD   SizeOfInitializedData;*                已初始化資料大小的和,必須是FileAlignment的整數倍 編譯器填的  沒用                      

DWORD   SizeOfUninitializedData;*                未初始化資料大小的和,必須是FileAlignment的整數倍 編譯器填的  沒用                 

DWORD   AddressOfEntryPoint;*                程式入口                        

DWORD   BaseOfCode;*                代碼開始的基址,編譯器填的   沒用                        

DWORD   BaseOfData;*                資料開始的基址,編譯器填的   沒用                        

DWORD   ImageBase;*                記憶體鏡像基址                        

DWORD   SectionAlignment;*                記憶體對齊                        

DWORD   FileAlignment;*                檔案對齊                        

WORD    MajorOperatingSystemVersion;                                        

WORD    MinorOperatingSystemVersion;                                        

WORD    MajorImageVersion;                                        

WORD    MinorImageVersion;                                        

WORD    MajorSubsystemVersion;                                        

WORD    MinorSubsystemVersion;                                        

DWORD   Win32VersionValue;                                        

DWORD   SizeOfImage;*             記憶體中整個PE檔案的映射的尺寸,可以比實際的值大,但必須是SectionAlignment的整數倍     

DWORD   SizeOfHeaders;*          所有頭+節表按照檔案對齊後的大小,否則加載會出錯                        

DWORD   CheckSum;*                校驗和,一些系統檔案有要求.用來判斷檔案是否被修改.                        

WORD    Subsystem;                                        

WORD    DllCharacteristics;                                        

DWORD   SizeOfStackReserve;*                初始化時保留的堆棧大小                         

DWORD   SizeOfStackCommit;*                初始化時實際送出的大小                     DOS    

DWORD   SizeOfHeapReserve;*                初始化時保留的堆大小                     ...    

DWORD   SizeOfHeapCommit;*                初始化時實踐送出的大小                     PE标記    

DWORD   LoaderFlags;                                    标準PE    

DWORD   NumberOfRvaAndSizes;*                目錄項數目                    可選PE頭    

6.節表(由标準PE頭裡NumberOfsections可知節表數目)

#define IMAGE_SIZEOF_SHORT_NAME      8                                       

typedef struct _IMAGE_SECTION_HEADER {                    

    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];                    

    union {                    

            DWORD   PhysicalAddress;                    

            DWORD   VirtualSize;                    

    } Misc;                    

    DWORD   VirtualAddress;                    

    DWORD   SizeOfRawData;                    

    DWORD   PointerToRawData;                    

    DWORD   PointerToRelocations;                    

    DWORD   PointerToLinenumbers;                    

    WORD    NumberOfRelocations;                    

    WORD    NumberOfLinenumbers;                    

    DWORD   Characteristics;                    

} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

1、Name    8個位元組 一般情況下是以"\0"結尾的ASCII嗎字元串來辨別的名稱,内容可以自定義.    

注意:該名稱并不遵守必須以"\0"結尾的規律,如果不是以"\0"結尾,系統會截取8個位元組的長度進行處理.

2、Misc  雙字 是該節在沒有對齊前的真實尺寸,該值可以不準确。               

3、VirtualAddress 節區在記憶體中的偏移位址。加上ImageBase才是在記憶體中的真正位址.    

4、SizeOfRawData  節在檔案中對齊後的尺寸                    

5、PointerToRawData 節區在檔案中的偏移.                    

6、PointerToRelocations 在obj檔案中使用 對exe無意義            

7、PointerToLinenumbers 行号表的位置 調試的時候使用            

8、NumberOfRelocations 在obj檔案中使用  對exe無意義

9、NumberOfLinenumbers 行号表中行号的數量 調試的時候使用

10、Characteristics   *       節的屬性    

(這是一個節表資訊,幾個節表資訊連續)

7.三種不同的位址

檔案中的位址(FA): 在檔案位址空間中,檔案載入的起始位置總是等于0,FA位址表現為一個偏移位址;

虛拟位址(VA):PE檔案被映射到記憶體中時,在記憶體中的映射位址;

相對偏移位址(RVA):程式某一結構的VA減去FA的結果;

程式被裝載入記憶體中時,由檔案結構不變,故其RVA不變,但裝載起始位址不變,因為很難保證計算機的運作狀态時時刻刻都是一緻的。