• 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

    运行效果:


  • 相关阅读:
    Oracle连接与会话
    数据库物理备份与恢复系列之——数据库手动热备份和恢复
    RHCS 6.5 由于resource-agents-3.9.2-40.el6版本过低导致rgmanager[61164]: [fs] umount failed
    ORA-20011 ORA-29913 and ORA-29400 with Associated KUP-XXXXX Errors from DBMS_STATS.GATHER_STATS_JOB(Doc ID 1274653.1)
    initrd image比lvm.conf文件舊導致RHCS切換服務unmount failed,reboot
    Oracle监听的静态注册和动态注册
    Linux下安裝Oracle database內核參數設置
    kkjcre1p: unable to spawn jobq slave process, slot 0, error 1089(Linux x86_64)补丁
    NHibernate系列
    Oracle设置主键自增长
  • 原文地址:https://www.cnblogs.com/csnd/p/12062236.html
Copyright © 2020-2023  润新知