PE檔案格式的RVA概念

iiprogram發表於2008-04-14

我們常說的RVA,很容易讓我們理解成這是相對於節的RVA,其實不然。
要理解RVA的概念,首先還必須理解Section Header結構(由Section Header構成節表)。
typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

注意其中的VirtualAddress和PointerToRawData,這兩個都是節的起始地址。不同之處在於:
VirtualAddress用在記憶體中指明該節的起始地址,而PointerToRawData用在檔案中指明該
節的起始地址。


由於檔案的對齊值和記憶體的對齊值不一樣,所以,如果以直接用RVA(即iRVA)去定位的話,那麼,可能是錯誤的。

這個RVA我把它分成三種情況,在不同情況下計算得出的RVA各給個名字:
為了方便理解,使用例子資料來說明。
typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];  // .text
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;    // 00069f9b
    } Misc;
    DWORD   VirtualAddress;      // 00000540
    DWORD   SizeOfRawData;      // 00069fc0
    DWORD   PointerToRawData;      // 00000540
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;      // 68000020
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
整理成和LordPE的形式如下:
名稱Name  VOffset    VSize    ROffset    RSize    標誌
.text    0000540    00069f9b  00000540  00069fc0  68000020

虛擬地址VA = 00049586,ImageBase = 00040000

1、該RVA是以ImageBase為參考的,即是通過RVA=VA - ImageBase = 00049586-00040000=9586 我們稱其為iRVA(我們常說為RVA)
2、該RVA是以VOffset(如.text節的起始地址)為參考的,即是通過RVA=VA - VOffset,我們稱其為mRVA(記憶體節偏移)
3、真正的檔案偏為fRVA

我們很清楚的知道,唯有它們以節的起始地址為參考的相對偏移才是固定的。我們就根據這個來計算。
我們以VA=00049586為例子,為了得到它的檔案偏移,我們需要經過以下的步驟:
先把VA轉換成iRVA,即iRVA = VA - ImageBase = 00049586-00040000=9586
把iRVA轉換成mRVA,即mRVA = iRVA - VOffset = 9586-540=9046
得到了mRVA後,就很容易得到fRVA了,fRVA = mRVA+ROffset = 9046+540=9586
所以,VA=00049586的檔案偏移為fRVA=9586
上面由於ROffset和VOffset值一樣,所以,你別以為直接計算就行了。
最後總結:
1、虛擬地址轉檔案偏地址fRVA
fRVA = mRVA + ROffset

由於mRVA = iRVA - VOffset
   再由於iRVA = 虛擬地址 - ImageBase
所以,mRVA = (虛擬地址 - ImageBase) - VOffset

所以,fRVA = (虛擬地址 - ImageBase) - VOffset + ROffset

最終得到:
fRVA = (虛擬地址 - ImageBase) - VOffset + ROffset

一個簡單的代入法!

2、RVA轉檔案偏移地址fRVA
同上 

VirtualAddress是在記憶體中相對於ImageBase的偏移. RVA


VirtualAddress + ImageBase 得到的值才是該節在記憶體中的虛擬地址。

 

相關文章