【PE文件】重定位
重定位表位置
IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER32.IMAGE_DATA_DIRECTORY_ARRAY[5].VirtualAddress
重定位表结构
重定位表以一个 IMAGE_BASE_RELOCATION(IBR)数组开始,最后以一个全0的IBR结构作为结尾。每个IBR结构体中都包含多个需要修复的重定位数据。
struct _IMAGE_BASE_RELOCATION { 0x00 DWORD VirtualAddress; //当前块中需要修复重定位数据的起始RVA地址 0x04 DWORD SizeOfBlock; //当前IBR结构体的大小 //0x08 WORD TypeOffset[1]; //重定位偏移(高4位是类型,剩余12位+VirtualAddress=需要修复数据的地址) } IMAGE_BASE_RELOCATION;
TypeOffset 字段本身并不包含在IBR结构体中,在文件里它是紧跟在IBR结构体末尾的一段数据:
1 struct TypeOffset 2 { 3 0x00 WORD Offset:12; //偏移 4 0x02 WORD Type:4; //类型 5 }; 6 7 Type: 8 #define IMAGE_REL_BASED_ABSOLUTE 0 //无重定位操作,用于4字节对齐 9 #define IMAGE_REL_BASED_HIGH 1 //重定位指向位置的高2个字节需要被修正 10 #define IMAGE_REL_BASED_LOW 2 //重定位指向位置的低2个字节需要被修正 11 #define IMAGE_REL_BASED_HIGHLOW 3 //重定位指向位置的全部4个字节需要被修正 12 #define IMAGE_REL_BASED_HIGHADJ 4 //需要两个TypeOffset配合完成索引 13 #define IMAGE_REL_BASED_MACHINE_SPECIFIC_5 5 // 14 #define IMAGE_REL_BASED_RESERVED 6 // 15 #define IMAGE_REL_BASED_MACHINE_SPECIFIC_7 7 // 16 #define IMAGE_REL_BASED_MACHINE_SPECIFIC_8 8 // 17 #define IMAGE_REL_BASED_MACHINE_SPECIFIC_9 9 // 18 #define IMAGE_REL_BASED_DIR64 10 //重定位指向位置的8个字节需要被修正
通过 SizeOfBlock 字段可以计算出当前IBR结构体中有多少个需要修复重定位的数据:
//计算公式 (SizeOfBlock - 8) / 2 8 = VirtualAddress和SizeOfBlock字段大小 2 = TypeOffset字段大小
下面用一个例子实际演示一下:示例程序中共有5个待修复的IBR结构体,每个IBR中又包含若干个需要修复的重定位数据。
第一个IBR结构体的大小是E8(从7400开始到74E8结束)减去前8个字节,E0除以2正好有112个待修复的重定位数据。
获取需要修复重定位数据的位置:
1 //计算公式: 2 需要修复重定位数据的位置 = 当前模块加载基址 + VirtualAddress + TypeOffset低12位 3 4 VirtualAddress = 11000 5 TypeOffset = 33F5。高4位=3(重定位指向位置的全部4个字节都需要被修正),低12位=3F5 6 7 11000 + 3F5 = 113F5(RVA) 8 假设当前模块加载基址是00400000 + 113F5 = 004113F5(VA)
获取需要修复重定位的数据地址:
//计算公式: 需要修复重定位的数据地址 = (当前加载基址 - 默认加载基址)+ 需要进行基址重定位数据的地址(RVA)
内存地址:004113F5中存储的就是需要修复的重定位数据地址,但是由于EXE程序每次加载的基址几乎都是不变的,所以可以省略修复重定位的操作(这在分析恶意样本的时候非常有用)