重定位表:
程序的加載過程:
??在雙擊一個(gè)exe可執(zhí)行程序時(shí),它的執(zhí)行步驟是通過資源管理器(exploer,exe)定位到文件,得到文件后,使用CreateProcess(或CreateUserProcess)函數(shù)創(chuàng)建一個(gè)進(jìn)程,但是需要注意的是,雖然創(chuàng)建了一個(gè)進(jìn)程,但是未必跑的就一定是exe(可能是DLL或者sys)這倆步只是在三環(huán)或者0環(huán)掛上了所謂的物理頁,分配了一塊虛擬內(nèi)存空間。然后通過文件的路徑載入PE。
??載入后會(huì)拉伸、各種重定位。最后是call 程序入口。
為什么要重定位呢?
??在程序編譯前的地址是Imagebase+ RVA。當(dāng)這個(gè)地址被編譯后,已經(jīng)寫入文件中了,那么假設(shè),程序在編譯時(shí)沒有按照imagebase提供的基地址進(jìn)行寫入,那么在使用全局變量或者函數(shù)時(shí),就會(huì)使用錯(cuò)誤的數(shù)據(jù),因?yàn)樗麄兊钠瓢l(fā)生了變化。
??也就是說如果程序按照imagebase提供的基地址進(jìn)行加載,那么就不需要重定位。
重定位表:
數(shù)據(jù)目錄的第6個(gè)結(jié)構(gòu)就是重定位表:
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress; //重定位表的RVA
DWORD Size; //大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
1、通過IMAGE_DATA_DIRECTORY結(jié)構(gòu)中的VirtualAaddress成員找到第一個(gè)IMGAE_BASE_RELOCATION
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress; //需要定位的數(shù)據(jù)存在改地址中的低12位,高12位是3則表示改塊需要修復(fù)
DWORD SizeOfBlock; //塊的大小
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION ,* PIMAGE_BASE_RELOCATION;
2、判斷一共有幾塊數(shù)據(jù)
??IMAGE_BASE_RELOCATION結(jié)構(gòu)中SizeOfBlock成員是該塊的總大小。
??計(jì)算一共存在多少塊數(shù)據(jù),則判斷該結(jié)構(gòu)中的兩個(gè)成員都為0。
??
3、修復(fù)的具體項(xiàng)
??具體的項(xiàng)占用2字節(jié),那么通過當(dāng)前塊的總大小減掉兩個(gè)成員的寬度就得到了需要修復(fù)的項(xiàng),使用項(xiàng)在÷2 就得到了具體由多少項(xiàng)需要修復(fù)。計(jì)算公式如下:
????具體需要修復(fù)多少項(xiàng) = 塊的總大小(SizeOfBlock - VirtualAddress - SizeOfBlock)/ 2
??圖解:
??
??內(nèi)存中頁的大小是1000H(4KB),也就是2的12次方,就可以表示一個(gè)頁內(nèi)的所有偏移,具體項(xiàng)的寬度為2字節(jié)(16bit),高4位代表類型,值為3代表需要修復(fù)的數(shù)據(jù),值為0代表的是用于數(shù)據(jù)對(duì)齊的,可以不用修改,所以我們只需要關(guān)注值為3的。
4、如何定位需要修復(fù)的數(shù)據(jù)、
??具體項(xiàng)的高4位表示是否需要修復(fù)(也就是判斷值是不是為3)如果為3,則該項(xiàng)的低12位+ VirtualAddres 才是真正需要修復(fù)數(shù)據(jù)的RVA。
實(shí)現(xiàn)代碼:
/*定位頭*/
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)((DWORD)DosHeader + DosHeader->e_lfanew);
PIMAGE_FILE_HEADER FileHeader = (PIMAGE_FILE_HEADER)((DWORD)NtHeader + 4);
PIMAGE_OPTIONAL_HEADER OptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)FileHeader + IMAGE_SIZEOF_FILE_HEADER);
/*定位重定位表結(jié)構(gòu)*/
PIMAGE_BASE_RELOCATION Relocation = (PIMAGE_BASE_RELOCATION)(RVAtoFOA(FileBuffer, OptionalHeader->DataDirectory[5].VirtualAddress) + (DWORD)FileBuffer);
/*遍歷有幾個(gè)塊 和 每一塊中存在多少項(xiàng):具體項(xiàng)的數(shù)量 = (SizeOfBlock - 8)/2 */
int i = 0;
while (Relocation->VirtualAddress != 0 && Relocation->SizeOfBlock != 0)
{
int Item = (Relocation->SizeOfBlock - 8) / 2; //該塊的具體項(xiàng)
char* SectionName = LocationSection(FileBuffer, RVAtoFOA(FileBuffer, Relocation->VirtualAddress)); //定位節(jié)名稱
printf("%s\t 第%d塊\t共%d項(xiàng)\tRVA:%x\n", SectionName, i + 1, Item, Relocation->VirtualAddress);
/*遍歷要修復(fù)的塊*/
short* test = (short*)((DWORD)Relocation + 8);
printf("Index\tRVA\tOffset\tType\t\n");
for (int j = 0; j < Item; j++)
{
if (*test & 0x3000)
{
DWORD addr = RVAtoFOA(FileBuffer, Relocation->VirtualAddress + *test - 0x3000);
DWORD xiufu = addr + (DWORD)FileBuffer;
printf("%d\t%x\t%x\t% d\t\n", j + 1, Relocation->VirtualAddress + *test - 0x3000, addr, 3);
}
test++;
}
Relocation = (PIMAGE_BASE_RELOCATION)((DWORD)Relocation + Relocation->SizeOfBlock); //定位下一塊的位置
i++;
}
浙公網(wǎng)安備 33010602011771號(hào)