什么是RVA,FOV
RVA是相对虚拟地址,FOV是文件偏移
由于PE文件在磁盘上和在内存中的对齐粒度不同,会导致同一个PE文件在磁盘上和在内存中有两个不同的偏移,即,FOV和RVA.
在PE格式中查看对齐粒度
PE文件在磁盘和在内存的对齐粒度分别为: FileAlignment 和SectionAlignment
他们在PE扩展头中可以找到,PE扩展头的结构体:
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment; //内存对齐粒度
DWORD FileAlignment; //文件对齐粒度
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
FileAlignment一般是磁盘一个物理扇区的大小,512字节,即:0x200;
SectionAlignment的大小一般为0x1000,也就是win32中一个页的大小(4KB);
这两个值由链接器填写,SectionAlignment必须大于等于FileAlignment,在高版本的链接器中,SectionAlignment可能与FileAlignment相等,就无需进行RVA和FOV的转换了。
RVA转FOV
在解析PE文件时,经常会用到RAV与FOV的转换,
在RVA转FOV有以下几个步骤:
1.判断指定RVA落在哪个节区内。
2.获取该节区在内存中的虚拟地址,即:IMAGE_SECTION_HEADER.VirtualAddress
3.求出offset=指定RVA-IMAGE_SECTION_HEADER.VirtualAddress
4.得到FOV=offset+IMAGE_SECTION_HEADER.PointerToRaw(在文件中的起始地址)
可以通过IMAGE_FILE_HEADER+SizeOfOptionalHeader得到IMAGE_SECTION_HEADER地址,在IMAGE_FILE_HEADER得到NumberOfSections
具体转换代码:
ULONG RVAToFOV(PIMAGE_SECTION_HEADER pSectionHeader, ULONG NumberOfSections, ULONG RVA)
{
for (int i = 0; i < NumberOfSections; i++)
{
if (pSectionHeader->VirtualAddress <= RVA && RVA <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
{
return RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
}
pSectionHeader++;
}
return 0;
}