24. PE结构-PE详解之基址重定位详解
問題一:什么是基址重定位?
 答:重定位就是你本來這個程序理論上要占據(jù)這個地址,但是由于某種原因,這個地址現(xiàn)在不能讓你霸占,你必須轉(zhuǎn)移到別的地址,這就需要基址重定位。打個比方:例如你現(xiàn)在計(jì)劃在某某地方建一棟樓,但是有一天你收到上邊的通知,這個地方政府臨時(shí)要征用建公廁,所以這時(shí)候你就沒轍,得去別的地方建啦~
?
問題二:為什么需要基址重定位?
 答:其實(shí)這個問題看起來跟前邊的有點(diǎn)重復(fù)不是? 但是有些朋友可能會這么說,老濕你的言論是可以,但是放在程序中,你上節(jié)課不是還說每個程序都讓W(xué)indows 欺騙了嗎 —— 每個程序覺得自己都完全占有 4GB的內(nèi)存空間,何來地址被別的程序占據(jù)了呢?!?
 首先,能夠提出問題的朋友都是值得表揚(yáng)和鼓勵的
 但是,上節(jié)課我們談了什么內(nèi)容呢 ??談了導(dǎo)出表,為什么會出現(xiàn)導(dǎo)出表呢 ? 正是因?yàn)橛蠨LL 這類破壞別人家庭幸福的“小三”的存在~?
 我們之前談過,動態(tài)鏈接庫它自己是沒有占據(jù)任何似有空間的,都是寄生在應(yīng)用程序的私有空間里邊。那寄生在別人家里,睡在哪里就肯定不是小三說了算啦,肯定要由主人決定不是? 所以,在小三的眼里,不用說,肯定永遠(yuǎn)都睡在大房,但客觀事實(shí)告訴我們,經(jīng)常只能住臥室~(有點(diǎn)扯遠(yuǎn)了,其實(shí)想說的是,基址重定位就是這么被需求的^_^)
?
問題三:我們需要對程序中的哪些語句(指令)進(jìn)行基址重定位呢?
 答:請先看下圖
這是上節(jié)課我們用到的動態(tài)鏈接庫 Counter.dll 文件,對其用W32Dasm 進(jìn)行反匯編的截圖。我們分析下,有哪些語句是需要我們來進(jìn)行基址重定位的呢 ?
 答案是——但凡涉及到直接尋址的指令都需要進(jìn)行重定位處理!注意直接尋址和間接尋址。
 那么我們再過頭來看下圖片,一眼就能掃出以下指令需要對其進(jìn)行重定位:
 :10001026 FF0500300010??????????? inc dword ptr [10003000]
 :1000102C FF3500300010??????????? push dword ptr [10003000]
 :1000103D A100300010????????????? mov eax, dword ptr [10003000]
 :10001049 FF0D00300010??????????? dec dword ptr [10003000]
 :1000104F FF3500300010??????????? push dword ptr [10003000]
 :10001060 A100300010????????????? mov eax, dword ptr [10003000]
 :1000106A FF2500200010??????????? Jmp dword ptr [10002000]
那有些朋友可能會問了,類似于“:10001038 E8CFFFFFFF??????? call 1000100C”的指令,為什么后邊顯示的是call + 地址,而機(jī)器碼卻不包含地址信息呢? CPU神了? 莫非地址信息被加密了? 其實(shí)不是的,學(xué)過匯編的朋友不知道還記不記得,在講call 原理的時(shí)候用了大部分時(shí)間在談幾種跳轉(zhuǎn),其中經(jīng)常遇到的就是“地址+偏移”的形式。那這就能有個說得通的解釋了:CFFFFFFFh 事實(shí)上就是一個偏移地址,記得咱這是little-edition,轉(zhuǎn)換過來就是FFFF FFCFh,也就是等于-31h。那么1000103Dh - 31h == 1000100Ch,Perfect! ^_^
 問題四:系統(tǒng)對一條指令進(jìn)行重定位需要哪些信息?
 答:我們還是拿上邊那張圖片來說事兒,我們說了上邊的那些指令需要重定位,現(xiàn)在就假設(shè)重定位后的基地址由原來的10000000h 變?yōu)?20000000h了,那么類似這樣的語句:inc dword ptr [10003000]?應(yīng)該改成?inc dword ptr [20003000]?。
 注意,重定位的算法我們可以總結(jié)為:將直接尋址指令中的雙字地址加上模塊的實(shí)際裝入地址與模塊建議裝入地址之差。
 從上邊的信息中我們看到,需要進(jìn)行重定位需要三個因素:
 1. 需要修正的地址(10003000h)
 2. 建議裝入的地址(10003000h)
 3. 實(shí)際裝入的地址(20003000h)
 問題五:這些信息哪些應(yīng)該被保存在重定位表中?
 聰明的我們可以發(fā)現(xiàn):
 1. 建議裝入的地址在PE 文件頭中已經(jīng)定義了
 2. 實(shí)際裝入的地址在沒有被裝載器裝入我們根本無從得知,也就是說這事天不知地不知我們不知只有裝載器知道……
 因此,我們可以得到的結(jié)論是:PE 文件的重定位表(Base Relocation Table)中保存的就是文件中所有需要進(jìn)行重定位修正的代碼的地址。
基址重定位結(jié)構(gòu)表
IMAGE_BASE_RELOCATION STRUC
? ? ? VirtualAddress ?? ??? DWORD??????? ?? ; 重定位數(shù)據(jù)開始的RVA 地址
 ? ? ? SizeOfBlock?????????? DWORD? ? ? ? ??? ; 重定位塊得長度
 ? ? ? TypeOffset? ? ? ? ? ? ?WORD? ? ? ? ? ??? ;? 重定項(xiàng)位數(shù)組
 IMAGE_BASE_RELOCATION? ENDS
VirtualAddress 是 Base Relocation Table 的位置它是一個 RVA 值;
 SizeOfBlock 是 Base Relocation Table 的大小;
 TypeOffset 是一個數(shù)組,數(shù)組每項(xiàng)大小為兩個字節(jié)(16位),它由高 4位和低 12位組成,高 4位代表重定位類型,低 12位是重定位地址,它與 VirtualAddress 相加即是指向PE 映像中需要修改的那個代碼的地址。
IMAGE_REL_BASED_ABSOLUTE?????????? (0) 使塊按照32位對齊,位置為0。
 IMAGE_REL_BASED_HIGH????????? ????????? (1) 高16位必須應(yīng)用于偏移量所指高字16位。
 IMAGE_REL_BASED_LOW??????????????????? (2) 低16位必須應(yīng)用于偏移量所指低字16位。
 IMAGE_REL_BASED_HIGHLOW??????????? (3) 全部32位應(yīng)用于所有32位。
 IMAGE_REL_BASED_HIGHADJ????????????? (4) 需要32位,高16位位于偏移量,低16位位于下一個偏移量數(shù)組元素,組合為一個帶符號數(shù),加上32位的一個數(shù),然后加上8000然后把高16位保存在偏移量的16位域內(nèi)。
 IMAGE_REL_BASED_MIPS_JMPADDR?? (5)? Unknown
 IMAGE_REL_BASED_SECTION????????????? (6)? Unknown
 IMAGE_REL_BASED_REL32????????????????? (7)? Unknown
?
實(shí)踐:
VirtualAddress:1000H
SizeOfBlock:18H? ?(計(jì)算需要多少地址需要重定義:18-8(前面暫用的8個字節(jié)),10/2,等于8)
TypeOffset01:3028H,那么重定義地址為1028=1000+28
TypeOffset01:302E
。。。
總結(jié)
以上是生活随笔為你收集整理的24. PE结构-PE详解之基址重定位详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: MySql 主从模式原理及操作步骤
- 下一篇: C/C++:Windows编程—MFC基
