前言
通过分析和解析Windows PE格式,并使用qt进行图形化显示
一、什么是Windows PE格式中的重定位表表?
重定位表是Windows PE文件格式中的一种特殊数据结构,用于在程序加载到内存时修正地址。当程序被加载到内存时,它可能不会被加载到其预期的默认地址,而是被加载到其他地址。这就需要对程序中的地址进行重定位,以确保程序能够正确地运行。
总之,重定位表是PE文件格式中的一种关键数据结构,它用于在程序加载到内存时修正地址,确保程序能够正确地运行。
二、解析重定位表并显示
1.重定位表的结构
重定位表的结构如下:
重定位表是一个结构体数组,以全零元素结尾,每一个数组元素描述了4KB大小的区域的重定位信息。结构体包含两个重要成员:VirtualAddress和SizeOfBlock。VirtualAddress表示需要重定位的位置,这是一个RVA(相对虚拟地址);SizeOfBlock表示这个结构体的大小,包括TypeOffset数组的大小。
struct IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
};
TypeOffset数组是一个不定长度的数组,它紧随在结构体之后。TypeOffset数组中的每个元素都描述了一个相对于第一个元素描述的位置的偏移。这个偏移用于计算实际的内存地址。
TypeOffset数组中的每个元素都是一个32位的值,其中高12位表示重定位类型,低20位表示重定位的偏移。重定位类型有以下几种:
IMAGE_REL_BASED_ABSOLUTE:表示不需要重定位,这是一个占位符。
IMAGE_REL_BASED_HIGH:表示需要重定位的地址是一个16位的高位部分。
IMAGE_REL_BASED_LOW:表示需要重定位的地址是一个16位的低位部分。
IMAGE_REL_BASED_HIGHLOW:表示需要重定位的地址是一个32位的地址。
IMAGE_REL_BASED_HIGHADJ:表示需要重定位的地址是一个16位的高位部分,但是需要加上一个额外的16位的值。
IMAGE_REL_BASED_MIPS_JMPADDR:表示需要重定位的地址是一个MIPS架构的跳转地址。
IMAGE_REL_BASED_ARM_MOV32:表示需要重定位的地址是一个ARM架构的32位地址。
IMAGE_REL_BASED_THUMB_MOV32:表示需要重定位的地址是一个ARM Thumb架构的32位地址。
IMAGE_REL_BASED_MIPS_JMPADDR16:表示需要重定位的地址是一个MIPS架构的16位跳转地址。
IMAGE_REL_BASED_IA64_IMM64:表示需要重定位的地址是一个IA64架构的64位地址。
IMAGE_REL_BASED_DIR64:表示需要重定位的地址是一个64位的地址。
重定位表中的每个元素都对应于PE文件中的一个4KB大小的内存块。在这个块中,可能有一些地址需要被重定位。这些地址被记录在TypeOffset数组中,每个元素对应一个需要重定位的地址。当程序被加载到内存时,系统会使用重定位表中的信息来修正这些地址,以确保程序能够正确地运行。
2.解析重定位表
bool PEParser::parserFileData(const QByteArray &fileData)
{
//判断是否是MZ开头的文件
if (fileData.left(2) != "MZ")
{
return false;
}
//解析DOS头
parserDOSHeader(fileData.left(sizeof(IMAGE_DOS_HEADER)));
//DOSStub数据
m_dosStubData = fileData.mid(sizeof(IMAGE_DOS_HEADER), m_dosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER));
long peAddress = m_dosHeader.e_lfanew;
if (fileData.mid(peAddress, 2) != "PE")
{
return false;
}
m_fileData = fileData;
//去除前4个字节的PE头标识
long fileHeaderIndex = peAddress + 4;
//记录文件头索引
m_fileHeaderIndex = fileHeaderIndex;
//解析标准PE文件头
paserFileHeader(fileData.mid(fileHeaderIndex, sizeof(IMAGE_FILE_HEADER)));
//解析扩展PE文件头
long optionHeaderIndex = fileHeaderIndex + sizeof(IMAGE_FILE_HEADER);
//记录扩展PE文件头索引
m_optionHeaderIndex = optionHeaderIndex;
//解析扩展PE文件头
parserOptionHeader(fileData.mid