zoukankan      html  css  js  c++  java
  • PE知识复习之PE的RVA与FOA的转换

     

                PE知识复习之PE的RVA与FOA的转换

    一丶简介PE的两种状态

      首先我们知道PE有两种状态.一种是内存展开.一种是在文件中的状态.那么此时我们有一个需求.

    我们想改变一个全局变量的初始值.此时应该怎么做.你知道虚拟地址.或者文件位置了.那么你怎么自己进行转换.

    也就是说通过文件中的节数据找到在内存中这块数据的位置.或者反之.

    寻找之前我们要先弄前几个概念.

    ImageBase:  模块基址.程序一开始的地址.

    VA: 全名virtualAddress 虚拟地址. 就是内存中虚拟地址. 例如 0x00401000

    RVA: RVA就是相对虚拟偏移. 就是偏移地址. 例如 0x1000. 虚拟地址0x00401000的RVA就是 0x1000. RVA = 虚拟地址-ImageBase

    FOA: 文件偏移. 就是文件中所在的地址.

    二丶因为PE的两种状态.所以需要转换.

    上面简介了一下什么是VA RVA 以及FOA 那么我们为什么要转换.

    原因是这样的. 我们程序的数据.在PE文件中的地址假设是0x400, 那么在内存中展开的时候就是0x1000位置处.

    那么我们如何通过内存位置.找到文件中这个数据的位置. 或者反之. 如果找到就可以进行修改了.

    原因就是PE有两种状态.有内存对齐跟文件对齐. 如果内存对齐跟文件对齐一样.那么不管在内存中还是在文件中.数据的位置都是一样的.

    例如文件对齐是0x1000,内存也是一样. 那么文件中0x1000位置存放的值.跟PE在内存中展开的时候存放的值是一样的.所以就不需要转换了.直接在文件中更改或者在内存中更改就行了.

    因为对齐值不一样.所以我们才需要进行转换.

    例如下图:

    文件对齐值是0x200,内存对齐是0x1000

    三丶转换方法

    既然上方了解了PE的内存状态.以及文件状态形式. 那么转换就很好理解了.

    1.内存转文件偏移计算

      1.1.计算RVA

      这一个讲的就是内存转文件偏移.就是知道一个内存地址.我们要看看在文件中是哪里存储的.

    第一步: 我们知道PE在内存中展开.是在ImageBase位置展开的.头跟文件是一样的.只不过节数据展开位置不一样.

      所以首先就是 我们的内存地址-Image得出RVA

    下方我们的内存地址我就设为x了. 

      x - ImageBase == RVA  得出了我们的x位置在内存中的相对偏移.相对偏移就是我们计算的这个地址在开始位置的什么地方.

      ImageBase是在扩展头中存放的.我们可以查看一下.具体可以看看前几讲.属性解析.

      注意都是16进制进行加算的.

      根据上方我们得出的RVA.然后我们就在文件中从开头数RVA个字节,去寻找我们的这个数据.这样是不行的.因为文件对齐跟内存对齐是不一样的.所以我们要考虑对齐方式. 如果文件对齐跟内存对齐一样.那么这样就可以去找.

      2.寻址FOA

     既然找到了RVA了.那么就找一下FOA在哪里.也就是文件偏移在哪里.寻找这个值很简单.需要几个步骤.

      2.1.判断RVA属于哪个节/头. 

        如果RVA属于头(DOS+NT)那么不需要进行计算了.因为头在文件中根内存中都是一样展开的.直接从开始位置寻找到RVA个字节即可.

        如果不在头,就要判断在那个节里面. 判断节开始位置.跟结束位置. 我们的RVA在这个值里面.

        其中节虚拟地址结束位置 就是用节数据对齐后的大小+虚拟地址大小. 具体可以参考上一讲节表解析.

        公式: RVA  >= 节.VirtualAddress  && RVA <= (节.VirtualAddress + 节.SizeofRawData)

      2.2 计算差值偏移. 虚拟地址距离节数据的开始位置的偏移.

        然后计算差值偏移:

        差值  = RVA - 节.VirtuallAddress

    差值偏移:

      为什么要计算差值.因为我们计算的差值偏移就是我们的 RVA距离我们节数据开始位置 的偏移是多少. 因为这个位置是不会改变的.

    例如: 节数据开始位置是 0x1000  我们的RVA = 0x1024  那么差值是0x24. 如果文件中节数据开始的位置是0x400. 那么我们的差值偏移是不会变的. 那么文件偏移 + 差值偏移. 那么就是在文件中的位置. 例如 0x424

      2.3 计算FOA

      FOA就很好计算了.  差值偏移已经得出来了. 就知道我们的RVA距离节数据开始位置的偏移. 那么我们加上文件偏移就是FOA

    公式: FOA = 差值偏移 + 节.PointToRawData

    内存转文件偏移总结:

        1.计算RVA 公式: x - ImageBase == RVA

        2.计算差值偏移.  RVA - 节.VirtualAddress == 差值偏移.

        3.计算FOA         差值偏移 + 节.PointerToRawData == FOA

    2.文件偏移转内存虚拟地址

      上面讲解了我们根据虚拟地址可以定位到在文件中的那个位置.那么反之.我们也可以通过文件位置.定位到虚拟地址.

    需要理解的还是差值偏移. 只不过角色互换了. .

             设x 为节数据的任意一位置

          1.计算差值偏移:    x - 节.PointerToRawData(节数据在文件中开始的位置) == 差值偏移.

          2.计算RVA            差值偏移 + 节.VirtuallAddress(节数据在内存中展开的位置) == RVA

          3.计算虚拟地址:   RvA + ImageBase == VA

    需要注意的就是我们的 x在哪一个节中.  x <= 节.PointerToRawData + 节.SizeofRawData

     四丶实战演练

      我们写一个程序.其代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    
    
    int g_TestValue = 0x12345678;
    int main(int argc, char *argv[])
    {
        printf("全局变量地址 = %p 
    ", &g_TestValue);
        printf("全局变量值 = %X 
    ", g_TestValue);
    
        getchar();
    }

    PS: 如果是VS系列编译器,请在属性 -> 连接 中去掉随机基址. 不然你需要计算一下.或者自己在PE中将文件头的文件属性更改. 更改为. 0x0103 

    程序截图:

      

    此时我们已经知道了全局变量地址.那么我们要转换到文件中.将这个全局变量地址进行修改.也就是说.我们通过修改文件.达到修改我们的全局变量值的一种手段.

    思路:

      1.计算出RVA.  RVA怎么计算我们也知道了.我们需要查看PE中扩展头的ImageBase成员的值. 这里我已经查看好了.值为0x400000. 那么我们的RVA = 19000

      2.判断属于哪个节,计算出差值偏移

     在我们的.data节中.差值偏移计算出结果为0.

      3.计算FOA位置.

      因为现在编译器的文件对齐以及内存对齐都是一样了.所以我们不许要进行计算了. 直接就是文件偏移就是FOA位置.

    否则我们差值偏移加文件偏移 = = FOA.  现在我们的差值偏移是 0 0 + 节偏移 就是全局变量在文件中的位置.

    7400 就是我们的FOA

      4.跳转到FOA修改全局变量的值

    跳转到我们的FOA位置,可以看到我们全局变量的初始值为小端模式的 0x12345678,那么我们进行修改.进行文件保存即可.

     5.修改文件重新打开程序

       修改为0x55555555了,重新打开程序观看结果.

    这就是内存转文件偏移的实战. 如果学过逆向的人应该接触过OD.或者x64DBG. 如果我们在内存中修改后.要保存到文件.那么计算公式就是这个.

  • 相关阅读:
    校验函数
    声明
    主程序(开始检查)
    活代码LINQ——09
    活代码LINQ——08
    活代码LINQ——07
    活代码LINQ——06
    活代码LINQ——05
    活代码LINQ——04
    活代码LINQ——03
  • 原文地址:https://www.cnblogs.com/iBinary/p/9733703.html
Copyright © 2011-2022 走看看