向进程的虚拟内存加载PE文件(EXE/DLL/SYS)时,文件会被加载到PE头的ImageBase所指的地址处。若加载的是DLL(SYS)文件,且在ImageBase位置处已经加载了其他DLL(SYS)文件,那么PE装载器就会将其加载到其他未被占用的空间。这就涉及PE文件重定位的问题
PE重定位是指PE文件无法加载到ImageBase所指的位置,而是被加载到其他地址时发生的一系列处理行为。在PE文件中,重定位表往往单独作为一块,用“.reloc”表示
//
// Based relocation format.
//
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress; // RVA,这组重定位数据的开始的地址,各重定位项的地址加上这个指才是该重定位项的完整RVA地址
DWORD SizeOfBlock; // 当前重定位数据结构的大小,以字节位单位,减8就是TypeOffset数组大小
// WORD TypeOffset[1]; // 以注释形式存在,是一个数组,每项大小位2字节,共16位,其中高4位表示重定向的类型,低12位表示重定位的地址
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
//
// Based relocation types.
//
#define IMAGE_REL_BASED_ABSOLUTE 0 // 对齐使用
#define IMAGE_REL_BASED_HIGH 1
#define IMAGE_REL_BASED_LOW 2
#define IMAGE_REL_BASED_HIGHLOW 3 // 指向的整个地址都需要修正
#define IMAGE_REL_BASED_HIGHADJ 4
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5 5
#define IMAGE_REL_BASED_RESERVED 6
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7 7
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8 8
#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9 9
#define IMAGE_REL_BASED_DIR64 10 // 出现在64位PE文件中,对指向的整个地址进行修正
在程序中涉及到直接寻址的指令都需要进行重定位处理
如下程序的数据目录表指向重定位表的指针是00005000h,换算成文件偏移地址就是00000E00h。
VirtualAddress:00001000
SizeOfBlock:00000010((10h-8h)/ 2h = 4h),4个重定位数据
重定位数据1:300F
重定位数据2:3023
重定位数据3:0000(用于对齐)
重定位数据4:0000(用于对齐)
分别指向00402000和00403030,即为所需要重定位的数据
推荐文章++++