PE檔案結構(五)基址重定位
PE檔案結構(五)
參考
書:《加密與解密》
視訊:小甲魚 解密系列 視訊
基址重定位
連結器生成一個PE檔案時,它會假設程式被裝入時使用的預設ImageBase基地址(VC預設exe基地址00400000h,dll基地址10000000h),並且會把程式碼中所有指令中用到的地址都使用預設的基地址(例如 程式程式碼中 push 10001000,就是把10000000h當做了基地址,把push 10001000寫入到檔案中)。如果一個exe程式中一個dll裝載時的地址與其它dll地址發生衝突(因為windows程式是虛擬地址空間,exe一般不會有地址衝突,載入dll時可能會有地址衝突),就需要修改程式碼中的地址,如push 10001000,call 10002000等。這時就需要用進行基址重定位。而基址重定位表中存放了,如果預設地址被改,需要修改的程式碼的地址。在PE檔案中,基址重定位表一般放在一個單獨的 ".reloc" 區,可以通過IMAGE_OPTIONAL_HEADER 中 的DataDirectory[5] 檢視 基址重定位表 的RVA。
例如:
用W32Dasm 檢視 Demo.dll (下載地址:http://pan.baidu.com/s/1qWDepo4)
圖片1
可以發現MyMessageBox 這個函式,看看它的程式碼中的push 10006040 , push 10006030 中的地址是指向字串的。如果一個程式在載入Demo.dll時因為Demo.dll 預設的地址被佔用了,而使用其它的基地址,例如使用20000000h作為基地址,Demo.dll就從20000000h開始裝載。這樣字串“Demo”和“Hello World!” 就不是在10006040h跟10006030h中了,這時就需要把push 10006040 , push 10006030改成push 20006040 , push 20006030 。
基址重定位表是由一個一個IMAGE_BASE_RELOCATION結構 構成的。
圖片2
IMAGE_BASE_RELOCATION 結構:
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
// WORD TypeOffset[];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
其中 VirtualAddress 表示 這一組地址的起始RVA。SizeOfBlock表示當前這個IMAGE_BASE_RELOCATION 結構的大小。TypeOffset是一個數組,它的元素個數就是( SizeOfBlock - 8 ) / 2 ,TypeOffset 每一個元素佔用兩個位元組即16位,其中高4位表示重定位型別(一般都為3),低12位表示重定位地址。
例項分析:
檢視Demo.dll的第一個 IMAGE_BASE_RELOCATION 結構
圖片3
可以發現:
VirtualAddress 為1000h
SizeOfBlock 為 0164h
TypeOffset[0] 0333h 即 3是重定位型別 33h為重定位地址
TypeOffset[1] 0338hTypeOffset[2] 0340h
........
通過Type低12位+VirtualAddress 可以知道前三個的地址為1033h,1038h,1040h 。
再來看看圖片1中Demo.dll的程式碼,可以發現1033h就是圖片1中的push 10006040中的10006040,1038h就是push 10006030中的10006030 。
如果載入dll,發現不是使用預設的基地址,PE載入器就會把基址重定位表中所寫的地址的值改掉。改掉方法是把原先的值加上 實際基地址 - 預設基地址 的值。