PE文件:重定位表(爲什麼需要重定位和如何重定位)

0x00 結構

位於數據目錄的第6項。

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;//RVA
    DWORD   SizeOfBlock;   //定位整個重定位表的大小
   // WORD    TypeOffset[1];   //重定位偏移
} IMAGE_BASE_RELOCATION,* PIMAGE_BASE_RELOCATION;

VirtualAddress:當前頁面起始地址的RVA值(“基址”),本塊中所有重定位項中的12位地址加上這個起始地址後就得到了真正的RVA值。

首先VirtualAddress如何設計的:
比如我們有地址 101234 101235 101236 這種修正的地址有10000個.
那麼每個地址有4個字節的. 那麼 4 * 10000 = 4萬個字節. 也就是我們要準備一張4萬個字節的表來保存重定位的.
但是我們發現一個規律.我們要修正的表的偏移都很近, 1234 1235 …
那麼我們可不可以這樣那. 我們把 100000取出來. 兩個字節存儲1234 另外兩個地址存儲1235,不用準備四個字節了.小的偏移我們兩個字節存儲.這樣的話我們的表的字節就會縮小一半.
VirtuallAddress 就是存儲了 100000這個值,也就是需要 ““基址”” 公用的地址. SizeofBlock
就是下面的偏移由多大, 我們要修正的偏移是 VirtualAddress + sizeofBlock下面的值.
如下圖:
我們的重定位表,需要修正的基址是 0x11000,大小是54. 那麼需要修正的偏移是 “36b0” “36bc” “36e0”…
我們基址 + 偏移就是要修正的位置.
在這裏插入圖片描述
如果有n個重定位項,則只需要2n+4+4個字節(2n字節個地址+4字節頁面起始地址+4字節的重定位項的個數)

SizeOfBlock:重定位塊中重定位表項的數量。
TypeOffset:當前需要重定位數據的位置偏移,該值低12位加上VirtualAddress纔是需要重定位數據的RVA。
在這裏插入圖片描述
其中最後一項VirtualAddress和SizeOfBlack都爲0.

0x01 基址重定位

爲什麼重定位?
重定位就是修正PE文件的地址。
PE文件有着默認的基址(ImageBase默認爲0x40000000),理論上當PE要加載的時候,就會佔據這個地址,但是當這個地址因爲一些原因,被佔用而不能被加載時,PE文件就被加載到其他地方了,這時候就需要基址重定位了。
如何重定位?
如果基址OldImageBase發生變化,PE文件被加載到新的基址NewImageBase。因爲查詢的都是絕對地址VA(在查詢PE文件的時候,用的都是直接地址VA),這基址變化的過程中,VA會變化,但是RVA不會變。
所以NewVA就可以通過下面這個式子來求得:

NewVA=OldVA-OldImageBase+NewImageBase

也就是重定位表中的地址數據=原數據-原基址+新基址。

0x02 重定位表定位

位於數據目錄的第六項。
在這裏插入圖片描述

重定位表RVA=選項頭.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;

注意:
1.應用場合:
凡是涉及到直接尋址的指令都需要進行基址重定位處理;
2.EXE文件不存在重定位表:對於EXE文件來說,每個文件總是使用獨立的虛擬地址空間,所以EXE總是能夠按照這個地址裝入,這意味着EXE 文件不再需要重定位信息。

DLL文件需要重定位表:對於DLL文件來說,由於多個DLL文件全部使用宿主EXE文件的地址空間,不能保證裝入地址沒有被其他DLL使用, 所以DLL文件必須包含重定位表。
3.同一系統的kernel32.dll、user32.dll等會被加載到自身固有的IB,所以系統的DLL實際上並不會發生重定位問題。
👴就是個👶👶,難頂。

參考:《WindowsPE權威指南》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章