日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

操作系统是如何使用重定位表的

發(fā)布時(shí)間:2025/3/21 windows 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 操作系统是如何使用重定位表的 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、重定位表的結(jié)構(gòu)

重定位表是數(shù)據(jù)目錄中第6項(xiàng),它的結(jié)構(gòu)如圖示:

重定位表由多個(gè)塊(block)組成,每個(gè)塊內(nèi)部由三部分組成——VirtualAddress、SizeOfBlock 和若干個(gè)2字節(jié)偏移。SizeOfBlock 表示當(dāng)前塊的大小,當(dāng) SizeOfBlock 與 VirtualAddress 同時(shí)為0,表示重定位表結(jié)束。

VirtualAddress 表示一個(gè)頁(yè)面的基址的RVA,2字節(jié)偏移的數(shù)量 = (SizeOfBlock - 8) / 2,VirtualAddress+2字節(jié)偏移表示一個(gè)32位地址。其中,2字節(jié)偏移又分為高4位和低12位,高四位是屬性,當(dāng)它等于0011時(shí),表示這個(gè)地址需要“重定位”;低12位剛好足夠表示一個(gè)頁(yè)面的所有地址,因?yàn)?2位頁(yè)面大小 = 2^12 = 4KB.

有了上述概念以后,就可以寫出解析重定位表的程序了。但是對(duì)于初學(xué)者來說,重定位表是個(gè)啥,里面存的東西到底怎么使用,還是不清楚的。在講解操作系統(tǒng)如何使用重定位表之前,不妨先了解一下為什么需要重定位表。

二、為什么要設(shè)計(jì)重定位表

每個(gè)PE文件(exe,dll)都有一個(gè) ImageBase 表示它在4GB虛擬地址空間中加載的位置,一個(gè)運(yùn)行的程序由一個(gè)exe和多個(gè)dll構(gòu)成。對(duì)于exe來說,它總是最先加載到內(nèi)存中,因此沒有其他模塊會(huì)和它搶內(nèi)存,它總是可以加載到它希望去的位置,也就是exe指定的ImageBase;但是dll就不是這樣了,也許程序用到了3個(gè)dll,它們的ImageBase都是1000000H,那就一定會(huì)發(fā)生沖突,后加載的dll只能往高地址加載了。

在代碼中會(huì)用到一些寫死的地址,例如:

100012CD |. E8 5EFEFFFF CALL 10001130

這個(gè)地址 10001130 是 ImageBase + RVA 算出來的,對(duì)于DLL2來說,由于無法搶占到期望的 ImageBase ,所以寫死的地址就無效了,要改成 20001130 才對(duì),因此就需要用一個(gè)表來記錄下所有需要修正的地方,重定位表就是為了解決這個(gè)問題而設(shè)計(jì)的。

三、重定位表里存的是什么

重定位表存儲(chǔ)的地址由 VirtualAddress + 2字節(jié)偏移 得到,計(jì)算出來的是RVA,加上 ImageBase 就是在內(nèi)存中的地址。假設(shè)DLL2期望的ImageBase是 10000000,實(shí)際分配到的 ImageBase 是 20000000,程序里有一條指令:

100012CD |. E8 5EFEFFFF CALL 10001130

那么重定位表里一定在某個(gè)地方存儲(chǔ)了 12CD 這個(gè)地址(VA+2字節(jié)偏移得到),類似的地址還有很多,每個(gè)2字節(jié)偏移就對(duì)應(yīng)一個(gè)這樣的地址。那么操作系統(tǒng)在加載DLL時(shí),就會(huì)用DLL指定的 ImageBase + 12CD 得到一個(gè)地址,然后去修改里面寫死的地址,也就是將 10001130 改成 20001130,修改當(dāng)然就是加上實(shí)際ImageBase和期望ImageBase的差值了。

這就是操作系統(tǒng)使用重定位表的時(shí)候做的事情。

四、解析重定位表的代碼

// 打印重定位表 VOID PrintRelocationTable(LPVOID pFileBuffer) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));//PIMAGE_SECTION_HEADER pSectionHeader = \// (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);PIMAGE_BASE_RELOCATION pBaseRelocation = \(PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress));while (pBaseRelocation->VirtualAddress || pBaseRelocation->SizeOfBlock){puts("-------------------------------------");printf("VirtualAddress = %08x\n", pBaseRelocation->VirtualAddress);printf("SizeOfBlock = %08x\n", pBaseRelocation->SizeOfBlock);PWORD pwAddr = (PWORD)((DWORD)pBaseRelocation + 8);int n = (pBaseRelocation->SizeOfBlock - 8) / 2;printf("要修改的地址個(gè)數(shù) = %d\n", n); for (int i = 0; i < n ; i++){WORD wProp = (0xF000 & pwAddr[i]) >> 12;WORD wAddr = 0x0FFF & pwAddr[i];printf("[%d]:RVA = %08x\t屬性 = %d\n", i+1, pBaseRelocation->VirtualAddress + wAddr, wProp);}pBaseRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pBaseRelocation + pBaseRelocation->SizeOfBlock);} }

運(yùn)行結(jié)果
用LordPE驗(yàn)證了運(yùn)行結(jié)果的正確性:

五、模擬操作系統(tǒng)使用重定位表修正地址

編寫程序,修改ImageBase的值,然后模擬DLL加載時(shí)操作系統(tǒng)根據(jù)重定位表做的地址修正工作。
代碼在我的機(jī)器上測(cè)試過,修改后的DLL能夠正常使用。

// 修改 ImageBase 并修復(fù)重定位表 VOID SetImageBase(LPVOID pFileBuffer, DWORD dwNewImageBase) {PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(pDosHeader->e_lfanew + (DWORD)pDosHeader + 4);PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));PIMAGE_SECTION_HEADER pSectionHeader = \(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);PIMAGE_BASE_RELOCATION pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pFileBuffer + \RvaToFoa(pFileBuffer, pOptionHeader->DataDirectory[5].VirtualAddress)); DWORD dwImageBaseDelta = dwNewImageBase - pOptionHeader->ImageBase; // 新舊ImageBase 的差值 // 重定位表的 VirtualAddress + 低12位偏移 = RVA// RVA + ImageBase 這個(gè)內(nèi)存里存儲(chǔ)了一個(gè)“指針”// 要修改的是這個(gè)“指針”的值,要讓這個(gè)“指針”加上兩個(gè)ImageBase的差值while (pRelocationTable->VirtualAddress || pRelocationTable->SizeOfBlock){ size_t n = (pRelocationTable->SizeOfBlock - 8) / 2; // 可能需要修改的地址數(shù)量(高4位==0011才要修改)PWORD pOffset = (PWORD)((DWORD)pRelocationTable + 8); // 2字節(jié)偏移的數(shù)組for (size_t i = 0; i < n; i++){// 高4位等于0011才需要重定位if ((pOffset[i] & 0xF000) == 0x3000){// 計(jì)算需要重定位的數(shù)據(jù)的RVA地址DWORD dwRva = pRelocationTable->VirtualAddress + (pOffset[i] & 0x0FFF);// 計(jì)算在文件中的偏移DWORD dwFoa = RvaToFoa(pFileBuffer, dwRva);// 計(jì)算在文件中的地址PDWORD pData = (PDWORD)((DWORD)pFileBuffer + dwFoa);// 重定位,即修正寫死的地址 *pData += dwImageBaseDelta;}}pRelocationTable = (PIMAGE_BASE_RELOCATION)((DWORD)pRelocationTable + pRelocationTable->SizeOfBlock);}// 修改 ImageBasepOptionHeader->ImageBase = dwNewImageBase; }

總結(jié)

以上是生活随笔為你收集整理的操作系统是如何使用重定位表的的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。