1. 程式人生 > >PE知識復習之PE的RVA與FOA的轉換

PE知識復習之PE的RVA與FOA的轉換

地方 第一步 為什麽 截圖 tro 需求 ddr 去掉 span

            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 \r\n", &g_TestValue);
    printf("全局變量值 = %X \r\n", 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. 如果我們在內存中修改後.要保存到文件.那麽計算公式就是這個.

PE知識復習之PE的RVA與FOA的轉換