Windows Pe 第三章 PE头文件-EX-相关编程-2(RVA_FOA转换)

RVA-FOA之间转换

 

1.首先PE头加载到内存之后是和文件头内容一样的,就算是偏移不同,一个是磁盘扇区大小(400H)另一个是内存页大小(1000H),但是因为两个都是开头位置,所以相同。

 

2.看下IMAGE_SECTION_HEADER定义

 

也就是这样:

 

然后就可以算了(RVA->FOA)

 

(1) RVA20 < RVA < RVA30 可以知道在第二节

(2) 然后 off = RVA - RVA20 ,得出距离第二节的偏移off

(3) FOA = FOA 20 + off 求出FOA

计算FOA->RVA也是同理...

 

/************************************************************************/  
/*  
功能:虚拟内存相对地址和文件偏移的转换
参数:stRVA:    虚拟内存相对偏移地址
      lpFileBuf: 文件起始地址
返回:转换后的文件偏移地址
*/  
/************************************************************************/  
size_t RVAToOffset(size_t stRVA,PVOID lpFileBuf)  
{  
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpFileBuf;  
    size_t stPEHeadAddr = (size_t)lpFileBuf + pDos ->e_lfanew;  
    PIMAGE_NT_HEADERS32 pNT = (PIMAGE_NT_HEADERS32)stPEHeadAddr;  
    //区段数  
    DWORD dwSectionCount = pNT->FileHeader.NumberOfSections;  
    //内存对齐大小  
    DWORD dwMemoruAil = pNT->OptionalHeader.SectionAlignment;  
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNT);  
    //距离命中节的起始虚拟地址的偏移值。  
    DWORD  dwDiffer = 0;  
    for (DWORD i = 0; i < dwSectionCount; i++)  
    {  
        //模拟内存对齐机制  
        DWORD dwBlockCount  = pSection[i].SizeOfRawData/dwMemoruAil;  
        dwBlockCount       += pSection[i].SizeOfRawData%dwMemoruAil? 1 : 0;  
  
        DWORD dwBeginVA     = pSection[i].VirtualAddress;  
        DWORD dwEndVA       = pSection[i].VirtualAddress + dwBlockCount * dwMemoruAil;  
        //如果stRVA在某个区段中  
        if (stRVA >= dwBeginVA && stRVA < dwEndVA)  
        {  
            dwDiffer = stRVA - dwBeginVA;  
            return pSection[i].PointerToRawData + dwDiffer;  
        }  
        else if (stRVA < dwBeginVA)//在文件头中直接返回  
        {  
            return stRVA;  
        }  
    }  
    return 0;  
}  
 
/************************************************************************/  
/*  
功能:文件偏移地址和虚拟地址的转换
参数:stOffset:文件偏移地址
      lpFileBuf:虚拟内存起始地址
返回:转换后的虚拟地址
*/  
/************************************************************************/  
size_t Offset2VA(size_t stOffset, PVOID lpFileBuf)  
{  
    //获取DOS头  
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpFileBuf;  
    //获取PE头  
    //e_lfanew:PE头相对于文件的偏移地址  
    size_t stPEHeadAddr = (size_t)lpFileBuf + pDos ->e_lfanew;  
    PIMAGE_NT_HEADERS32 pNT = (PIMAGE_NT_HEADERS32)stPEHeadAddr;  
    //区段数  
    DWORD dwSectionCount = pNT->FileHeader.NumberOfSections;  
    //映像地址  
    DWORD dwImageBase    = pNT->OptionalHeader.ImageBase;  
    //区段头  
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNT);  
  
    //相对大小  
    DWORD  dwDiffer = 0;  
    for (DWORD i = 0; i <  dwSectionCount; i++)  
    {  
        //区段的起始地址和结束地址  
        DWORD dwBeginVA     = pSection[i].PointerToRawData;  
        DWORD dwEndVA       = pSection[i].PointerToRawData + pSection[i].SizeOfRawData;  
        //如果文件偏移地址在dwBeginVA和dwEndVA之间  
        if (stOffset >= dwBeginVA && stOffset < dwEndVA)  
        {  
            //相对大小  
            dwDiffer = stOffset - dwBeginVA;  
            //进程的起始地址 + 区段的相对地址 + 相对区段的大小  
            //return dwImageBase + pSection[i].VirtualAddress + dwDiffer;  
return  pSection[i].VirtualAddress + dwDiffer;
        }  
        else if (stOffset < dwBeginVA)    //如果文件偏移地址不在区段中  
        {  
            return dwImageBase + stOffset;  
        }  
    }  
    return 0;  
}  
 

测试了上面两个函数,没发现什么问题,测试结果:

 

随手写了个简单的工具,直接控制台写的,功能简单,懒得写界面了。源码在:

http://download.csdn.net/detail/u013761036/9643230

运行效果:


原文地址:https://www.cnblogs.com/csnd/p/12062236.html