PE檔案結構解析
t.exe共 3072 bytes,下面是t.exe映象 PE 檔案頭的整體結構圖:
windows 的 PE 檔案頭結構包括三大部分:DOS 檔案頭、NT 檔案頭以及 Section 表(節表),在 DOS 檔案頭後面有一小段 DOS 程式,被稱為 DOS stub 程式。
DOS stub 程式是執行在 DOS 下面的 16 位程式,目的是指出:當 windows 程式在 dos 下執行時,將顯示資訊:This program cannot be run in DOS mode.... 然後終止執行。
這段 DOS stub 程式是這樣的:
00000040 0E push cs 00000045 B409 mov ah,0x9 00000047 CD21 int 0x21 00000049 B8014C mov ax,0x4c01 0000004C CD21 int 0x21 |
資訊字串在位置 0x0e 上,即在:0x00000040 + 0x0e =0x0000004e,這正好是字元資訊“This program cannot be run in DOS mode....$”的地址。
6.1 MS-DOS 檔案頭
t.exe映象檔案頭最開始部分是 MS-DOS 檔案頭部分,這個檔案頭結構定義在WinNT.h檔案裡,在我的 windows 7 系統 visual studio 2010 下,這個 winnt.h 在目錄:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header |
這個IMAGE_DOS_HEADER結構共 64 bytes,從映象的 0x00000000 - 0x0000003F,參見上圖標註的“DOS 檔案頭”部分,將這部分按照IMAGE_DOS_HEADER結構分解為:
00000000 4D 5A // e_magic |
其中最重要的是:e_magic和e_lfanew域(上面紅色部分標註),e_magic是 MS-DOS 檔案頭的簽名,它的值是:0x5A4D,這個簽名在WinNT.h中定義為:
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ |
它的值代表字母 MZ,表示 MS-DOS 檔案頭。e_lfanew是一個 offset 偏移量,指出IMAGE_NT_HEADER在映象中的位置,IMAGE_NT_HEADER是 PE 檔案的核心部分,IMAGE_NT_HEADER在 WinNT.h 中定義為兩個版本,分別是:IMAGE_NT_HEADERS64和IMAGE_NT_HEADERS32,它們的定義如下:
typedef struct _IMAGE_NT_HEADERS64 { typedef struct _IMAGE_NT_HEADERS { |
當使用在 win64 下時,IMAGE_NT_HEADER使用的是 64 位版本IMAGE_NT_HEADERS64,當使用在 win32 下時,IMAGE_NT_HEADER使用的是IMAGE_NT_HEADERS32
#ifdef _WIN64 |
在本例t.exe映象裡e_lfanew為0x000000C0,它說明IMAGE_NT_HEADERS結構位於映象的 0x000000C0 處,此時尚不能斷定這個 PE 是 32 位還是 64 位結構。
6.2 IMAGE_NT_HEADER 結構
在IMAGE_NT_HEADERS結構的定義裡得出,它包含了一個簽名和兩個結構體,這個簽名是 0x00004550 表示 PE 檔案:
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00 |
6.2.1 IMAGE_FILE_HEADER 結構
在IMAGE_NT_HEADER的中IMAGE_FILE_HEADER定義如下:
typedef struct _IMAGE_FILE_HEADER { |
這個結構共 20 bytes,下面是這些域的描述:
域 | size | 值 | 描述 |
Machine | WORD | IMAGE_FILE_MACHINE_xxx | 表示目標平臺 processor 型別,例:IMAGE_FILE_MACHINE_I386 |
NumberOfSection | WORD | --- | 表示映象中有多少個 section |
TimeDataStamp | DWORD | 從1970年1月1日0:00 以來的總秒數 | 表示檔案建立的時間 |
PointerToSymbolTable | DWORD | COFF 符號表偏移量 | 在 PE 中很少見,總是為 0 |
NumberOfSymbols | DWORD | COFF 符號表的個數 | 如果存在的話,表示符號表的個數 |
SizeOfOptionHeader | WORD | IMAGE_OPTIONAL_HEADER 結構大小 | 該域表示IMAGE_NT_HEADER中的IMAGE_OPTIONAL_HEADER結構的大小 |
Characteristics | WORD | IMAGE_FILE_xxx | 表示檔案屬性,例如:IMAGE_FILE_DLL屬性 |
IMAGE_FILE_HEADER 結構中比較重要的域是:Machine和SizeOfOptionalHeader,Machine可以用來判斷目標平臺,比如:值為 0x8664 是代表 AMD64(即:x64 平臺)它也適合 Intel64 平臺。SizeOfOptionalHeader指出IMAGE_OPTIONAL_HEADER結構的大小。
在WinNT.h檔案裡定義了一系列的 Machine 值,這裡舉列一些,詳細的參見 WinNT.h 檔案:
#define IMAGE_FILE_MACHINE_UNKNOWN 0 |
也為 Characteristics 定義了一系列的常量,這些定義的常量值,代表映象是什麼型別的檔案:
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. |
下面看看t.exe裡的IMAGE_FILE_HEADER具體的值,如下圖所示:
t.exe映象的目標平臺是 x64 平臺,它指出了接下來的 IMAGE_OPTIONAL_HEADER結構大小為:0x00F0 bytes
注意:雖然在 Machine 裡指出目標平臺,但是對於判斷映象是 32 位還是 64 位的 PE 檔案,Microsoft 官方認可以的方法是:通過IMAGE_OPTIONAL_HEADER結構裡的Magic域
6.2.2 IMAGE_OPTIONAL_HEADER 結構
與IMAGE_NT_HEADER一樣,IMAGE_OPTIONAL_HEADER也有 32 位版本和 64 位版本,因此,相應版本的IMAGE_NT_HEADER對應相應版本的IMAGE_OPTIONAL_HEADER。雖然這個結構被稱為 IMAGE_OPTIONAL_HEADER(可選),但是它卻是必須存在於IMAGE_NT_HEADER結構中。
下面是 64 位版本的IMAGE_OPTIONAL_HEADER結構定義, 32 位版本的參見 WinNT.h 中的定義
typedef struct _IMAGE_OPTIONAL_HEADER64 { |
IMAGE_OPTIONAL_HEADER結構的定義稍長一些,下面是自來 Matt Pietrek 所寫的文章,名為《An In-Depth Look into the Win32 Portable Executable File Format》中對IMAGE_OPTIONAL_HEADER結構的描述,地址在:http://msdn.microsoft.com/en-us/magazine/bb985997.aspx其中的Figure 5 IMAGE_OPTIONAL_HEADER一節裡對 IMAGE_OPTIONAL_HEADER 結構有詳細的描述。這裡就不再描述了。 :)
關鍵的一點: 在IMAGE_OPTIONAL_HEADER裡,第 1 個域magic用來識別檔案頭是 32 位還是 64 位 |
這個 magic 的值在 WinNT.h 的定義如下:
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b |
當 magic = 0x10b 時,映象是 32 位,magic = 0x20b 時,映象是 64 位。
6.3 觀察 t.exe 映象的實際 IMAGE_NT_HEADER 結構
在我們例項 t.exe 映象中,IMAGE_NT_HEADER的偏移量是0x000000C0,IMAGE_NT_HEADER結構在 32 位下是 244 bytes,在 64 位下是 264 bytes
下面我們來看一看 t.exe 映象中的 IMAGE_NT_HEADER 結構,從 0x0000000C0 - 0x000001C7(共 264 bytes)
IMAGE_NT_HEADER結構的簽名 Signature 是 0x00004550 表示 PE 檔案頭。
6.3.1 t.exe 的 IMAGE_FILE_HEADER 結構
藍色部分是IMAGE_FILE_HEADER結構,IMAGE_FILE_HEADER結構緊接著 PE 簽名之後,共 20 bytes,其中的Machine是 0x8664,由上述定義所得,它代表的機器型別是AMD64處理器
000000C4 64 86 // Machine = AMD64 |
它的檔案屬性是 0x0022,也就是:Characteristics =IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_LARGE_ADDRESS_AWARE,說明它是一個可執行的映象,可以在 >2G 地址上,並且指明瞭接下來的IMAGE_OPTIONAL_HEADER結構是 0xf0 bytes(240 個位元組)。
6.3.2 t.exe 的 IMAGE_OPTIONAL_HEADER 結構
IMAGE_FILE_HEADER結構接下來就是IMAGE_OPTIONAL_HEADER結構,前面的 SizeOfOptionHeader 域已經指出IMAGE_OPTIONAL_HEADER將會是 0xf0 個位元組。
000000D8 0B 02 // Magic = 0x020b |
t.exe的IMAGE_OPTIONAL_HEADER結構從 0xd8 ~ 0x1c7 共 0xF0 bytes,這個值在IMAGE_FILE_HEADER結構的 SizeOfOptionalHeader 域裡已經給出。
在上面的可以看出t.exe映象是 64 位是 PE+ 檔案結構,它的ImageBase是 0x00000001_40000000,t.exe映象的入口點在ImageBase + AddressOfEntryPoint= 0x00000001_40001000,這個資訊可以從上面分析的.text節中所描述的資訊中驗證,IMAGE_OPTIONAL_HEADER結構的 AddressOfEntryPoint 域的值是RVA(Relative Virtual Address)值。
上面的 SectionAlinment 域值為 0x1000 是表示映象被載入到 virtual address 以是 0x1000(4K byte)為單位的倍數,也就是載入在 virtual address 的 4K 邊界上,例如:t.exe映象的.text節被載入到以ImageBase(virtual address 為 0x00000001_40000000)為基址的第 1 個 4K 邊界上(即:0x00000001_40001000 處),.rdata節載入到第 2 個 4K 邊界上(即:0x00000001_40002000 處)。
FileAlinment 域的值為 0x200 表示執行映象從 0x200 為邊界開始載入到 virtual address 上。例如,t.exe映象中 code 位於檔案映象的 0x400 處(0x200 邊界上),因此,t.exe檔案映象 code 從 0x400 處開始載入到 virtual address。
因此:.text節在檔案映象中位於 0x400 開始,在 virtual address 空間中是位於 0x00000001_40001000 開始,它說明映象的 0x400 處被載入到 virtual address 000000001_40001000 位置上。
6.3.3 t.exe 的 IMAGE_DATA_DIRECTORY 表格
上面所示:從 0x00000148 到 0x000001C7 是被稱之為IMAGE_DATA_DIRECTORY的結構的表格。這個 IMAGE_DATA_DIRECTORY 結構在WinNT.h中定義如下:
typedef struct _IMAGE_DATA_DIRECTORY { |
這個結構十分重要,它用來描述 windows 執行映象中所使用的各種表格的位置和大小。VirtualAddress 域是一個RVA(Relative Virtual Address)值,更明白一點就是:它是一個偏移量(基於 PE 檔案頭),Size 域表示這個表格有多大。
這個陣列有 16 個元素,也就是表示,在執行映象中最多可以使用 16 個表格。在WinNT.h裡定義為:
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 |
由於這個IMAGE_DATA_DIRECTORY表格用來描述在映象中所使用到的表格(最多 16 個表格)
實際上這 16 個表格是固定的,對於這些表格 Microsoft 都作了統一的規定,在WinNT.h裡都作了定義:
// Directory Entries #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory |
下面,我將這些表格歸納如下:
表項 | 表格 |
0 | export table |
1 | import table |
2 | resource table |
3 | exception table |
4 | certificate table |
5 | base relocation table |
6 | debug |
7 | architecute |
8 | global pointer |
9 | TLS table |
10 | load configuration table |
11 | bound import |
12 | import address table |
13 | delay import descriptor |
14 | CLR runtime header |
15 | reserved, must bo zero |
那麼,下面我們來看一看 t.exe 映象中使用了哪些表?
00000148 00 00 00 00 // IMAGE_DATA_DIRECTORY[0] |
我們的示例程式 t.exe 僅僅使用了 3 個 driectory 表格:import table、relocation table以及import address table
import table 的 RVA 是 0x00002010,size 是 0x28,relocation table 的 RVA 是 0x4000,size 是 0x0c, import address table 的 RVA 是 0x2000,size 是 0x10
t.exe的ImageBase是 0x00000001_40000000,那麼import table則在 0x00000001_40002010,relocation table則在 0x00000001_40004000,import address table則在 0x00000001_40002000。
6.3.3.1 t.exe 所使用的 import table
上面所述,t.exe的import talbe在 0x00000001_40002010(virtual address),這個import table位於.rdata節中,從上面的.rdata節介紹中看出,.rdata節位於檔案映象中的 0x600 ~ 0x7ff 中共 512 bytes。
import table 在 WinNT.h 中定義為一個 IMAGE_IMPORT_DESCRIPTOR 結構,如下:
typedef struct _IMAGE_IMPORT_DESCRIPTOR { DWORD ForwarderChain; // -1 if no forwarders |
IMAGE_IMPORT_DESCRIPTOR結構 5 個域,共 20 bytes,OriginalFirstThunk域指向一個IMAGE_THUNK_DATA結構,IMAGE_THUNK_DATA實際上只有一個域AddressOfData,AddressOfData指向一個IMAGE_IMPORT_BY_NANE結構,它們在 WinNT.h 中的定義為:
// typedef struct _IMAGE_IMPORT_BY_NAME { #include "pshpack8.h" // Use align 8 for the 64-bit IAT. typedef struct _IMAGE_THUNK_DATA64 { |
IMAGE_IMPORT_BY_NAME是最終的 import table 結構,是原始的 Thunk 表格,這個 Thunk 表格是一個包含所有匯入 function 的列表,這個Thunk table包括了 Hint, function name 和 DLL name。 Hint 代表每個函式的標識,是一個 16 位的數值,Hint 下面接著是 import 的函式名,最後是所匯入的 DLL name。
IMAGE_IMPORT_DESCRIPTOR裡的FirstThunk指向出 Import Address Table (IAT)表格,這個 IAT 大小為 16 bytes ,前 4 bytes 是一個 RVA 指向上面所說的 Thunk table。
import table +----------------------+ IMAGE_THUNK_DATA |
上面是一張關係圖表,上面所示,在映象和記憶體中,存在 4 張表格:
● import table(IMAGE_IMPORT_DESCRIPTOR)
● Thunk table pointer-table(IMAGE_THUNK_DATA)
● IAT(Import Address Table)
● 匯入函式的 Thunk Table(IMAGE_IMPORT_BY_NAME)。
下面看看實際中t.exe映象中的這幾個表格是什麼:
RAW DATA #2 Section contains the following imports: USER32.dll 212 MessageBoxA |
上面已經顯示出了全部資訊,在IMAGE_DATA_DIRECTORY結構裡已給出了 Import table 的 RVA 是 0x00002010,即:t.exe的 import table 在 virtual address 0x00000001_40002010 裡,那麼現在我們來看一看 import table 裡的資料:
0000000140002010: 38 20 00 00 // OriginalFirstThunk(Thunk table pointer) |
因此 Thunk table pointer 放在 00000000140002038 裡,匯入的 DLL 名字放在 0000000140002056 裡,Import address table 放在 0x0000000140002000 裡。
6.4 t.exe 的節表
IMAGE_NT_HEADER結構後面緊接著就是section table(節表)結構, 從 0x1c8 ~ 0x267 共 160 bytes。
這個節表結構在WinNT.h中定義為
// #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { #define IMAGE_SIZEOF_SECTION_HEADER 40 |
映象中包括有多少個節表結構,由IMAGE_NT_HEADER結構中的IMAGE_FILE_HEADER結構中的 NumberOfSections 域指出。在前面所述的t.exe映象裡 NumberOfSections 值是 4 那麼表示將有 4 個 sections 存在於映象中。從前的面 dumpbin 工具輸出可以得出。
在IMAGE_SECTION_HEADER結構的第 1 個域 Name,用來標識section table的名字。它的長度固定為 8 bytes(前面定義的巨集),這將意味著,不存在超過 8 bytes 的節表名。接下來使用 VirtualSize 來用表示 section talbe 大小。VirtualAddress 表示 section table 的 RVA
域 | size | 描述 |
Name | 8 bytes | Section 表名字 |
VirtualSize | DWORD | Section 表的大小 |
VirtualAddress | DWORD | Section 表的 RVA,即:section 表的位置 |
SizeOfRawData | DWORD | section 表佔用映像的大小,這個 size 是以 0x200 為單位的 |
PointerToRawData | DWORD | section 表在映像中的物理位置,即是:file 位置,而非 virtual 位置 |
PointerToRelocation | DOWRD | |
PointerToLinenumber | DWORD | |
NumberOfRelocation | WORD | |
NumberOfLineumbers | WORD | |
Characteristics | DWORD | section 的屬性 flags,可用於 '|' 多個屬性值 |
所有的 Characteristics 都在 WinNT.h 中有定義,下面是一些常用的 flags:
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. |
下面以.text節為例,看看t.exe的.text是什麼。
.text節的 Name 是 ".text",VirtualSize 是 0x42 bytes,.text節在 RVA 為 0x00001000 的位置上,section 的分配單位為 0x1000(4K bytes),第 1 個 section 一般都分配在 0x1000 位置上,SizeOfRawData 為 0x200,這是映像檔案分配單位。PointerToRawData 為 0x400,說明.text節在映像檔案的 0x400 處。Characteristics 是 0x60000020,說明.text是 executable/readable/code 屬性。
相關推薦
PE檔案結構解析 C、C++程式 vc2008編譯
//MyPeFile.h------------------------------------------------------------------------------------------------------ typedef unsigned short USHORT;typ
PE檔案結構解析
t.exe共 3072 bytes,下面是t.exe映象 PE 檔案頭的整體結構圖: windows 的 PE 檔案頭結構包括三大部分:DOS 檔案頭、NT 檔案頭以及 Section 表(節表),在 DOS 檔案頭後面有一小段 DOS 程式,被稱為 DOS stub 程
MP3檔案結構解析(超詳細)
1. MP3檔案結構解析 1.1. 概述 1.1.1. 音訊相關術語 ü ID3: 一般位於一個mp3檔案的開頭或末尾的若干位元組內,記錄該mp3檔案的歌手、標題、專輯名稱、年代、風格等資訊,ID3分位兩個版本,V1版ID3在檔案末尾的固定128位元組,以TAG字元開頭,若沒有則認為
tomcat9目錄檔案結構解析
一、tomcat目錄檔案如下圖: bin: 啟動和關閉tomcat的指令碼檔案 conf: 存放tomcat配置檔案 server.xml : 該檔案用於配置和 server 相關的資訊, 比如 tomcat啟動埠後,配置Host, 配置Conte
MP3解碼流程(一)-----音訊檔案結構解析
本文多處摘自網際網路,僅供本人學習使用,出處標示於文章尾端。 #一、概述 Layer-3 音訊檔案,MPEG(Moving Picture Experts Group) 在漢語中譯為活動影象專家組,特指活動影音壓縮標準,MPEG音訊檔案是MPEG1
windows PE檔案結構及其載入機制
1. 概述 PE檔案的全稱是Portable Executable,意為可移植的可執行的檔案,常見的EXE、DLL、OCX、SYS、COM都是PE檔案,PE檔案是微軟Windows作業系統上的程式檔案(可能是間接被執行,如DLL)。它是1993年Windows
PE檔案結構及其載入機制(一)
一、PE檔案結構 PE即Portable Executable,是win32環境自身所帶的執行體檔案格式,其部分特性繼承自Unix的COFF(Common Object File Format)檔案格式。PE表示該檔案格式是跨win32平臺的,即使Windows執行在非Intel的CPU上,任何Win32平
(2) springframework主配置檔案結構解析
轉自: http://book.51cto.com/art/201004/193743.htm Spring配置檔案是用於指導Spring工廠進行Bean生產、依賴關係注入(裝配)及Bean例項分發的"圖紙"。Java EE程式設計
PE檔案結構(0x02)
最 最近包括暑假一直在學習PE檔案的格式結構,對一些病毒感染檔案的方式想要做一些瞭解,學的東西可能很淺顯,在這裡記錄一下想。 PE檔案的第一個位元組起始於 MS-DOS 頭部,被稱作 IMAGE_DOS_HEADER,定義在WINNT.H,其結構如下: t
00 PE檔案結構
一、什麼是PE檔案結構? 可執行檔案指的是由作業系統進行載入執行的檔案,而PE檔案結構就是Windows下可執行檔案的格式,同樣ELF(Executable and Linking Format)檔案結構就是linux下可執行檔案的格式;PE是 Potable Executable的首字母縮
PE檔案詳解------PE檔案結構剖析
一.PE檔案結構縱覽 PE檔案的結構如上圖所示,由低地址到高地址分別為:Dos頭,PE頭,塊表,塊,除錯資訊。其中真正的PE檔案頭是位於Dos頭的後面的部分。 上圖為利用PE工具開啟的一個可執行檔案在磁碟中的對映,這就是PE檔案的內部資訊。 可以看到這個檔案的錢兩個
vue2目錄及檔案結構解析
一、首先建立一個vue專案,如:my-vue,其程式碼結構如下: 由上圖分析每個檔案的作用: 二、我們主要工作src資料夾的分析結構如圖: 這是src資料夾下面的初始情況,裡面有一些示
深入boot.img格式檔案結構解析
以msm8226為例,講解android原始碼編譯生成boot.img的結構。boot.img包括boot.img header、kernel以及ramdisk檔案系統。下面是對boot.img的結構進行解讀。 boot.img 檔案頭資訊的具體結構可以在system/
PE檔案結構(一) 基本結構
PE檔案結構(一) 參考 書:《加密與解密》 視訊:小甲魚 解密系列 視訊 exe,dll都是PE(Portable Execute)檔案結構。PE檔案使用的是一個平面地址空間,所有程式碼和資料都被合併在一起,組成一個很大的結構。先看2張圖,來大
PE檔案結構詳解(四)PE匯入表
PE檔案結構詳解(二)可執行檔案頭的最後展示了一個數組,PE檔案結構詳解(三)PE匯出表中解釋了其中第一項的格式,本篇文章來揭示這個陣列中的第二項:IMAGE_DIRECTORY_ENTRY_IMPORT,即匯入表。 也許大家注意到過,在IMAGE_DATA_DIRECTO
PE總結7---PE檔案結構NT頭之資料目錄表 IMAGE_DATA_DIRECTORY
IMAGE_DATA_DIRCTORY結構如下: typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; //相對虛擬地址 DWORD Size; //大小 } IMAGE_DATA_
PE檔案結構(五)基址重定位
PE檔案結構(五) 參考 書:《加密與解密》 視訊:小甲魚 解密系列 視訊 基址重定位 連結器生成一個PE檔案時,它會假設程式被裝入時使用的預設ImageBase基地址(VC預設exe基地址00400000h,dll基地址10000000h)
PE總結3---PE檔案結構DOS檔案頭
PE檔案結構DOS檔案頭,會使用到IMAGE_DOS_HEADER結構體,如下 typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic;
C++PE檔案格式解析類(輕鬆製作自己的PE檔案解析器)
PE是Portable Executable File Format(可移植的執行體)簡寫,它是目前Windows平臺上的主流可執行檔案格式。 PE檔案中包含的內容很多,具體我就不在這解釋了,有興趣的可以參看之後列出的參考資料及其他相關內容。 最近我也在學習PE檔案格式,參
opencv2.x檔案結構解析
1 OpenCV簡介 OpenCV(Open Source Computer Vision)是一個用於實時處理的計算機視覺函式庫,它基於BSD許可證授權並且可免費用於學術研究和商業應用。它擁有C/C++、Python、和Java(僅用於Android)介