文章目錄
- 說明
- 一、FOA和RVA
- 二、RVA轉為FOA
-
- 1.大緻步驟
- 2.特殊情況
- 3.C語言實作函數功能
- 三、FOA轉為RVA
-
- 1.大緻步驟
- 2.特殊情況
- 3.C語言實作函數功能
說明
看滴水的視訊寫學習筆記總結
語言:c/c++
編譯環境:vc++6.0
C語言函數中定義的結構類型來自于頭檔案
windows.h
準确的說,定義的PE的結構體類型的所有資料都來自與頭檔案
winnt.h
,隻不過windows.h内部聲明了winnt.h
一、FOA和RVA
縮寫 | 英文全稱 | 含義 |
---|---|---|
FOA | File Offset Address | 檔案偏移位址 |
RVA | Relative Virtual Addresses | 相對虛拟位址 |
VA | Virtual Address | 虛拟位址 |
RVA
VA = RVA + ImageBase
二、RVA轉為FOA
1.大緻步驟
第一步:判斷RVA是否在PE頭區。在PE頭區RVA與FOA相等,直接傳回RVA。
對比第一個節表頭VirtualAddress.
若RVA < VirtualAddress則說明RVA在PE頭區
第二步:若RVA沒有在頭區,就周遊節表頭,尋找這個RVA位于哪個節表區。
循環周遊節表頭,在該 節表頭内 滿足下列條件
VirtualAddress <= RVA <= VirtualAddress + SizeOfRawData
即可确定RVA位于哪個節表頭
第三步:找到RVA對應的節表區頭後,計算并傳回FOA的值
在對應的節表頭區内,
FOA = (RVA - VirtualAddress) + PointerToRawData;
2.特殊情況
兩種情況的RVA沒有對應的FOA
- RVA為記憶體拉伸後系統填充的位址
- RVA超出記憶體範圍
3.C語言實作函數功能
說明 | 意義 |
---|---|
函數名稱 | size_t ConvertRvaToFoa( size_t RVA , LPVOID pFileBuffer ) |
功能 | 将RVA轉化為FOA |
參數 | 參數1:要轉換的RVA的值(size_t);參數2:指向檔案緩沖區的指針(LPVOID) |
傳回值 | 成功則傳回對應的FOA,失敗則傳回0(這個RVA是沒有對應的FOA,為記憶體拉伸後系統填充的位址,或者RVA超出記憶體範圍) |
調用頭檔案 | stdio.h |
//功能:将RVA轉化為FOA
//參數:參數1:要轉換的RVA的值(size_t);參數2:指向檔案緩沖區的指針(LPVOID)
//傳回值:成功則傳回對應的FOA,失敗則傳回0(這個RVA是沒有對應的FOA,為記憶體拉伸後系統填充的位址,或者RVA超出記憶體範圍)。
size_t ConvertRvaToFoa( size_t RVA , LPVOID pFileBuffer )
{
int i ;//用于周遊節表
// size_t FOA = 0;
//定義表頭指針
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS32 pNtHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//給表頭賦初值
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeader = (PIMAGE_NT_HEADERS32)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader+4 );
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一個節表頭
pSectionHeader = (PIMAGE_SECTION_HEADER)( (DWORD)pOptionHeader + pFileHeader->SizeOfOptionalHeader);
if(RVA < pSectionHeader->VirtualAddress)//判斷RVA是否在PE頭區
{
if(RVA < pSectionHeader->PointerToRawData)
return RVA;//此時FOA == RVA
else
return 0;
}
for(i=0 ; i<pFileHeader->NumberOfSections ; i++)//循環周遊節表頭
{
if( i )//周遊節表頭,第一次不周遊,
pSectionHeader = (PIMAGE_SECTION_HEADER)( (DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER );
if(RVA >= pSectionHeader->VirtualAddress )//是否大于這個節表的RVA
{
if( RVA <= pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData )//判斷是否在這個節區
return ( RVA - pSectionHeader->VirtualAddress ) + pSectionHeader->PointerToRawData;//确定節區後,計算FOA
}
else//RVA不可能此時的pSectionHeader->VirtuallAddress小,除非是傳回值為0的情況。
return 0;
}
return 0;
}
三、FOA轉為RVA
1.大緻步驟
和
VA轉為FOA
的步驟架構差不多,但細節不一樣
第一步:判斷FOA是否在PE頭區。在PE頭區FOA與RVA相等,直接傳回這個FOA。
對比第一個節表頭的PointerToRawData
若FOA < PointerToRawData則證明FOA在PE頭區
第二步:若FOA沒有在頭區,就周遊節表頭,尋找這個FOA位于哪個節表區。
循環周遊節表頭,在該 節表頭内 滿足下列條件
PointerToRawData <= FOA < PointerToRawData + SizeOfRawData
即可确定FOA位于哪個節表頭
第三步:找到FOA對應的節表區頭後,計算并傳回RVA的值
在對應的節表頭區内,
RVA = (FOA - PointerToRawData) + VirtualAddress;
2.特殊情況
FOA超出檔案記憶體的範圍
3.C語言實作函數功能
說明 | 意義 |
---|---|
函數名稱 | size_t ConvertFoaToRva( size_t FOA , LPVOID pFileBuffer ) |
功能 | 将FOA轉換為RVA |
參數 | 參數1:要轉換的FOA值(size_t);參數2:指向檔案記憶體的指針(LPVOID) |
傳回值 | 成功則傳回對應的RVA,失敗傳回0(此時為FOA越界) |
調用頭檔案 | stdio.h |
//功能:将FOA轉換為RVA
//參數:參數1:要轉換的FOA值(size_t);參數2:指向檔案記憶體的指針(LPVOID);
//傳回值:成功則傳回對應的RVA,失敗傳回0(此時為FOA越界)。
size_t ConvertFoaToRva( size_t FOA , LPVOID pFileBuffer )
{
int i = 0;//用于周遊節表。
// size_t RVA = 0;
//定義表頭指針
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS32 pNtHeader = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//給表頭賦初值
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeader = (PIMAGE_NT_HEADERS32)( (DWORD)pDosHeader + pDosHeader->e_lfanew );
pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader + 4 );
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一個節表頭
pSectionHeader = (PIMAGE_SECTION_HEADER)( (DWORD)pOptionHeader + pFileHeader->SizeOfOptionalHeader );
if( FOA < pSectionHeader->PointerToRawData )//判斷是否位于 頭區
return FOA ; //這是RVA == FOA ;
for(i=0 ; i<pFileHeader->NumberOfSections ; i++)//循環周遊節表頭
{
if( i )//周遊節表頭,第一次不周遊,
pSectionHeader = (PIMAGE_SECTION_HEADER)( (DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER);
if( FOA >= pSectionHeader->PointerToRawData )//是否大于這個節表的FOA
{
if( FOA < pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData )//判斷是否在這個節表區域
return (FOA - pSectionHeader->PointerToRawData ) + pSectionHeader->VirtualAddress ;//計算并傳回RVA
}
}
return 0;
}
歡迎大家留言交流 ^ _ ^