思路:
RVA To FOA:
1、内存中的地址减去内存基址得到偏移,即RVA。此时RVA在PE头中
2、循环遍历节表中各个节的信息,判断在哪个节中。
3、找出在哪个节后,减去该节在内存中的偏移(VirturalAddress)得到在该节中的相对偏移。
4、该节的相对偏移+该节在文件中的偏移(PointToRawData),即得到FOA
// 代码节选,FOA计算RVA的过程
if(dwRva <= pOptionHeader->SizeOfHeaders){
return dwRva;
}else{
for(int n=0; n < pPEHeader->NumberOfSections; n++, pSectionHeaderTemp++){
if((dwRva >= pSectionHeaderTemp->VirtualAddress) && (dwRva < (pSectionHeaderTemp->VirtualAddress + pSectionHeaderTemp->Misc.VirtualSize)))
return dwRva - pSectionHeaderTemp->VirtualAddress + pSectionHeaderTemp->PointerToRawData;
}
}
FOA TO RVA:
1、文件中的地址减去文件基址,得到在文件中的偏移,即FOA。同样在头中
2、循环遍历节表中各个节的信息,判断在哪个节中。
3、找出在哪个节后,减去该节在文件中的偏移(PointToRawData)得到在该节中的相对偏移。
4、该节的相对偏移+该节在内存中的偏移(VirtualAddress),即得到RVA。
// 代码节选,RVA计算FOA过程
if(dwFoa <= pOptionHeader->SizeOfHeaders){
return dwFoa;
}else{
for(int i=0; i < pPEHeader->NumberOfSections; i++, pSectionHeaderTemp){
if((dwFoa >= pSectionHeaderTemp->PointerToRawData) && (dwFoa < (pSectionHeaderTemp->PointerToRawData + pSectionHeaderTemp->SizeOfRawData)))
return dwFoa - pSectionHeaderTemp->PointerToRawData + pSectionHeaderTemp->VirtualAddress;
}
}
完整代码
#include<stdio.h>
#include<windows.h>
DWORD toLoaderPE(LPSTR file_path, PVOID* pFileBuffer){
FILE *pFile;
DWORD FileSize = 0;
PVOID pFileBufferTemp = NULL;
pFile = fopen(file_path, "rb");
if(!pFile){
printf("文件读取失败!\n");
return 0;
}
fseek(pFile, 0, SEEK_END);
FileSize = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
pFileBufferTemp = malloc(FileSize);
if(!pFileBufferTemp){
printf("内存分配失败!\n");
fclose(pFile);
return 0;
}
DWORD n = fread(pFileBufferTemp, FileSize, 1, pFile);
if(!n){
printf("读入内存失败!\n");
free(pFileBufferTemp);
fclose(pFile);
return 0;
}
*pFileBuffer = pFileBufferTemp;
pFileBufferTemp = NULL;
return FileSize;
}
DWORD Rva2Foa(PVOID pFileBuffer, DWORD dwRva){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
if(!pFileBuffer){
printf("从磁盘读取文件为空!\n");
return 0;
}
if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE){
printf("(Rva2Foa)没有MZ标志!\n");
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if(*(PDWORD)((DWORD)pDosHeader + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE){
printf("(Rva2Foa)没有PE标志!\n");
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER pSectionHeaderTemp = pSectionHeader;
PIMAGE_SECTION_HEADER pNextSectionHeaderTemp = pSectionHeader + 1;
if(dwRva <= pOptionHeader->SizeOfHeaders){
return dwRva;
}else{
for(int n=1; n < pPEHeader->NumberOfSections; n++, pSectionHeaderTemp++, pNextSectionHeaderTemp++){
if((dwRva >= pSectionHeaderTemp->VirtualAddress) && (dwRva < (pNextSectionHeaderTemp->VirtualAddress)))
return dwRva - pSectionHeaderTemp->VirtualAddress + pSectionHeaderTemp->PointerToRawData;
}
}
if (dwRva >= pSectionHeaderTemp->VirtualAddress && dwRva < pOptionHeader->SizeOfImage)
{
return pSectionHeaderTemp->PointerToRawData + dwRva - pSectionHeaderTemp->VirtualAddress;
}
printf("RVA TO FOA Failed!\n");
return 0;
}
DWORD Foa2Rva(PVOID pFileBuffer, DWORD dwFoa){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
if(!pFileBuffer){
printf("从磁盘读取文件为空!\n");
return 0;
}
if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE){
printf("没有MZ标志!\n");
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if(*(PDWORD)((DWORD)pDosHeader + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE){
printf("没有PE标志!\n");
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER pSectionHeaderTemp = pSectionHeader;
if(dwFoa <= pOptionHeader->SizeOfHeaders){
return dwFoa;
}else{
for(int i=0; i < pPEHeader->NumberOfSections; i++, pSectionHeaderTemp){
if((dwFoa >= pSectionHeaderTemp->PointerToRawData) && (dwFoa < (pSectionHeaderTemp->PointerToRawData + pSectionHeaderTemp->SizeOfRawData)))
return dwFoa - pSectionHeaderTemp->PointerToRawData + pSectionHeaderTemp->VirtualAddress;
}
}
return 0;
}
int main(){
LPSTR file_path = "C:\\Users\\lolol\\Desktop\\geek2.exe";
PVOID pFileBuffer = NULL;
DWORD FileSize = toLoaderPE(file_path, &pFileBuffer);
printf("从磁盘读取文件大小:%x\n", FileSize);
DWORD RvaToFoa = Rva2Foa(pFileBuffer, 0x001234);
printf("0x001234 RVA2FOA: %x\n", RvaToFoa);
DWORD FoaToRva = Foa2Rva(pFileBuffer, 0x001234);
printf("0x001234 FOA2RVA: %x\n", FoaToRva);
return 0;
}
计算结果