1. 程式人生 > >PE檔案結構(五)基址重定位

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]   0338h

TypeOffset[2]   0340h

     ........

通過Type低12位+VirtualAddress 可以知道前三個的地址為1033h,1038h,1040h 。

再來看看圖片1中Demo.dll的程式碼,可以發現1033h就是圖片1中的push 10006040中的10006040,1038h就是push 10006030中的10006030 。

    如果載入dll,發現不是使用預設的基地址,PE載入器就會把基址重定位表中所寫的地址的值改掉。改掉方法是把原先的值加上 實際基地址 - 預設基地址 的值。