Windows PE第6章 栈与重定位表
第六章?棧與重定位表
? ? 本章主要介紹棧和代碼重定位。站和重定位表兩者并沒有必然的聯(lián)系,但都和代碼有關(guān)。棧描述的是代碼運(yùn)行過程中,操作系統(tǒng)為調(diào)度程序之間相互調(diào)用關(guān)系,或臨時(shí)存放操作數(shù)而設(shè)置的一種數(shù)據(jù)結(jié)構(gòu)。重定位表則是在一個(gè)PE中的代碼被加載到任意一個(gè)內(nèi)存地址時(shí),用來描述相關(guān)操作數(shù)地址變化規(guī)律的數(shù)據(jù)結(jié)構(gòu)。通過重定位技術(shù),代碼運(yùn)行在內(nèi)存中的任意位置時(shí),可以避免因操作數(shù)的定位錯(cuò)誤而導(dǎo)致失敗。
6.1棧
? ? 前面基本概念直接過...
? ? 程序在運(yùn)行的時(shí)候會(huì)為系統(tǒng)分配一塊內(nèi)存區(qū)域作為棧,由棧選擇子SS和棧定指針(esp)來確定當(dāng)前棧的大小,CPU則直接操作EBP來存取數(shù)據(jù)。
內(nèi)存中棧結(jié)構(gòu)如下:
?
? ? 壓棧時(shí)根據(jù)壓入的數(shù)據(jù)類型的字節(jié)大小,將ESP減少相應(yīng)的字節(jié)數(shù),如壓入一個(gè)雙子,則ESP-4。
? ? 相反出棧的時(shí)候是esp增加相應(yīng)的字節(jié)數(shù),如彈出一個(gè)雙字,則esp+4。
6.1.1??棧的應(yīng)用場(chǎng)合
(1)保存臨時(shí)的值
?Push?eax
?......
?Pop?eax
?
(2)保存程序現(xiàn)場(chǎng)
?CALL?_subPrg
? ? 當(dāng)指令執(zhí)行時(shí),會(huì)將緊跟在CALL指令后面的下一條指令地址壓入棧,以便于程序在調(diào)用完以后,能正確放回到主程序繼續(xù)運(yùn)行<shell?code?常用>。
(3)
? ? 傳遞函數(shù)參數(shù)
?看下面的MessageBox調(diào)用反匯編
?
下面是壓棧以后的示意圖。
? ? 當(dāng)子程序結(jié)束以后,會(huì)調(diào)用ret指令返回,eip隨之被彈出。為了平衡棧,需要調(diào)用者使用如下語句將傳入的參數(shù)一一彈出:
Add?esp,0010h??;4個(gè)整型
(4)存放過程中的局部變量
進(jìn)入一個(gè)過程后,會(huì)定義很多局部變量,而局部變量的存放處也是棧。為局部變量在棧中申請(qǐng)的內(nèi)存區(qū)域成為緩沖區(qū)。當(dāng)過程結(jié)束以后,局部變量將從棧中刪除,恢復(fù)到進(jìn)入過程最初狀態(tài)。也就是說,局部變量在過程結(jié)束以后就自動(dòng)被釋放了,原因是CPU調(diào)整了棧的棧頂指針esp。
6.1.3??棧溢出
? ? 所謂棧溢出,是指由于程序沒有考慮棧中定義的局部數(shù)據(jù)塊的大小,而向該數(shù)據(jù)塊寫入了過多的數(shù)據(jù),從而導(dǎo)致數(shù)據(jù)越界,覆蓋了棧中的已存在的其他數(shù)據(jù)的技術(shù)。這里可以shellcode,細(xì)節(jié)不說了,之前單獨(dú)總結(jié)過這里。后面都是基本定義,直接跳過,直接看重定位。
6.2??代碼重定位
? ? 代碼重定位是把可執(zhí)行代碼從內(nèi)存的一個(gè)地方移動(dòng)到另一個(gè)地方去,保證該部分代碼還能正常執(zhí)行的一種技術(shù)。用于補(bǔ)丁和病毒程序開發(fā)。
6.2.1??重定位的提出
? ? 可執(zhí)行代碼從內(nèi)存的一個(gè)地方移動(dòng)到另一個(gè)地方,所有的字節(jié)均保持不變;如果代碼指令中的某些操作數(shù)不跟隨著地址發(fā)生改變,勢(shì)必會(huì)導(dǎo)致程序運(yùn)行出錯(cuò)。這里的某些操作是指那些使用了絕對(duì)地址定位的程序指令中的操作數(shù)。如下:
????從上面可以看出,全局變量訪問直接采用了絕對(duì)地址。如果直接把這部分機(jī)器碼拷貝到另一個(gè)位置,直接執(zhí)行會(huì)出問題的,因?yàn)樾枰覀冎匦陆o代碼定位才可以。
6.2.2??實(shí)現(xiàn)重定位的方法
先看書上的姿勢(shì):
???是這樣的,大體就是用相對(duì)偏移來算的,然后下面給了特長(zhǎng)一段來解釋這個(gè),看了半天有點(diǎn)暈,我自己大體猜了下,然后用C++還原了這個(gè)場(chǎng)景。
C++代碼(就直接拿上面用過的那個(gè)例子):
然后看下反匯編:
? ? 注意被圈上的那一行,后面那個(gè)***ds:[00104F18h]是直接用的映地址寫的,每次編譯都是隨機(jī)的,我看上面書上的意思是可以根據(jù)棧彈出來的位置,也就是函數(shù)里面的某個(gè)位置來偏移過去,于是我們可以驗(yàn)證下,直接還是看上面紅色框的部分,注意這兩個(gè)值:
?
前面是代碼地址,后面是全局變量地址,我在想,這兩個(gè)差是不是固定的,于是就奪取了幾組,發(fā)現(xiàn)差真的是固定的。
00C815D4??mov?????????eax,dword?ptr?ds:[00C94F18h]??13944
000515D4??mov?????????eax,dword?ptr?ds:[00064F18h]??13944
000F15D4??mov?????????eax,dword?ptr?ds:[00104F18h]??13944
? ? so應(yīng)該大體知道啥姿勢(shì)了,于是模擬一發(fā):
? ? 先計(jì)算下偏移量:
? ? 得到如下結(jié)果:
pFunAddMark?=?0x001a15c0?{TEST_CPP_.exe!wmain(int,?wchar_t?*?*)}
pnNumber?=?0x001b4f18?{TEST_CPP_.exe!int?g_nNumber}?{1111}
? ? 然后字節(jié)嘗試測(cè)試一發(fā):
? ? 這樣看來結(jié)果沒啥問題,如果我沒理解錯(cuò)書上的那一坨匯編的話,應(yīng)該就是這么個(gè)意思,如果理解有誤希望大家留言提醒我,一起學(xué)習(xí)。
6.3??PE頭文件中的重定位表
? ? 重定位信息是在編譯的時(shí)候,由編譯器生成并被保留在可執(zhí)行文件中。當(dāng)程序執(zhí)行前,操作系統(tǒng)會(huì)根據(jù)這些重定位信息對(duì)代碼予以修正,復(fù)雜的操作由編譯器和操作系統(tǒng)代替程序完成。程序被裝入內(nèi)存時(shí),其基址是由字段IMAGE——OPTIONAL_HEADER32.imageBase決定的:
但是,如果當(dāng)裝載時(shí)該位置已經(jīng)被別的程序使用,那么操作系統(tǒng)就有權(quán)重新選擇一個(gè)基地址。這時(shí)候就需要對(duì)所有的重定位信息進(jìn)行修正,而修正的依據(jù)就是PE中的重定位表。
6.3.1??重定位表定義
重定位表為數(shù)據(jù)目錄中注冊(cè)的數(shù)據(jù)類型之一,其描述信息處于數(shù)據(jù)目錄項(xiàng)的第6個(gè)目錄項(xiàng)中:
通過上面,得到信息:
重定位表所在地址RVA=0x00018000
重定位表數(shù)據(jù)大小????=0x000010C4
結(jié)合這個(gè):
說明存在了.reloc段。
然后根據(jù)RVA計(jì)算FOA:
FOA?=?0x12C00
6.3.2??重定位表項(xiàng)IMAGE_BASE_RELOCATION
? ? 與導(dǎo)入表類似,重定位表指針指向的位置是一個(gè)數(shù)組,而不像導(dǎo)出表一樣只有一個(gè)結(jié)構(gòu)。這個(gè)數(shù)組中的每一項(xiàng)都是如下結(jié)構(gòu):
IMAGE_BASE_RELOCATION?STRUCT
??VirtualAddress??dd?????;重定位內(nèi)存頁的起始RVA
??SizeOfBlock????dd?????;重定位塊的長(zhǎng)度
IMAGE_BASE_RELOCATION?ENDS
? ? 解釋下這兩項(xiàng):
? ? MAGE_BASE_RELOCATION.VirtualAddress
? ? +0000h,雙字。重定位塊RVA.由于直接尋址指令較多,所以在一些PE文件中,存在大量的需要修正的重定位地址。按照常規(guī)計(jì)算,每個(gè)地址占4字節(jié),如果有n個(gè)重定位項(xiàng),那么需要總的空間為4*n字節(jié)。重新審視直接尋址中的地址發(fā)現(xiàn),在一頁中的所有地址只需要12位(因?yàn)?/span>Win32頁面大小為10000h,也就是4096字節(jié),即2的12次方)。
? ? 而這12位只需要用兩個(gè)字就能表達(dá)出來。如果有n個(gè)重定位項(xiàng),則只需要2*n個(gè)地址+4字節(jié)頁面起始RVA+4字節(jié)的本業(yè)的重定位項(xiàng)長(zhǎng)度。將以上兩種情況的表達(dá)式:
Sum0=4*n
Sum1=2*n+4+4
? ? 很明顯,當(dāng)有大量的重定位地址時(shí),Sum0遠(yuǎn)大于Sum1。事實(shí)上,為了節(jié)約存儲(chǔ)空間,重定位表的存儲(chǔ)方式選擇第二種方式。字段IMAGE_BASE_RELOCATION.VirtualAddress就是表達(dá)式Sum1中的第一個(gè)4,也就是頁面起始RVA。
IMAGE_BASE_RELOCATION.SizeOfBlock
+0004h,雙字。重定位塊中重定位表項(xiàng)長(zhǎng)度。該字段是表達(dá)式Sum1里的第二個(gè)4.
? ? 數(shù)組和數(shù)組之間并不是相鄰的。比如頁面1的IMAGE_BASE_RELOCATION后并不是頁面2的IMAGE_BASE_RELOCATION,而是頁面1的所有重定位表項(xiàng);每個(gè)項(xiàng)大小為一個(gè)字,每個(gè)字的高四位被用來說明此重定位的類型,剩下的十二位才是需要重定位的數(shù)據(jù)在頁面中的地址。高四位含義如下:
? ?在實(shí)際的PE文件中,我們只能看到0和3這兩種情況,也就是說要么是對(duì)其用的,要么是需要全部修正的。
6.3.3??重定位表的結(jié)構(gòu)
?
?
總結(jié)
以上是生活随笔為你收集整理的Windows PE第6章 栈与重定位表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TLS实现代码段加密
- 下一篇: Windows核心编程 第23章 结束处