1. 程式人生 > 其它 >RVA與FOA的轉換

RVA與FOA的轉換

RVA與FOA的轉換

想象一下,如果你想通過逆向的方式改變一個全域性變數的初始值,該怎麼做?首先我們可以寫一個程式,輸出一個全域性變數的地址和值:

int a = 0x 12345678;
int main(){
  printf("Address: 0x%x \n",&a);
  printf("Value:0x%x \n",a);
  getchar();
  return 0;
}


我們執行程式可以看見相應的值,那麼我們可以是否可以在檔案中直接搜尋對應的值然後修改呢?這種方法沒有毛病,但是檔案中也許會存在很多個0x12345678,你無法準確的知道哪一個才是全域性變數;那麼,又是否可以通過已經給出的這個地址0x42ba30直接去尋找呢?當然也是不行的,因為在之前章節的學習中我們瞭解到,PE檔案有2種狀態(動靜態),在這2種狀態下,檔案的對齊方式會發生變化,所以當前的地址是PE檔案執行時(動態)的地址,你需要轉換成在磁碟上(靜態)的地址。


這兩種狀態的地址相互轉換,我們可以稱之為RVA與FOA的轉換RVA就是相對虛擬地址(執行時的位置)FOA就是檔案偏移地
址(磁碟靜態的位置);從RVA轉換到FOA,就是從檔案執行時(動態)的地址轉換成在磁碟上(靜態)的地址,按如下公式可以
進行轉換:

第一步:RVA地址由記憶體地址減去ImageBase地址(PE檔案在記憶體中的開始位置是由擴充套件PE頭中的ImageBase決定);
第二部 判斷RVA地址是否位於PE頭中:
a.如果是,那麼RVA等於FOA;
b.如果不是,判斷RVA在哪個節
i. 當滿足RVA地址大於等於節.VirtualAddress和RVA地址小於等於.VirtualAddress加上當前節記憶體對齊後的大小

,就表示RVA地址在該節中。
ii. RVA地址減去節.VirtualAddress等於差值,FOA地址就是根據.PointerToRawData加上差值。
在一些較老的編譯器中,編譯出來的檔案會區分檔案對齊、記憶體對齊,但是在現在的編譯器編譯出來的程式,
檔案對齊與記憶體對齊時完全一樣的,所以我們不用費這麼大的周折,我們只需要算出RVA的值就可以得出FOA
的值。
例如,在當前程式中就是這樣,根據0x42BA30-0x400000(ImageBase)得出0x2BA30,其是RVA,也是FOA,直
接使用Winhex開啟找到:

可以直接修改它然後儲存執行,這時候你就會發現全域性變數的值已經發生了改變: