PE结构基址重定位表
PE體系
PE結構&整體敘述
PE結構&導入表
PE結構&導出表
PE結構&基址重定位表
PE結構&綁定導入實現(xiàn)
PE結構&延遲加載導入表
重定位表定位
PE重定位:
向進程的虛擬內存加載PE文件時,文件會被加載到PE頭的ImageBase所指的地址處。如果是加載的DLL(SYS)文件,且在ImageBase位置處已經(jīng)加載了DLL(SYS)文件,那么PE裝載器就會將其加載到其他未被占用的空間。此時就會發(fā)生基址重定位。
使用SDK或VC++創(chuàng)建PE文件,EXE默認的ImageBase為00400000,DLL默認的ImageBase為10000000,使用DDK創(chuàng)建的SYS文件默認的ImageBase為10000。
創(chuàng)建好進程后,因為EXE文件會首先加載進內存,所以EXE文件中無需考慮基址重定位問題。但是需要考慮ASLR(地址隨機化)。對于各OS的主要系統(tǒng)DLL,微軟會根據(jù)不同版本分別賦予不同的ImageBase地址,例如同一系統(tǒng)的kernel32.dll和user32.dll等會被加載到自身固有的ImageBase,所以系統(tǒng)的DLL實際上也不會發(fā)生重定位問題
重定位表:
重定位表為數(shù)據(jù)目錄中注冊的數(shù)據(jù)類型之一,其描述信息處于數(shù)據(jù)目錄的第6個目錄項中,
重定位表所在地址RVA=0x1F000
重定位數(shù)據(jù)大小=39C
RVA轉FOA后可以得到文件偏移地址為0x9800
基本操作原理
上面三個步驟即可完成PE重定位,其中最關鍵的是查找硬編碼地址的位置,查找過程中會使用到PE文件內部的Relocation Tables(重定位表),它記錄了硬編碼地址便宜,是在PE文件構建中的編譯/鏈接階段提供的。通過重定位表查找,本質上就是根據(jù)PE頭的“基址重定位表”項進行的查找。
重定位表項IMAGE_BASE_RELOCATION
與導入表類似,重定位表指針指向的位置就是一個數(shù)組,而不像導出表一樣只有一個結構,這個數(shù)組的每一項都是如下結構:
IMAGE_BASE_RELOCATION STRUCTVirtualAddress dd ? ;重定位內存頁的起始RVASizeOfBlack dd ? ;重定位塊的長度//WORD TypeOffset[1]; //以注釋形式存在,非結構體成員,表示在該結構體下會出現(xiàn)WORD類型的數(shù)組,并且該數(shù)組元素的值就是硬編碼在程序中的地址偏移。IMAGE_BASE_RELOCATION ENDS以下是對每一項的詳細解釋。
IMAGE_BASE_RELOCATION.VirtualAddress
+0000h,雙字。重定位塊RVA。由于直接尋址指令比較多,所以在一些PE文件中,存在大量的需要修正的重定位地址。按照常規(guī)計算,每個地址占4個字節(jié),如果有n個重定位項,那么需要的空間為4 x n。在一頁中的 所有地址只需要12位(因為Win32頁面大小為1000h,也就是4096字節(jié),即2的12次方)。而這12位只需要用一個字就能表達出來。即如果有n個重定向項,則只需要 2 x n個地址+4字節(jié)的起始RVA +4字節(jié)的本頁的重定位項個數(shù)。將以上兩位情況的表達式分別是:
sum1=4xn
sum2=2xn+4+4
解釋:
sum1式子:1個重定位項就需要4個字節(jié)(每個地址占4個字節(jié)),2個重定位項就需要8個字節(jié),3個重定位項就需要12個字節(jié),4個重定位項就需要16個字節(jié)……n個重定位項就需要4xn個字節(jié)
sum2式子:在一頁里面偏移只需要兩個字節(jié),即一頁里面出現(xiàn)1個重定位項,就需要2x1個位置;一頁里面出現(xiàn)2個重定位項,就需要2x2個位置;一頁里面出現(xiàn)n個重定位項,就需要2xn個位置;
然后表示在哪一頁的話,需要4個字節(jié)的位置,即sum1=2xn+4
表示(n表示的是總的,并非哪一頁)本頁的重定位項個數(shù),又需要4個字節(jié)的位置,即sum1=2xn+4+4
(上面的式子強調的是4個字節(jié)的空間,并非強調RVA。。。)
很明顯,當有大量的重定位地址時,sum1遠大于sum2。重定位表的存儲方式就是第二種方式,字段 IMAGE_BASE_RELOCATION.VirtualAddress就是Sum2中的第一個4,也就是頁面的起始RVA
IMAGE_BASE_RELOCATION.SizeOfBlock
+0004h,雙字。這個有的資料顯示是重定位塊的大小,有的資料顯示是該頁面所有的重定向字段個數(shù),也就是第二個4。接下來我們查看一下:
從這里看出的它是重定位塊的大小,從9800~984C是第一個重定位塊的大小,984D開始就是第二個重定位塊的VirtualAddress。因為如果說個數(shù)的話,因為后面一個占了2字節(jié),那么4Cx2比這個大得多。
數(shù)組和數(shù)組直接并不是相鄰的,比如頁面1的IMAGE_BASE_RELOCATION后,并不是頁面2的IMAGE_BASE_RELOCATION,而是頁面1的所有重定位表項;每個項大小為1個字,每個字的高四位被用來說明此重定位項類型,十六才是需要重定位的數(shù)據(jù)在頁面中的地址。高四位含義如下:
在實際的PE文件中,我們只能看到0和3這兩種情況,也就是說這一項要么是對齊用,要么是需要全部全部修正。
重定位表第一項的起始代碼頁面RVA是0x11000
長度為4C
第一塊的第一個重定位項的值為0x379F,其中高四位為3,轉換為二進制代碼是0011,表示該重定位值的高位和低位均需要修正。低十二位為修正地址,該地址加上地址再加上代碼頁面的起始地址即為代碼在內存的實際位置VA值。
VirtualAddress(11000) + Offset(79F) = 1179F(RVA)
然后再找點后面的,盡量算在main函數(shù)里面去,這樣可以調試,即0x3929,0x3938
VirtualAddress(11000) + Offset(929) = 11929(RVA)
VirtualAddress(11000) + Offset(938) = 11938(RVA)
然后去找到RVA為11929,RVA為11938地址處:
看一下RVA 11929處,RVA為11938處是否實際存在要執(zhí)行PE重定位操作的硬編碼地址:
總結:
1.查看一下RVA 11929處,RVA為11938處硬編碼的值:
RVA 11929處硬編碼為:0x00417BD4
2.讀取數(shù)值后,減去ImageBase值:
0x00417BD4- 0x00400000= 0x17BD4
3.然后用它加上實際加載地址即可:
如:0x17BD4+0x00800000=0x817BD4
對于程序內硬編碼的地址,PE裝載器都做如上的處理,根據(jù)實際加載的內存地址修正后,將得到的值覆蓋到同一位置上。對一個IMAGE_BASE_RELOCATION結構體的所有TypeOffset都做如上處理,且對RVA 1000~2000地址區(qū)域對應的所有硬編碼地址都要進行PE重定位處理。如果TypeOffset值為0,說明一個IMAGE_BASE_RELOCATION結構體結束。至此,完成重定位流程。
《新程序員》:云原生和全面數(shù)字化實踐50位技術專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的PE结构基址重定位表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PE结构导出表
- 下一篇: TLS回调函数(2)