小甲魚PE詳解之區塊描述、對齊值以及RVA詳解(PE詳解06)

各種區塊的描述:

很多朋友喜歡聽小甲魚的PE詳解,因爲他們覺得課堂上老師講解的都是略略帶過,繞得大家雲裏霧裏~剛好小甲魚文采也沒課堂上的教授講的那麼好,只能以比較通俗的話語來給大家描述~

通常,區塊中的數據在邏輯上是關聯的。PE 文件一般至少都會有兩個區塊:一個是代碼塊,另一個是數據塊。每一個區塊都需要有一個截然不同的名字,這個名字主要是用來表達區塊的用途。例如有一個區塊叫.rdata,表明他是一個只讀區塊。注意:區塊在映像中是按起始地址(RVA)來排列的,而不是按字母表順序。

另外,使用區塊名字只是人們爲了認識和編程的方便,而對操作系統來說這些是無關緊要的。微軟給這些區塊取了個有特色的名字,但這不是必須的。當編程從PE 文件中讀取需要的內容時,如輸入表、輸出表,不能以區塊名字作爲參考,正確的方法是按照數據目錄表中的字段來進行定位。


下表中的區塊名稱以及意義:









當然我們在Visual C++ 中也可以自己命名我們的區塊,用#pragma 來聲明,告訴編譯器插入數據到一個區塊內,格式如下:
        #pragma data_msg( "FC_data" )


大家還記得吧,#爲宏處理符號,啥是宏?簡單的說就是編譯器的時候由編譯器直接先進行翻譯。或許說按照指定的格式機械替換。嘻嘻,學破解要懂編程吶~

以上語句告訴編譯器將數據都放進一個叫“FC_data” 的區塊內,而不是默認的.data 區塊。區塊一般是從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 值,就得到了真正的文件偏移地址。

爲節省筆墨和時間,以上步驟將在視頻中具體演示……

通過上述三個步驟,我們可以寫得出程序……
發佈了19 篇原創文章 · 獲贊 14 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章