PE文件詳解四:PE詳解之區塊描述、對齊值以及RVA詳解


通常,區塊中的數據在邏輯上是關聯的。PE 文件一般至少都會有兩個區塊:一個是代碼塊,另一個是數據塊。每一個區塊都需要有一個截然不同的名字,這個名字主要是用來表達區塊的用途。例如有一個區塊 叫.rdata,表明他是一個只讀區塊。注意:區塊在映像中是按起始地址(RVA)來排列的,而不是按字母表順序。
另外,使用區塊名字只是人們為 了認識和編程的方便,而對操作系統來說這些是無關緊要的。微軟給這些區塊取了個有特色的名字,但這不是必須的。當編程從PE 文件中讀取需要的內容時,如輸入表、輸出表,不能以區塊名字作為參考,正確的方法是按照數據目錄表中的字段來進行定位。


各種區塊的描述:

區塊一般是從OBJ 文件開始,被編譯器放置的。鏈接器的工作就是合並左右OBJ 和庫中需要的塊,使其成為一個最終合適的區塊。鏈接器會遵循一套相當完整的規則,它會判斷哪些區塊將被合並以及如何被合並。

合並區塊:
鏈 接器的一個有趣特征就是能夠合並區塊。如果兩個區塊有相似、一致性的屬性,那么它們在鏈接的時候能被合並成一個單一的區塊。這取決於是否開啟編譯器的 /merge 開關。事實上合並區塊有一個好處就是可以節省磁盤的內存空間……注意:我們不應該將.rsrc、.reloc、.pdata 合並到++的區塊里。


區塊的對齊值:

之前我們簡單了解過區塊是要對齊的,無論是在內存中存放還是在磁盤中存放~但他們一般的對齊值是不同的。

PE 文件頭里邊的FileAligment 定義了磁盤區塊的對齊值。每一個區塊從對齊值的倍數的偏移位置開始存放。而區塊的實際代碼或數據的大小不一定剛好是這么多,所以在多余的地方一般以00h 來填充,這就是區塊間的間隙。

例 如,在PE文件中,一個典型的對齊值是200h ,這樣,每個區塊都將從200h 的倍數的文件偏移位置開始,假設第一個區塊在400h 處,長度為90h,那么從文件400h 到490h 為這一區塊的內容,而由於文件的對齊值是200h,所以為了使這一區塊的長度為FileAlignment 的整數倍,490h 到 600h 這一個區間都會被00h 填充,這段空間稱為區塊間隙,下一個區塊的開始地址為600h 。

PE 文件頭里邊的SectionAligment 定義了內存中區塊的對齊值。PE 文件被映射到內存中時,區塊總是至少從一個頁邊界開始。

一般在X86 系列的CPU 中,頁是按4KB(1000h)來排列的;在IA-64 上,是按8KB(2000h)來排列的。所以在X86 系統中,PE文件區塊的內存對齊值一般等於 1000h,每個區塊按1000h 的倍數在內存中存放。


RVA 和文件偏移的轉換

在前邊我們探討過RVA 這個詞,但對於初次接觸PE 文件的朋友來說,顯得尤其陌生和無奈。中國人不喜歡老外的縮寫,但總要**着接受……不過,在有了前邊知識的鋪墊之后,現在來談這個概念大家伙應該能夠得心應手了。起碼不用顯得那么的費解和無奈~

RVA 是相對虛擬地址(Relative Virtual Address)的縮寫,顧名思義,它是一個“相對地址”。PE 文件中的各種數據結構中涉及地址的字段大部分都是以 RVA 表示的,有木有??

更 為准確的說,RVA 是當PE 文件被裝載到內存中后,某個數據位置相對於文件頭的偏移量。舉個例子,如果 Windows 裝載器將一個PE 文件裝入到 00400000h 處的內存中,而某個區塊中的某個數據被裝入 0040**xh 處,那么這個數據的 RVA 就是(0040**xh - 00400000h )= **xh,反過來說,將 RVA 的值加上文件被裝載的基地址,就可以找到數據在內存中的實際地址。

DOS 文件頭、PE 文件頭和區塊表的偏移位置與大小均沒有變化。而各個區塊映射到內存后,其偏移位置就發生了變化。

RVA 使得文件裝入內存后的數據定位變得方便,然而卻給我們要定位位於磁盤上的靜態PE 文件帶來了麻煩。舉個例子說話:……由於例子在視頻中,這里爭取時間我就不寫啦,大伙看參考視頻演示吧。


如何換算 RVA 和文件偏移呢?

當處理PE 文件時候,任何的 RVA 必須經過到文件偏移的換算,才能用來定位並訪問文件中的數據,但換算卻無法用一個簡單的公式來完成,事實上,唯一可用的方法就是最土最笨的方法:

步 驟一:循環掃描區塊表得出每個區塊在內存中的起始 RVA(根據IMAGE_SECTION_HEADER 中的VirtualAddress 字段),並根據區塊的大小(根據IMAGE_SECTION_HEADER 中的SizeOfRawData 字段)算出區塊的結束 RVA(兩者相加即可),最后判斷目標 RVA 是否落在該區塊內。

步驟二:通過步驟一定位了目標 RVA 處於具體的某個區塊中后,那么用目標 RVA 減去該區塊的起始 RVA ,這樣就能得到目標 RVA 相對於起始地址的偏移量 RVA2.

步驟三:在區塊表中獲取該區塊在文件中所處的偏移地址(根據IMAGE_SECTION_HEADER 中的PointerToRawData 字段), 將這個偏移值加上步驟二得到的 RVA2 值,就得到了真正的文件偏移地址。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM