Windows Pe 第三章 PE头文件(上)
第三章??PE頭文件
????本章是全書重點,所以要好好理解,概念比較多,但是非常重要。
????PE頭文件記錄了PE文件中所有的數(shù)據(jù)的組織方式,它類似于一本書的目錄,通過目錄我們可以快速定位到某個具體的章節(jié);通過PE文件頭部分對某些數(shù)據(jù)結構的描述,我們也可以定位到那些不在頭文件部的信息,比如導入表數(shù)據(jù)、導出表數(shù)據(jù)、資源表數(shù)據(jù)等。
3.1 ?PE的數(shù)據(jù)組織方式
這一節(jié)說了很多,舉了兩個例子,分別是圖書館存書1和圖書館存書2,細節(jié)我不介紹了,是基本的數(shù)據(jù)結構應用,沒有難點。最后說PE數(shù)據(jù)組織方式類似于存書2的例子。那么說下存書2的例子:
為了方便圖書館更好的管理書籍(為了方便查找),我們可以定義兩個數(shù)據(jù)結構,一個是BookStore,另一個是Book。(書中都是用匯編寫的,我用C++翻譯一下吧,方便看)。
BOOKSTORE
?
BOOK
?
找書的時候,我們可以通過BookStore遍歷書庫位置中的所有書找到存儲指定的書的信息的變量的地址(某個Book地址),然后我們在根據(jù)這個地址找到Book結構,然后再根據(jù)這個結構去找到這本書。
對應的結構圖
?
????????PE文件結構基本采用了類似的阻止方式。
3.2 ?與PE有關的基本概念
在詳細了解PE文件結構之前,先學習幾個基本概念。
3.2.1 ?地址
????PE中設計的地址有四類,它們分別是:
1.虛擬內(nèi)存地址(VA)
2.相對虛擬內(nèi)存地址(RVA)
3.文件偏移地址(FOA)
4.特殊地址
要想了解這些概念,需要先簡單了解一下32位環(huán)境下Windows對內(nèi)存的管理,以及分頁機制的原理。(這個地方請自行百度補腦)。
1.虛擬內(nèi)存地址
??用戶的PE文件被操作系統(tǒng)加載進內(nèi)存后,PE對應的進程支配了自己獨立的4GB虛擬空間。在這個空間中定位的地址稱為虛擬內(nèi)存地址(Virtual Address,VA),所以虛擬內(nèi)存地址的范圍是00000000h~ffffffffh。在PE中,進程本身的VA被解釋為:VA=進程的基地址+相對偏移內(nèi)存地址。?
2.相對虛擬內(nèi)存地址
一個進程被操作系統(tǒng)加載到虛擬內(nèi)存空間后,其相關的動態(tài)鏈接庫也會被加載。這些同時加載到進程地址空間的文件被稱為模塊。每個模塊在加載時都會有一個基址,也就是預先告操作系統(tǒng):它會占用4GB空間的哪個部分(即從哪里開始存儲該模塊)。不同模塊的基地址一般不一樣,如果兩個模塊的基地址相同,就由操作系統(tǒng)決定這兩個模塊在虛擬空間中的具體位置。
相對虛擬內(nèi)存地址(Reverse Virtual Address ,RVA)是相對于基地址的偏移,即RVA是虛擬內(nèi)存中用來定位某個特定位置的地址,該地址的值是這個特定位置距離某個模塊基地址的偏移量,所以說RVA是針對某個模塊而存在的。
關于VA和RVA的概念,如下圖:
?
上圖假設模塊2的基地址為0x01000000,而模塊2中的某個位置距離模塊2的基地址偏移為400h,那么值0x00000400就是模塊2中某個位置的RVA,而值0x01000400是該位置的VA。記住,RVA是相對于模塊而言的,VA是相對于整個地址空間而言的。[RVA與具體模塊相關,它有一個范圍,該范圍從模塊的開始到結束,脫離這個范圍的RVA是無效的,稱為越界。越界的RVA地址沒有任何意義。]
3.文件偏移地址
文件偏移地址(File Offset Address,FOA)和內(nèi)存無關,它是只某個位置距離文件頭的偏移。
4.特殊地址
在PE結構中海油一種特殊地址,其計算方法并不是從文件頭算起,也不是從內(nèi)存的某個模塊的基地址算起,而是從某個特定的位置算起。這種地址在PE結構中很少見,如在資源列表里出現(xiàn)過這樣的地址。
3.2.2 ?指針
????PE數(shù)據(jù)結構中的指針的定義:如果數(shù)據(jù)結構中某個字段存儲的值為一個地址,那么這個字段就是一個指針。
?
3.2.3 ?數(shù)據(jù)目錄
Windows下的可執(zhí)行文件是PE中的一種,這種文件出了包含代碼及數(shù)據(jù)段的相關數(shù)據(jù)以外,還包含許多與文件執(zhí)行有關的其他數(shù)據(jù),比如引用外部函數(shù)的信息、PE程序的圖標、內(nèi)部到處函數(shù)等,這些數(shù)據(jù)可能會隨著操作系統(tǒng)的新特性出現(xiàn)而增加。
PE中有一個數(shù)據(jù)結構成為數(shù)據(jù)目錄,其中記錄了所有可能的數(shù)據(jù)類型。這些類型中,目前已定義的有15種,包括導出表、導入、資源表、異常表、屬性證書表、重定位表、調(diào)試數(shù)據(jù)、Architecture、Global Ptr 、線程局部存儲、加載配置表、綁定導入表、IAT、延遲導入表和CLR運行時頭部。
3.2.4 ?節(jié)
無論是結構化程序設計,還是面向對象程序設計,都抵償數(shù)據(jù)與程序獨立性,因此,程序中的代碼和數(shù)據(jù)通常是分開存放的。為了保證程序執(zhí)行的安全,保障內(nèi)核的穩(wěn)定,Windows操作系統(tǒng)通常對不同用途的數(shù)據(jù)設置不同的訪問權限。比如,代碼段中的字節(jié)碼在程序運行的時候,一般不允許用戶進行修改,數(shù)據(jù)段則允許在程序運行過程中讀和寫,常量只能讀等。Windows操作系統(tǒng)在加載可執(zhí)行程序時,會為這些具有不同屬性的數(shù)據(jù)分配標記有不同屬性的頁面(當然,相同屬性的數(shù)據(jù)可能會被放到同一個頁面中),以確保程序運行時的安全。正式基于這個原因,PE中才錯線了所謂的節(jié)的概念。
節(jié)就是存放不同類型數(shù)據(jù)(比如代碼、數(shù)據(jù)、常量、資源等)的地方,不同的節(jié)具有不同的訪問權限。節(jié)是PE文件中存放代碼或數(shù)據(jù)的基本單元。例如,一個目標文件中的所有代碼可以組合成單個節(jié),或者每個函數(shù)單獨占一個節(jié)(如果編譯器行為允許)。增加節(jié)的數(shù)目會增加文件的開銷,但是鏈接器在鏈接代碼時會有更大的選擇余地。一個節(jié)中的所有原始數(shù)據(jù)必須被加載到連續(xù)的內(nèi)存空間中。
從操作系統(tǒng)加載角度來看,節(jié)是相同屬性的組合。與數(shù)據(jù)目錄不同的是,盡管有些數(shù)據(jù)類型不同,分別屬于不同的數(shù)據(jù)目錄,但由于其訪問屬性相同,便被歸類到同一個節(jié)中。這個節(jié)最終可能會占用一個或多個頁面;但無論多少個,所有相關頁面均會被賦予相同的頁屬性。這些屬性包括只讀、只寫、可讀、可寫等。
匯編語言中以‘.’開頭的一些偽指令其實就是在聲明不同數(shù)據(jù)類型。比如.data聲明的是初始化的數(shù)據(jù),.data ? 聲明的是未初始化的數(shù)據(jù),.code聲明的是可執(zhí)行的代碼等。Windows操作系統(tǒng)在裝載PE文件時會對這些數(shù)據(jù)執(zhí)行拋棄、合并、新增、復制等操作。這些不同的操作交叉組合導致了內(nèi)存的節(jié)和文件的節(jié)會出現(xiàn)很大的不同。例如.data?的數(shù)據(jù)在磁盤中不存在,但在內(nèi)存中存在,。reloc重定位表數(shù)據(jù)卻恰恰相反。
3.2.5 ?對齊
????對齊這個概念并非只是在PE結構沖出現(xiàn),許多文件格式都會有對齊的要求。有的對齊是為了美觀,有的對齊是為了效率。PE中規(guī)定了三類對齊:數(shù)據(jù)在內(nèi)存中對齊、數(shù)據(jù)在文件中對齊、資源文件中資源數(shù)據(jù)的對齊。
1.內(nèi)存對齊
由于Windows操作系統(tǒng)對內(nèi)存屬性的設置以頁為單位,所以通常情況下,節(jié)在內(nèi)存中的對齊單位必須至少是一個頁的大小。對32位的系統(tǒng)來說是4KB(1000h),而對于64位操作系統(tǒng)來說,這個值就是8KB(2000h)。
2.文件對齊
相對來說,節(jié)在磁盤文件中的對齊尺寸沒有那么嚴格。為了提高磁盤利用率,通常情況下,定義的節(jié)在文件中的對齊單位要遠小于內(nèi)存對齊的單位;通常會以一個屋里扇區(qū)的大小作文對齊粒度的值,即512字節(jié),十進制表示為200h。這就是我們在第一章中看到的數(shù)據(jù)段、代碼段等其實地址都是200h的倍數(shù)的原因了。
出于節(jié)約資源的考慮,操作系統(tǒng)允許節(jié)在內(nèi)存和文件中的對齊尺寸不一致。這就直接造成了PE在文件中和在內(nèi)存中的大小也會不一致。通常情況下,PE在內(nèi)存中的尺寸要比文件的尺寸大。用戶可以自己定義這些對齊的值。
[如果內(nèi)存對齊被定義為小于操作系統(tǒng)頁的大小,則文件對齊和內(nèi)存對齊的值必須一致!]
3.資源數(shù)據(jù)對齊
資源文件中,資源字節(jié)碼部分一般要求以(4個字節(jié))方式對齊,在資源表部分(詳見7章)我們會詳細解釋。
3.2.6 ?Unicode字符串
基本概念,略,請自行百度。
本書的所有程序都使用一個字節(jié)來表示字符串中的字符,稱為ACSI字符串。PE格式中設計字符串的部分云彩用ANSI字符串。然而在資源表中,對菜單名、對話框標題等的表述則全部使用Unicode字符串。所以,在讀取這些資源的字符串時,首先要使用一些API進行轉換。
?
3.3 ?PE文件結構
PE經(jīng)歷了從16位系統(tǒng)到32位系統(tǒng)的過渡,因此,32位系統(tǒng)下的每一個PE文件都可以在16位系統(tǒng)下運行。盡管PE文件的結構一樣,但從不同的角度來看其結構的劃分卻并不一樣。
3.3.1 ?16位系統(tǒng)下的PE結構
DOS頭部分的存在見證了PE的強大兼容性。為了保持與16位系統(tǒng)的兼容,在PE里依舊保留了16位系統(tǒng)下的標準可執(zhí)行程序執(zhí)行時所必須的文件頭部(DOS MZ頭)和指令代碼(DOS Stub)。
在16位系統(tǒng)下,PE結構可以大致分為兩部分:DOS頭和榮譽數(shù)據(jù):
?
?
如上圖所示,在16位系統(tǒng)下,PE的四部分內(nèi)容被重新組合成兩部分-可以在16位系統(tǒng)下運行的DOS頭和冗余數(shù)據(jù)。把Windows下的PE文件存儲到DOS系統(tǒng)并運行,它就是DOS系統(tǒng)下的一個EXE文件。
DOS頭分為兩部分,DOS MZ頭和DOS Stub(即指令字節(jié)碼)。大部分情況下,這些指令實現(xiàn)的功能都非常簡單,根本不會涉及到重定位信息。在往后的PE頭和PE數(shù)據(jù)去可以看做是16位系統(tǒng)下的可執(zhí)行文件的冗余數(shù)據(jù)。
1.DOS MZ頭
在Windows的PE格式中,DOS MZ頭的定義如下:
?
如上所示,加粗部分在16位系統(tǒng)下是沒有定義的。由于其開始的標志為“MZ”,所以稱它為DOS MZ 頭。
2.DOS Stub
?
由于DOS Stub的大小不固定,因此DOS頭的大小也是不固定的。DOS Stue部分是該程序在DOS系統(tǒng)下運行的指令字節(jié)碼。
3.3.2 ?32位系統(tǒng)下的PE結構
在16位系統(tǒng)中,PE頭和PE數(shù)據(jù)部分被當成是用于數(shù)據(jù);在32位系統(tǒng)中,剛好相反,即DOS頭稱為冗余數(shù)據(jù)。所謂冗余,是針對DOS頭不參與32位系統(tǒng)運行過程而言的。盡管該部分不參與運行,但是也不能把這些數(shù)據(jù)從PE結構中出去。因為在DOS MZ頭中有一個字段非常重要,即IMAGE_DOS_HEADER.e_ifanew,如果沒有它操作系統(tǒng)就定位不到標準的PE頭部,可執(zhí)行程序也就會被操作系統(tǒng)認為是非法的PE映像。
1.定位標準PE頭
由于DOS Stub的長度不固定,導致了DOS頭也不是一個固定大小的數(shù)據(jù)結構,那么,在Windows PE中,既然把DOS頭放在了PE的起始位置,如何去定位后面的標準PE頭所在的位置呢?字段e_ifanew即起這個作用。該字段的值是一個相對偏移量,絕對定位時需要增加上DOS MZ 頭的基地址。也就是說,通過以下公式可以得出PE頭的絕對位置:
PE_start=DOS MZ基地址+IMAGE_DOS_HEADER.e_ifanew
該節(jié)是以PE開頭的。
?
2.PE文件結構
在32位系統(tǒng)下,最重要的部分就是PE頭和PE數(shù)據(jù)區(qū)。隨著講解不斷深入,下圖也會被不斷第細化和豐富。
?
如上圖所示,32位系統(tǒng)下的PE文件結構被劃分為5個部分,包括:
DOS MZ頭、DOS Stue 、PE頭 、節(jié)表和節(jié)內(nèi)容。
節(jié)表和節(jié)內(nèi)容兩部分其實就是之前圖中所示的PE數(shù)據(jù)區(qū)。DOS MZ頭的大小是64個字節(jié),PE頭的大小是456個字節(jié)(由于數(shù)據(jù)目錄項不一定是16個,所以準確地說,PE頭也是一個不能確定大小的結構,該結構的實際大小由字段IMAGE_FILE_HEADER.SizeOfOptionalHeader來確定)。節(jié)表的大小之所以不固定,是因為每個PE中節(jié)的數(shù)量是不固定的。每個節(jié)的表述信息則是個固定值,共40個字節(jié),節(jié)表是有不確定數(shù)量的節(jié)表述信息組成的,其大小等于節(jié)的數(shù)量*40,節(jié)的數(shù)量字段IMAGE_FILE_HEADER.NumberOfSections來定義。DOS Stue和節(jié)內(nèi)同都是大小不確定的。
節(jié)表是PE中所有節(jié)的目的,每個目錄都是一個BookStore,其字節(jié)碼就是節(jié)內(nèi)容。它按照目錄里的指針指向的地址,分別將節(jié)的字節(jié)碼放在文件空間中排列起來,從而組成了一個完整的PE文件。PE文件頭部等于DPS頭+PE頭。
3.3.3 ?程序員眼中的PE結構
在程序員眼中,PE文件格式是有許多數(shù)據(jù)結構組成的,數(shù)據(jù)結構是一系列有組織的數(shù)據(jù)的集合:
?
如圖所示,一個標準的PE文件一般有四大部分組成:
DOS頭
PE頭(IMAGE_NT_HEADERS)
節(jié)表(多個IMAGE_SECTION_HEADER結構)
節(jié)內(nèi)容
其中,PE頭的數(shù)據(jù)結構最為復雜。簡單來說,PE頭包含:
4個字節(jié)的表示符號(Signature)
20個字節(jié)的基本頭信息(IMAGE_FILE_HEADER)
216個字節(jié)的擴展頭信息(IMAGE_OPTIONAL_HEADER32)
[
??PE文件頭部=DOS頭+PE頭+節(jié)表
??PE文件身體=節(jié)內(nèi)容
]
節(jié)內(nèi)容中會出現(xiàn)各種不同的數(shù)據(jù)結構,如導入表、導出表、資源表、重定位表等。這些后續(xù)介紹。
《新程序員》:云原生和全面數(shù)字化實踐50位技術專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Windows Pe 第三章 PE头文件(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows核心编程 第六章 线程基础
- 下一篇: AsSystemRum 系统提权工具 实