PE文件基址重定位(Base Relocation),程序編譯時每個模塊有一個優(yōu)先加載地址ImageBase,這個值是連接器給出的,因此連接器生成的指令中的地址是在假設模塊被加載到ImageBase前提之下生成的,,那么一旦程序沒有將模塊加載到ImageBase時,,那么程序中 的指令地址就需要重新定位,例如:假設一個可執(zhí)行文件,,基址是0x400000,在這個image偏移0x1234處是一個指針,,指向一個字符串,字符串始于實際地址0x404002處,,所以指針應該是0x404002,加載文件時,,由于種種原因,加載器決定把他加載到0x600000處,,連接器假設的地址和實際的地址之差成為delta,上例delta為0x200000,,整個位置提高了0x200000,那么字符串位置應該為0x604002,原來指向字符串的指針就錯誤了,所以要把delta加到指針值中,,為了讓加載器有這樣的能力做調(diào)整,,可執(zhí)行文件內(nèi)含許多個【基址重定位項】,給那些存放指針的位置使用,,加載器必須把delta加載到各個基址上,。本例中應該把0x200000加給原來的指針值,0x404002,并將0x604002寫回原處,。
下面我們來介紹一下【基址重定位項】,,加載器就是利用它來知道模塊是否按預期的位置加載,哪些指令是需要修改的,。因此我們研究的重點將是【基址重定位項】,,首先加載器也是通過數(shù)據(jù)目錄來定位【基址重定位項】,【基址重定位項】被包裝為一系列連續(xù)區(qū)段,,每一個區(qū)段來描述一個4K PAGE(也就是一頁)的重定位信息,,長短不一(每頁中需要重定位的指令數(shù)目也不一樣),它們以一個IMAGE_BASE_RELOCATION結(jié)構(gòu)作為開始,,格式如下: DWORD VirtualAddress重定位內(nèi)存頁的起始RVA,每一個【基址重定位項】的偏移位置(即下面的TypeOffset的低12位,,它是指令相對于它所在頁的第一條指令的偏移),必須加上重定位頁的RVA才是一個真正的RVA,指向【基址重定位項】 DWORD SizeOfBlock:結(jié)構(gòu)大小,在加上跟著后面的所有【基址重定位項】(都是WORDS),,為了決定【基址重定位項】的個數(shù),,=(SizeOfBlock-Sizeof(IMAGE_BASE_RELOCATION)(8個字節(jié)))/2(WORD占2個字節(jié));例如此值為44,則個數(shù)為44-8/2=18. 總結(jié):IMAGE_BASE_RELOCATION包含兩個成員,,一個是VirtualAddress,包含自身內(nèi)存頁起始位置RVA,另一個SizeOfBlock,表明這個結(jié)構(gòu)有多大。 WORD TypeOfOffset 這并不是單獨一個WORD,,而是一個WORDS組,,數(shù)組元素個數(shù)可以有上一個式子計算得到,每一個WORD的最底部12位代表【基址重定位項】的位置偏移,,但必須在加上IMAGE_BASE_RELOCATION表頭中VirtualAddress,最高4位是【基址重定位項】的型態(tài),。對于在Intel CPU中的PE文件,你將看到兩種狀態(tài),,0(IMAGE_REL_BASED_ABSOLUTE)此一【基址重定位數(shù)據(jù)項】無意義,,只是用來充數(shù)而已,使所有【基址重定位項】總數(shù)為DWORD倍數(shù),。3(IMAGE_REL_BASED_HIGNLOW):把delta值加到欲計算的RVA值,,另外還有其他狀態(tài)在WINNT.h中,它們大部分是給i386以外的的CPU使用,。 下面給出一些【基址重定位項】,,請注意其中的RVA已經(jīng)被IMAGE_BASE_RELOCATION中的VirtualAddress校正過。 VirtualAddress:00001000 Size0000012C 000001032 HIGHLOW 00000106D HIGHLOW 0000010AF HIGNLOW ...... VirtualAddress:00002000 Size0000009C 000020A6 HIGHLOW 00002110 HIGHLOW 00002136 HIGHLOW 00002156 HIGHLOW ........ VirtualAddress:000003000 Size00000114 0000300A HIGHLOW 0000301E HIGHLOW 0000303B HIGHLOW 0000306A HIGHLOW 通過上面的例子我們可以看到相鄰區(qū)段正好相差0X1000,,也就是4K,,證實了上面所說的“每一個區(qū)段描述image一個4K Page(也就是一頁)的重定位信息”同時我們可以看到第一個區(qū)段的VirtualAddress是00001000,正好是.text起始RVA,。 現(xiàn)在問題基本明白了,,一旦模塊沒有價加載到預期地址,編譯器就會根據(jù)【基址重定位項】去修正哪些需要修正的指令,,這樣程序就可以正常執(zhí)行了,。
|
|
來自: herowuking > 《Cracker》