理解别人写的简单的重定位程序

看了下看雪的一篇文章,加深下对重定位的理解,其实这是一个程序

https://bbs.pediy.com/thread-76638.htm

这个程序需要用户输入的是加载基址,还有文件的路径

开始首先通过MZ头,还有e_lfanew偏移是否是PE\x00\x00 来判断这是否是一个PE文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BOOL VerifyPE( PVOID pFile ) 
{
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;

pDosHeader = (PIMAGE_DOS_HEADER)pFile;
if ( pDosHeader->e_magic != 0x5A4D ) // compare with 'MZ'
return FALSE;

pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pFile + pDosHeader->e_lfanew); // e_lfanew + 0x3c
if ( pNtHeader->Signature != 0x00004550 ) // compare with 'PE\0\0'
return FALSE;

return TRUE;
}

重定位

计算镜像基址与真正加载基址的差值

1
2
3
4
5
pDosHeader = (PIMAGE_DOS_HEADER)pFile;  
pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pFile + pDosHeader->e_lfanew); // e_lfanew + 0x3c

dwImageBase = pNtHeader->OptionalHeader.ImageBase;
dwDiffer = dwImageBase - BaseAddr; // pay attention to the order

获取重定位表RVA,并计算出File Offset

1
2
3
4
5
 // Get reloc table RVA  
PIMAGE_DATA_DIRECTORY pRelocTable = (PIMAGE_DATA_DIRECTORY)pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;

// Get reloc table File Offset
pRelocBlock = (PIMAGE_RELOCATION)( (PCHAR)pFile + RvaToFileOff( pFile, (DWORD)pRelocTable ) ); // the pRelocTable is file offset?

之后根据重定位表循环计算真正的地址,具体如下

1、一次获取一条记录,获取其RVA,算出File Offset
2、通过与pRelocAddr相加得到储存原始地址的地方(即要修正的地址)
3、将这个要修正的地址减去之前算出来的基址的差别即可
4、最后将结果写回文件即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pRelocAddr = pRelocBlock->VirtualAddress + (*pType & 0x0fff);     
// pRelocAddr += dwImageBase;

// Get reloc address's File Offset
pRelocAddr = RvaToFileOff( pFile, pRelocAddr );

// DWORD test = pRelocAddr;

// Go to the Buffer offset
pRelocAddr += (DWORD)pFile;

// Get the reloc address
dwRelocAddr = *(PDWORD)pRelocAddr;

// Calculate the new address
dwRelocAddr -= dwDiffer;

// Copy to the file
*(PDWORD)pRelocAddr = dwRelocAddr;
自愿打赏专区