• RVA和FOA的相互转换


    全局变量有无初始值的区别:

    没有初始值:PE文件在文件中的状态的时候不会对该变量的地址进行存储,只有在内存中运行的时候的状态才会进行分配

    有初始值:PE文件在文件中的状态的时候会对该变量的地址进行存储


    什么是VA、RVA、FOA

    VA:英文全称是Virual Address,简称VA,中文意思是虚拟地址,指的是文件被载入虚拟内存后的地址。

    ImageBase:中文意思是基址,指的是程序在虚拟内存中被装载的位置。

    RVA:相对虚拟地址,可以理解为文件被装载到虚拟内存(拉伸)后先对于基址的偏移地址。

    它的对齐方式一般是以1000h为单位,以虚拟内存对齐的方式对齐的,具体对齐需要参照IMAGE_OPTIONAL_HEADER32中的SectionAlignment成员。

    FOA:文件偏移地址。可以理解为文件在磁盘上存放时相对于文件开头的偏移地址。

    它的对齐方式一般是以200h为单位,以文件对齐的方式对齐的,具体对齐需要参照IMAGE_OPTIONAL_HEADER32中的FileAlignment成员。

    计算方式:RVA = VA(虚拟地址) - ImageBase(基址)


    RVA转换为FOA

    RVA(相对虚拟地址)转换FOA(文件偏移地址)过程:

    int a = 0x12345678;
    int main() {
        printf("地址:%.8X
    ",&a);
        printf("数值:%d
    ",a);
        return 0; 
    } 
    

    运行结果:

    D:VC6ENCOMMONMSDEV98BINDebug>5.exe
    地址:00424A30
    数值:305419896
    

    我们要求RVA,RVA = VA - ImageBase,VA虚拟地址为0x00424A30

    那么 RVA = 424A30 - ImageBase

    查看Imagebase:0x00400000

    RVA = 424A30 - 400000 = 24A30

    接下来寻址FOA,就要考虑文件对齐跟内存对齐不是一样的问题,大家可以想象下如果一样的话 ,那么就是 文件对齐和内存对齐是一样的 唯一变化的就是内存中会加上基址的地址,现在基址已经减去了,那么这两种也都一样了!


    第一种情况:文件对齐跟内存对齐一样的情况,那么这样就可以直接去找 0x24A30的地址了 这个地址也就是FOA

    第二种情况:文件对齐和内存对齐不一样的情况

    我们需要判断RVA属于哪个节/头,这里也要分为两种情况!

    1):如果RVA属于文件头部(DOS头 + PE头 + 节表),头部大小是文件对齐大小的整数倍!

    那么不需要进行计算了,因为DOS头和PE头和节表在文件中和在内存中展开都是一样的,直接从开始位置寻找到RVA个字节即可,就是找0x24A30,也就是FOA(文件偏移地址)

    2):如果RVA不在头,就要判断在哪个节里面

    判断节开始位置到节结束位置 我们的RVA是否在这个范围里面,总共分为三步骤:

    第一步:指定节.VirtualAddress <= RVA <= 指定节.VirtualAddress + VirtualSize(当前节内存实际大小)

    第二步:差值 = RVA - 指定节.VirtualAddress

    第三步:FOA = 指定节.PointerToRawData + 差值

    代码实现:

    #include<windows.h>
    #include<stdio.h>
    
    #define FILE_PATH "C:\Documents and Settings\Administrator\桌面\PE练习素材\练习素材\NOTEPAD.EXE"
    
    int GetFileLength(FILE *pf, DWORD *Length)
    {
    	int ret = 0;
    	
    	fseek(pf, 0, SEEK_END);
    	*Length = ftell(pf);
    	fseek(pf, 0, SEEK_SET);
    	
    	return ret;
    }
    
    int MyReadFile(void **pFileAddress)
    {
    	int ret = 0;
    	DWORD Length = 0;
    	//打开文件
    	FILE* pf = fopen(FILE_PATH, "rb");
    	if (pf == NULL)
    	{
    		ret = -1;
    		printf("func ReadFile() Error!
    ");
    		return ret;
    	}
    	
    	//获取文件长度
    	ret = GetFileLength(pf, &Length);
    	if (ret != 0 && Length == -1)
    	{
    		ret = -2;
    		printf("func GetFileLength() Error!
    ");
    		return ret;
    	}
    	
    	//分配空间
    	*pFileAddress = (PVOID)malloc(Length);
    	if (*pFileAddress == NULL)
    	{
    		ret = -3;
    		printf("func malloc() Error!
    ");
    		return ret;
    	}
    	memset(*pFileAddress, 0, Length);
    	
    	//读取文件进入内存
    	fread(*pFileAddress, Length, 1, pf);
    	
    	fclose(pf);
    	return ret;
    }
    
    int RVA_TO_FOA(PVOID FileAddress, DWORD RVA, PDWORD pFOA)
    {
    	int ret = 0;
    	
    	PIMAGE_DOS_HEADER pDosHeader				= (PIMAGE_DOS_HEADER)(FileAddress);
    	PIMAGE_FILE_HEADER pFileHeader				= (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
    	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader	= (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER));
    	PIMAGE_SECTION_HEADER pSectionGroup			= (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
    	
    	//RVA在文件头中 或 SectionAlignment 等于 FileAlignment 时RVA等于FOA
    	if (RVA < pOptionalHeader->SizeOfHeaders || pOptionalHeader->SectionAlignment == pOptionalHeader->FileAlignment)
    	{
    		*pFOA = RVA;
    		return ret;
    	}
    
    	//循环判断RVA在节区中
    	for (int i = 0; i < pFileHeader->NumberOfSections; i++)
    	{
    		if (RVA >= pSectionGroup[i].VirtualAddress && RVA < pSectionGroup[i].VirtualAddress + pSectionGroup[i].Misc.VirtualSize)
    		{
    			*pFOA = pSectionGroup[i].PointerToRawData + RVA - pSectionGroup[i].VirtualAddress;
    
    			return ret;
    		}
    	}
    	
    	//没有找到地址
    	ret = -4;
    	printf("func RAV_TO_FOA() Error: %d 地址转换失败!
    ", ret);
    	return ret;
    }
    
    
    int main(){
    	PVOID pFileAddress;
    	DWORD FOA;
    
    	MyReadFile(&pFileAddress);
    	RVA_TO_FOA(pFileAddress,(DWORD)0x1080,&FOA);
    	printf("%x",FOA);
    
    	
    
    	return 0;
    }
    

    FOA转换为RVA

    FOA(文件偏移地址)转换RVA(相对虚拟地址)过程:

    设FOA为节数据的任意一位置

    1.计算差值偏移:

    FOA - 指定节.PointerToRawData = 差值

    2.计算RVA:

    差值 + 指定节.VirtuallAddress(节数据在内存中展开的位置) = RVA

    3.计算虚拟地址:

    VA = RVA + ImageBase

    需要注意的就是我们的 FOA 在哪一个节中:

    指定节.PointerToRawData <= FOA <= 指定节..PointerToRawData + 指定节..SizeofRawData

    代码实现:

    #include<windows.h>
    #include<stdio.h>
    
    #define FILE_PATH "C:\Documents and Settings\Administrator\桌面\PE练习素材\练习素材\NOTEPAD.EXE"
    
    int GetFileLength(FILE *pf, DWORD *Length)
    {
    	int ret = 0;
    	
    	fseek(pf, 0, SEEK_END);
    	*Length = ftell(pf);
    	fseek(pf, 0, SEEK_SET);
    	
    	return ret;
    }
    
    int MyReadFile(void **pFileAddress)
    {
    	int ret = 0;
    	DWORD Length = 0;
    	//打开文件
    	FILE* pf = fopen(FILE_PATH, "rb");
    	if (pf == NULL)
    	{
    		ret = -1;
    		printf("func ReadFile() Error!
    ");
    		return ret;
    	}
    	
    	//获取文件长度
    	ret = GetFileLength(pf, &Length);
    	if (ret != 0 && Length == -1)
    	{
    		ret = -2;
    		printf("func GetFileLength() Error!
    ");
    		return ret;
    	}
    	
    	//分配空间
    	*pFileAddress = (PVOID)malloc(Length);
    	if (*pFileAddress == NULL)
    	{
    		ret = -3;
    		printf("func malloc() Error!
    ");
    		return ret;
    	}
    	memset(*pFileAddress, 0, Length);
    	
    	//读取文件进入内存
    	fread(*pFileAddress, Length, 1, pf);
    	
    	fclose(pf);
    	return ret;
    }
    
    int FOA_TO_RVA(PVOID FileAddress, PDWORD pRVA, DWORD FOA)
    {
    	int ret = 0;
    	
    	PIMAGE_DOS_HEADER pDosHeader				= (PIMAGE_DOS_HEADER)(FileAddress);
    	PIMAGE_FILE_HEADER pFileHeader				= (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
    	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader	= (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + sizeof(IMAGE_FILE_HEADER));
    	PIMAGE_SECTION_HEADER pSectionGroup			= (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
    	
    	//RVA在文件头中 或 SectionAlignment 等于 FileAlignment 时RVA等于FOA
    	if (FOA < pOptionalHeader->SizeOfHeaders || pOptionalHeader->SectionAlignment == pOptionalHeader->FileAlignment)
    	{
    		*pRVA = FOA;
    		return ret;
    	}
    
    	//循环判断FOA在节区中
    	for (int i = 0; i < pFileHeader->NumberOfSections; i++)
    	{
    		if (FOA >= pSectionGroup[i].PointerToRawData && FOA < pSectionGroup[i].PointerToRawData + pSectionGroup[i].Misc.VirtualSize)
    		{
    			*pRVA = FOA - pSectionGroup[i].PointerToRawData + pSectionGroup[i].VirtualAddress;
    
    			return ret;
    		}
    	}
    	
    	//没有找到地址
    	ret = -4;
    	printf("func FOA_TO_RVA() Error: %d 地址转换失败!
    ", ret);
    	return ret;
    }
    
    
    int main(){
    	PVOID pFileAddress;
    	DWORD RVA;
    
    	MyReadFile(&pFileAddress);
    	FOA_TO_RVA(pFileAddress,&RVA,(DWORD)0x480);
    	printf("%x",RVA);
    
    	
    
    	return 0;
    }
    
  • 相关阅读:
    Set,List,Map的区别
    阅读笔记15
    阅读笔记14
    阅读笔记13
    阅读笔记12
    阅读笔记11
    阅读笔记10
    架构漫谈读后感
    阅读笔记1
    暑期周记8
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/12312370.html
Copyright © 2020-2023  润新知