目錄linux
PE 格式是Windows系統下組織可執行文件的格式。PE文件由文件頭和對應的數據組成。目標是在不一樣的架構下裝載器和編程工具不用重寫。編程
PE中一大特色是不連續的位置大部分記錄的都是相對地址(RVA),相對的是PE文件中記錄的基地址(image base)的偏移量。進程是程序的執行狀態的實體,每一個進程都有本身獨立的內存空間(編址)PE和內核等一塊兒編制,因此image base也不老是肯定的。windows
結構(參考:加密與解密)數據結構
參考:參考:http://www.openrce.org/reference_library/files/reference/PE%20Format.pdf架構
IMAGE_DOS_HEADER STRUCT { +0h WORD e_magic //Magic DOS signature MZ(4Dh 5Ah) DOS可執行文件標記 +2h WORD e_cblp //Bytes on last page of file +4h WORD e_cp //Pages in file +6h WORD e_crlc //Relocations +8h WORD e_cparhdr //Size of header in paragraphs +0ah WORD e_minalloc //Minimun extra paragraphs needs +0ch WORD e_maxalloc //Maximun extra paragraphs needs +0eh WORD e_ss //intial(relative)SS value DOS代碼的初始化堆棧SS +10h WORD e_sp //intial SP value DOS代碼的初始化堆棧指針SP +12h WORD e_csum //Checksum +14h WORD e_ip // intial IP value DOS代碼的初始化指令入口[指針IP] +16h WORD e_cs //intial(relative)CS value DOS代碼的初始堆棧入口 +18h WORD e_lfarlc //File Address of relocation table +1ah WORD e_ovno // Overlay number +1ch WORD e_res[4] //Reserved words +24h WORD e_oemid // OEM identifier(for e_oeminfo) +26h WORD e_oeminfo // OEM information;e_oemid specific +29h WORD e_res2[10] // Reserved words +3ch DWORD e_lfanew //Offset to start of PE header PE頭相對於文件的偏移地址 } IMAGE_DOS_HEADER ENDS
對於PE來講DOS頭是爲了兼容16位程序的,如今都是3二、64位因此咱們只關心這個結構體中的兩個成員(16位系統中PE頭和內容是冗餘數據)ide
e_magic、e_lfanew(第一個和最後一個)函數
上圖3CH是e_lfanew內容指向PE頭地址內容位0000000E(小端存儲)。工具
咱們能夠看到DOS頭和PE頭是間隔的那塊區域叫DOS stub這個是存儲16位程序的,對於3二、64位系統無用this
PNTHeader = ImageBase + (dosHeader->e_lfanew)加密
typedef struct _IMAGE_NT_HEADERS { +0 hDWORD Signature // +4h IMAGE_FILE_HEADER FileHeader // +18h IMAGE_OPTIONAL_HEADER32 OptionalHeader // } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; #define IMAGE_NT_SIGNATURE 0x00004550
typedef struct _IMAGE_FILE_HEADER { +04h WORD Machine;//04h相對於_IMAGE_NT_HEADERS的,運行平臺 +06h WORD NumberOfSections;//文件的區塊數(*重要) +08h DWORD TimeDateStamp;//文件建立時間 和unix時間戳同樣int(secound(now-19700101)) +0cH DWORD PointerToSymbolTable;//指向符號表(主要用於調試) +10H DWORD NumberOfSymbols;//符號表中符號個數(同上) +14H WORD SizeOfOptionalHeader;//IMAGE_OPTIONAL_HEADER32 結構大小(*重要)IMAGE_OPTIONAL_HEADER是長度可變的。 +16H WORD Characteristics;//文件屬性多,種屬性經過 「或運算」 同時擁有 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
由IMAGE_FILE_HEADER的SizeOfOptionalHeader決定大小(可變長) typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // +18h WORD Magic; // 標誌字, ROM 映像(0107h),普通可執行文件(010Bh) +1Ah BYTE MajorLinkerVersion; // 連接程序的主版本號 +1Bh BYTE MinorLinkerVersion; // 連接程序的次版本號 +1Ch DWORD SizeOfCode; // 全部含代碼的節的總大小 +20h DWORD SizeOfInitializedData; // 全部含已初始化數據的節的總大小 +24h DWORD SizeOfUninitializedData; // 全部含未初始化數據的節的大小 +28h DWORD AddressOfEntryPoint; // 程序執行入口RVA +2Ch DWORD BaseOfCode; // 代碼的區塊的起始RVA +30h DWORD BaseOfData; // 數據的區塊的起始RVA // // NT additional fields. // +34h DWORD ImageBase; // 文件在內存中的的首選裝載地址。 +38h DWORD SectionAlignment; // 內存中的區塊的對齊大小 +3Ch DWORD FileAlignment; // 文件中的區塊的對齊大小 +40h WORD MajorOperatingSystemVersion; // 要求操做系統最低版本號的主版本號 +42h WORD MinorOperatingSystemVersion; // 要求操做系統最低版本號的副版本號 +44h WORD MajorImageVersion; // 可運行於操做系統的主版本號 +46h WORD MinorImageVersion; // 可運行於操做系統的次版本號 +48h WORD MajorSubsystemVersion; // 要求最低子系統版本的主版本號 +4Ah WORD MinorSubsystemVersion; // 要求最低子系統版本的次版本號 +4Ch DWORD Win32VersionValue; // 莫須有字段,不被病毒利用的話通常爲0 +50h DWORD SizeOfImage; // 映像裝入內存後的總尺寸 +54h DWORD SizeOfHeaders; // 全部頭 + 區塊表的尺寸大小 +58h DWORD CheckSum; // 映像的校檢和 +5Ch WORD Subsystem; // 可執行文件指望的子系統 +5Eh WORD DllCharacteristics; // DllMain()函數什麼時候被調用,默認爲 0 +60h DWORD SizeOfStackReserve; // 初始化時的棧大小 +64h DWORD SizeOfStackCommit; // 初始化時實際提交的棧大小 +68h DWORD SizeOfHeapReserve; // 初始化時保留的堆大小 +6Ch DWORD SizeOfHeapCommit; // 初始化時實際提交的堆大小 +70h DWORD LoaderFlags; // 與調試有關,默認爲 0 +74h DWORD NumberOfRvaAndSizes; // 下邊數據目錄的項數,這個字段自Windows NT 發佈以來 // 一直是16 +78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];// 數據目錄表 } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
ImageBase文件在內存中載入地址,若是有文件佔據這個位置裝載器會進行應用基址重定位。 對於EXE文件來講,因爲每一個文件老是使用獨立的虛擬地址空間通常不會被別的文件搶佔。 對於DLL文件來講,因爲多個DLL文件所有使用宿主EXE文件的地址空間,不能保證優先裝入地址沒有被別的DLL使用,因此DLL文件中必須包含重定位信息,對應
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. IMAGE_FILE_HEADER ->Characteristics(能夠看到下面的數字位數不一樣,並且都是一、二、四、8他們總共加起來就是16看看二進制就知道了他們佔的不是同一位與一下就能取到相對應位,linux的文件屬性一、二、4也是同樣的) EXE文件的默認優先裝入地址被定爲00400000h,而DLL文件的默認優先裝入地址被定爲10000000h
AddressOfEntryPoint字段 : 程序執行入口RVA,imageBase+AddressOfEntryPoint就是程序運行的時候首先執行代碼處。通常指向.text節。
SectionAlignment:程序載入內存後區塊(節)對齊大小,每一個節被載入內存後必須和CPU內存頁對齊(方便設置內存頁屬性)最小1Kh(4KB)
FileAlignment:PE文件在磁盤上的對齊大小,最小爲200h(512byte)一個扇區大小。
關於對齊能夠用winhex打開磁盤上的notpad.exe和內存中的notpad.exe,notpad裝載的時候就被拉伸了。
IMAGE_DATA_DIRECTORY
這個是個結構存儲的對應表位置和大小,至於這些表有什麼,作什麼須要下面詳細解釋。
typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; //表首地址的RVA DWORD Size; //表長度 } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
下面是微軟的文檔上截取的,其中咱們比較關心的是導入表、重定位表(DLL等)
Size | Field | Description |
---|---|---|
8 | Export Table | The export table address and size. For more information see .edata Section (Image Only). |
8 | Import Table | The import table address and size. For more information, see The .idata Section. |
8 | Resource Table | The resource table address and size. For more information, see The .rsrc Section. |
8 | Exception Table | The exception table address and size. For more information, see The .pdata Section. |
8 | Certificate Table | The attribute certificate table address and size. For more information, see The Attribute Certificate Table (Image Only). |
8 | Base Relocation Table | The base relocation table address and size. For more information, see The .reloc Section (Image Only). |
8 | Debug | The debug data starting address and size. For more information, see The .debug Section. |
8 | Architecture | Reserved, must be 0 |
8 | Global Ptr | The RVA of the value to be stored in the global pointer register. The size member of this structure must be set to zero. |
8 | TLS Table | The thread local storage (TLS) table address and size. For more information, The .tls Section. |
8 | Load Config Table | The load configuration table address and size. For more information, The Load Configuration Structure (Image Only). |
8 | Bound Import | The bound import table address and size. |
8 | IAT | The import address table address and size. For more information, see Import Address Table. |
8 | Delay Import Descriptor | The delay import descriptor address and size. For more information, see Delay-Load Import Tables (Image Only). |
8 | CLR Runtime Header | The CLR runtime header address and size. For more information, see The .cormeta Section (Object Only). |
8 | Reserved, must be zero |
區塊由區塊表映射,區塊表緊跟IMAGE_NT_HEADERS;多少個區塊表由_IMAGE_NT_HEADERS.FileHeader.NumberOfSections指定。
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //8字節的name union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress;//區塊RVA DWORD SizeOfRawData;//文件對齊後的尺寸 DWORD PointerToRawData;//文件中的偏移 DWORD PointerToRelocations;// DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics;//區塊屬性 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; #define IMAGE_SIZEOF_SHORT_NAME 8
Name八個字節的不必定以「\0」借位的字符串表示節的名字
Misc、PhysicalAddress、VirtualSize叫什麼都行是未對齊前節的大小(能夠不許確,改了也沒事,編譯器生成的)
節在內存中的偏移地址,RVA。
SizeOfRawData 節在文件中對齊的尺寸
PointerToRawData 節在磁盤文件中的便宜,若是須要本身裝載PE(不用操做系統裝載)這個值有不少用處。
Characteristics 節屬性(代碼/數據,可讀/可寫)
經常使用 #define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. #define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. #define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. #define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. #define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.
區塊對齊分兩部分,FileAlignment、SectionAlignment分別表明文件中和內存中的對齊,爲了有效讀取和設置屬性規定,FileAlignment如今好多程序都和SectionAlignment同樣大小了。SectionAlignment內存對齊值在x86上通常是內存頁大小4kB(1000H)在x64當中是8KB(2000H)。
FileAlignment、SectionAlignment不一樣須要將磁盤中的PE文件拉伸。
FileOffset=VA-RVA-k
參考:加密與解密
https://docs.microsoft.com/zh-cn/windows/win32/debug/pe-format