本文主要是介绍PE文件:VA、RVA和FOA,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
VA: 虚拟内存地址(Virtual Address)PE 文件被操作系统加载进内存后的地址。
RVA: PE文件的相对虚拟地址(Relative Virual Address)是PE文件中的数据、模块等运行在内存中的实际地址相对PE文件装载到内存的基址之间的距离。举例说明,如果PE文件装入虚拟地址(VA)空间的400000h处,且进程从虚址401000h开始执行,我们可以说进程执行起始地址在RVA 1000h。
FOA: 文件偏移地址(File Offset Address),和内存无关,它是指某个位置距离文件头的偏移。
VA和RVA的转换
VA=ImageBase+RVA
RVA和FOA的转换
PE文件中的节等模块加载到内存时,节的数据布局和文件中的内存布局基本保持不变。所以可以根据这个数据位置相对不变的特点来由RVA正确换算出到数据相对文件的偏移。即,每个节(section)中的数据的起始位置相对节的起始位置是不变的,不管节是在文件中还是被加载到内存中。
1.判断指定的RVA在那个节中
2.求得该节的起始地址RVA
3.求出偏移量Offset=RVA-节起始RVA
4.FOA = Offset+该节在磁盘中的起始地址
数据的文件偏移=(数据RVA - 节RVA) + 节的文件偏移
typedef struct _IMAGE_SECTION_HEADER {BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //8个字节的节区名称union {DWORD PhysicalAddress;DWORD VirtualSize;} Misc;DWORD VirtualAddress; //节区的虚拟地址DWORD SizeOfRawData; //在文件中对齐后的尺寸DWORD PointerToRawData; //在文件中的偏移DWORD PointerToRelocations;DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
FOA=RVA-VirtualAddress+PointerToRawData
代码实现:
// RVA转FOA函数 //
/
DWORD RvaToOffset(BYTE* pFileBaseAddress, DWORD Rva)
{// 获取DOS头PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBaseAddress;// 获取NT头PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pFileBaseAddress + pDosHeader->e_lfanew);// 得到区段个数DWORD SectionNumber = pNtHeader->FileHeader.NumberOfSections;// 得到区段PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);// 遍历区段表,找到RVA所在的区段/** 每个偏移,不管是在文件中,还是在内存中,它们距离区段开始位置的距离总是相等的。* 而且,区段表中,保存着两个开始偏移:* 1. 文件中的开始偏移* 2. 内存中的开始偏移* 具体过程:* 找到RVA所在区段, 然后计算出这个RVA到区段在内存中的开始位置的距离。* 用这个距离加上区段在文件中的开始位置就得到文件偏移了*/for (int i = 0; i < SectionNumber; ++i){// 区段的起始相对虚拟地址RVADWORD SectionBeginRva = pSectionHeader[i].VirtualAddress;// 区块的结束相对虚拟地址RVA = 区段的RVA地址 + 文件中的区段对齐大小DWORD SectionEndRva = pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData;// 判断RVA是否在当前的区段中if (Rva >= SectionBeginRva&& Rva <= SectionEndRva){// 计算出RVA对应的文件偏移// 公式:文件偏移 = RVA - 区段的起始相对虚拟地址RVA + 区段的起始文件偏移FOA// 1. 要转换的RVA - 区段的起始相对虚拟地址RVADWORD Temp = Rva - pSectionHeader[i].VirtualAddress;// 2. 加上区段的起始文件偏移FOA,dwOffset为FOADWORD FileOffset = Temp + pSectionHeader[i].PointerToRawData;// 3. 得到文件偏移FOAreturn FileOffset;}}return -1;
}
这篇关于PE文件:VA、RVA和FOA的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!