在之前五篇文章中,无意中已经涉及到RVA与FOA的互相转化
RVA与节表的VirtualAddress有关
FOA与节表的PointerToRawData有关
继续展示老图(似乎五篇文章都有这个图)

使用和前文相同的代码,解析头部的一些数据
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){ return 0;}pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 0x04);pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);如果输入的RVA不在节中,位于头部,直接返回
xxxxxxxxxxif (RVA <= pOptionHeader->SizeOfHeaders){ return (DWORD)RVA;}遍历节表,如果输入的RVA位于图中绿色的保留区,返回0
xxxxxxxxxxfor (DWORD n = 0; n < numberOfSection; n++){ if (RVA < pTempSectionHeader->VirtualAddress) { return 0; } // ...}只有RVA位于对齐前节内(Misc.VirtualSize)中,认为可以转换。使用VirtualAddress偏移加当前Misc.VirtualSize得到的是当前节对齐前有效内存偏移
RVA减去当前VirtualAddress得到先对于当前节的起始位置的偏移,从PointerToRawData偏移相同的大小即可得到RVA在FileBuffer中的偏移,也就是我们需要的FOA
xxxxxxxxxxif (RVA < pTempSectionHeader->VirtualAddress + pTempSectionHeader->Misc.VirtualSize){ FOAValue = RVA - pTempSectionHeader->VirtualAddress + pTempSectionHeader->PointerToRawData; break;}// 下一次循环pTempSectionHeader++;
整体代码
xDWORD RvaToFileOffset(IN LPVOID pFileBuffer, IN DWORD RVA){ PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_NT_HEADERS pNTHeader = NULL; PIMAGE_FILE_HEADER pPEHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; PIMAGE_SECTION_HEADER pSectionHeader = NULL; DWORD numberOfSection = 0; DWORD FOAValue = 0;
if (!pFileBuffer) { return 0; } if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) { return 0; } pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) { return 0; } pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 0x04); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
numberOfSection = pPEHeader->NumberOfSections; PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; if (RVA <= pOptionHeader->SizeOfHeaders) { return (DWORD)RVA; } for (DWORD n = 0; n < numberOfSection; n++) { if (RVA < pTempSectionHeader->VirtualAddress) { return 0; } if (RVA < pTempSectionHeader->VirtualAddress + pTempSectionHeader->Misc.VirtualSize) { FOAValue = RVA - pTempSectionHeader->VirtualAddress + pTempSectionHeader->PointerToRawData; break; } pTempSectionHeader++; } return FOAValue;}
从FOA转RVA的代码类似
当输入FOA位于头部时直接返回
xxxxxxxxxxif (FOA <= pOptionHeader->SizeOfHeaders){ return (DWORD)FOA;}遍历节表,如果FOA小于当前节文件起始偏移PointerToRawData(位于绿色中)返回0
xxxxxxxxxxfor (DWORD n = 0; n < numberOfSection; n++){ if (FOA < pTempSectionHeader->PointerToRawData) { return 0; } // ...}当FOA大于PointerToRawData且小于对齐前最大偏移,认为这是有效的FOA
使用FOA减去PointerToRawData得到相对当前节起始位置的偏移,这个偏移同时也是相对于VirtualAddress的偏移,相加后得到我们需要的RVA值:输入的FOA地址对应的内存ImageBuffer地址
xxxxxxxxxxif (FOA < pTempSectionHeader->PointerToRawData + pTempSectionHeader->Misc.VirtualSize){ RVAValue = FOA - pTempSectionHeader->PointerToRawData + pTempSectionHeader->VirtualAddress;}// 继续循环pTempSectionHeader++;
整体代码
xxxxxxxxxxDWORD FoaToImageOffset(IN LPVOID pFileBuffer, IN DWORD FOA){ PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_NT_HEADERS pNTHeader = NULL; PIMAGE_FILE_HEADER pPEHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; PIMAGE_SECTION_HEADER pSectionHeader = NULL; DWORD numberOfSection = 0; DWORD RVAValue = 0;
if (!pFileBuffer) { return 0; } if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) { return 0; } pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) { return 0; } pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 0x04); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
numberOfSection = pPEHeader->NumberOfSections; PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
if (FOA <= pOptionHeader->SizeOfHeaders) { return (DWORD)FOA; } for (DWORD n = 0; n < numberOfSection; n++) { if (FOA < pTempSectionHeader->PointerToRawData) { return 0; } if (FOA < pTempSectionHeader->PointerToRawData + pTempSectionHeader->Misc.VirtualSize) { RVAValue = FOA - pTempSectionHeader->PointerToRawData + pTempSectionHeader->VirtualAddress; } pTempSectionHeader++; } return RVAValue;}