在之前五篇文章中,无意中已经涉及到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
不在节中,位于头部,直接返回
xxxxxxxxxx
if (RVA <= pOptionHeader->SizeOfHeaders)
{
return (DWORD)RVA;
}
遍历节表,如果输入的RVA
位于图中绿色的保留区,返回0
xxxxxxxxxx
for (DWORD n = 0; n < numberOfSection; n++)
{
if (RVA < pTempSectionHeader->VirtualAddress)
{
return 0;
}
// ...
}
只有RVA
位于对齐前节内(Misc.VirtualSize)中,认为可以转换。使用VirtualAddress
偏移加当前Misc.VirtualSize
得到的是当前节对齐前有效内存偏移
RVA
减去当前VirtualAddress
得到先对于当前节的起始位置的偏移,从PointerToRawData
偏移相同的大小即可得到RVA
在FileBuffer
中的偏移,也就是我们需要的FOA
xxxxxxxxxx
if (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
位于头部时直接返回
xxxxxxxxxx
if (FOA <= pOptionHeader->SizeOfHeaders)
{
return (DWORD)FOA;
}
遍历节表,如果FOA
小于当前节文件起始偏移PointerToRawData
(位于绿色中)返回0
xxxxxxxxxx
for (DWORD n = 0; n < numberOfSection; n++)
{
if (FOA < pTempSectionHeader->PointerToRawData) {
return 0;
}
// ...
}
当FOA
大于PointerToRawData
且小于对齐前最大偏移,认为这是有效的FOA
使用FOA
减去PointerToRawData
得到相对当前节起始位置的偏移,这个偏移同时也是相对于VirtualAddress
的偏移,相加后得到我们需要的RVA
值:输入的FOA
地址对应的内存ImageBuffer
地址
xxxxxxxxxx
if (FOA < pTempSectionHeader->PointerToRawData + pTempSectionHeader->Misc.VirtualSize)
{
RVAValue = FOA - pTempSectionHeader->PointerToRawData + pTempSectionHeader->VirtualAddress;
}
// 继续循环
pTempSectionHeader++;
整体代码
xxxxxxxxxx
DWORD 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;
}