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