重定位表是在一个PE中的代码被加载到任意一个内存地址时,用来描述相关操作数的变化规律的数据结构。通过重定位技术,代码运行在内存任意位置时,可以避免因操作数的定位错误而导致失败

当程序调用DLL时,如果当前IMAGEBASE已被占用,操作系统会分配一个新的IMAGEBASE,并通过重定位表修复地址

修复重定位表

手动修改IMAGEBASE(此次练习中为0x10000000,将其改为0x20000000),模拟操作系统修复每一个地址的过程,并用程序成功调用修改后的DLL

newVA = oddVA - oddImageBase + newImageBase

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
#define OUTFILEPATH TEXT("D:\\absolution\\temporary\\output.dll")
#define DLLPATH TEXT("D:\\absolution\\temporary\\myDll.dll")
#include<PETool.h>
#pragma comment(lib,"PETool.lib")

int main() {
LPVOID lpFileBuffer = createFileBuffer(DLLPATH);
PIMAGE_DOS_HEADER pDos =
(PIMAGE_DOS_HEADER)lpFileBuffer;
PIMAGE_NT_HEADERS pNT =
(PIMAGE_NT_HEADERS)((DWORD)lpFileBuffer + pDos->e_lfanew);
PIMAGE_FILE_HEADER pFile =
(PIMAGE_FILE_HEADER)((DWORD)pNT + 4);
PIMAGE_OPTIONAL_HEADER pOption =
(PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pFirstSection =
(PIMAGE_SECTION_HEADER)((DWORD)pOption + pFile->SizeOfOptionalHeader);
//定位到最后一个节头
PIMAGE_SECTION_HEADER pLastSection = (PIMAGE_SECTION_HEADER)((DWORD)pFirstSection + (pFile->NumberOfSections - 1) * 40);

/*重定位表的信息结构*/
IMAGE_DATA_DIRECTORY pReloc = (IMAGE_DATA_DIRECTORY)pOption->DataDirectory[5];

/*获取重定位表的文件偏移*/
PIMAGE_BASE_RELOCATION pRelocFileOffset =
(PIMAGE_BASE_RELOCATION)(RVA2FOA(lpFileBuffer, (DWORD)pReloc.VirtualAddress) + (DWORD)lpFileBuffer);

DWORD oddImageBase = pOption->ImageBase;
/*手动修改ImageBase*/
pOption->ImageBase = 0x20000000;

for (int i = 0; pRelocFileOffset->VirtualAddress; i++) {
/*往后8个字节找到块数据的偏移*/
PWORD pwBlockOffset = (PWORD)pRelocFileOffset + 4;

/*IMAGE_BASE_RELOCATION占8个字节,一个地址项占2字节*/
DWORD dwItemCount = (pRelocFileOffset->SizeOfBlock - 8) / 2;
for (int p = 0; p < dwItemCount; p++) {
/*高4位为3则修复地址*/
if ((*(pwBlockOffset + p) & 0x3000) == 0x3000) {
DWORD RVA = (*(pwBlockOffset + p) & 0xFFF) + pRelocFileOffset->VirtualAddress;
/*需要修正的地址的文件地址*/
PDWORD pdwFixAddress = (PDWORD)(RVA2FOA(lpFileBuffer, RVA) + (DWORD)lpFileBuffer);
/*通过指针修改地址*/
*pdwFixAddress = *pdwFixAddress - oddImageBase + pOption->ImageBase;
}
}
pRelocFileOffset= (PIMAGE_BASE_RELOCATION)((DWORD)pRelocFileOffset + pRelocFileOffset->SizeOfBlock);
}

FILE *fp;
fopen_s(&fp, OUTFILEPATH, "wb+");
if (!fp) {
printf("fopen error\n");
getchar();
return 0;
}
fseek(fp, 0, SEEK_SET);

DWORD count = fwrite(lpFileBuffer, pLastSection->PointerToRawData+pLastSection->SizeOfRawData, 1, fp);

if (count) {
printf("写入成功!!\n");
getchar();
}

fclose(fp);

free(lpFileBuffer);

}