7.PE文件之RVA与FOA转换

PE文件头和PE内存映像的文件头大小是一样的.节的数据在内存和磁盘文件的大小是不一样的,节表项记录了内存映像中节的起始RVA(IMAGE_SECTION_HEADER -> VirtualAddress),也同样记录了本节在文件中的起始偏移FOA(IMAGE_SECTION_HEADER -> PointerToRawData).由于节在内存中是线性排列的,因此如果找到下一个节的内存起始RVA就能知道上一个节的大小,所有的节组合起来就是PE中除去文件头以外的内容,而文件头在磁盘文件中和内存中是没有变化的.

  • 相对虚拟地址(Relative Virtual Address, RVA) = 虚拟地址(VA) - 基地址(ImageBase).相对于基地址的偏移,即RVA是虚拟内存中用来定位某个特定位置的地址,该地址的值是这个特定位置距离某个模块基地址的偏移量.
  • 文件偏移地址(File Offset Address, FOA)和内存无关,它是指某个位置距离文件头的偏移.

文件中手动转换示例:

1).执行下述代码获取全局变量地址

DWORD g_Data = 0x12345678;

int main()
{
  printf("global data -> [0x%08x] \r\n", g_Data);
  system("Pause");
  return 0;
}

得到当前全局变量地址(VA)为0x00541008

2).通过WinHex解析文件.获取ImageBase与文件和内存对齐大小

ImageBase = 0x00400000

SectionAlignment = 0x00001000

FileAlignment = 0x00000200

Ps: 如果文件对齐与内存对齐相同为1000h,且节区在内存中大小小于文件中大小那么RVA与FOA一致.这里测试文件不同

RVA = VA - ImageBase = 0x00541008 - 0x00400000 = 0x141008

3).通过WinHex解析文件.获取节区对应文件与内存偏移

这里方便用工具展示结果(.textbss 代表未被初始化的静态内存区。此区段不占用磁盘空间,仅占用内存空间)

判断当前RVA(0x141008)位于哪个节中.公式为RVA ≥ VirtualAddress && RVA < VirtualAddress + VirtualSize

可以得出RVA(0x141008)位于节.data中.

算出RVA在节区对应OFFSET RVA - VirtualAddress = 0x141008 - 0x141000 = 0x8

FOA为OFFSET + PointerToRawData = 0x8 + 0xE7800 = 0xE7808

全局变量对应FOA为0xE7808数据为0x12345678;

修改其对应数据并保存观察效果:

数据被成功修改.

上述示例通过代码实现(全局变量未初始化时在文件中将不会有对应数据,拉伸到内存后才会分配对应内存):

RVA转FOA

DWORD RvaToFoa(IN PVOID pBuffer, IN DWORD dwRva)
{
	//定位PE结构
	PIMAGE_DOS_HEADER			pDos = (PIMAGE_DOS_HEADER)pBuffer;
	PIMAGE_NT_HEADERS			pNth = (PIMAGE_NT_HEADERS)((PUCHAR)pBuffer + pDos->e_lfanew);
	PIMAGE_FILE_HEADER			pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
	PIMAGE_OPTIONAL_HEADER		pOpo = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER		pSec = (PIMAGE_SECTION_HEADER)((PUCHAR)pOpo + pFil->SizeOfOptionalHeader);

	//转换地址是否在头+节表中
	if (dwRva < pOpo->SizeOfHeaders)
	{
		return dwRva;
	}

	//遍历转换地址在哪个节中
	for (size_t i = 0; i < pFil->NumberOfSections; i++)
	{
		if ((dwRva >= pSec[i].VirtualAddress) && (dwRva < pSec[i].VirtualAddress + pSec[i].Misc.VirtualSize))
		{
			return dwRva - pSec[i].VirtualAddress + pSec[i].PointerToRawData;
		}

	}

	return 0;

}

FOA转RVA

DWORD FoaToRva(IN PVOID pBuffer, IN DWORD dwFoa)
{
	//定位PE结构
	PIMAGE_DOS_HEADER			pDos = (PIMAGE_DOS_HEADER)pBuffer;
	PIMAGE_NT_HEADERS			pNth = (PIMAGE_NT_HEADERS)((PUCHAR)pBuffer + pDos->e_lfanew);
	PIMAGE_FILE_HEADER			pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
	PIMAGE_OPTIONAL_HEADER		pOpo = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER		pSec = (PIMAGE_SECTION_HEADER)((PUCHAR)pOpo + pFil->SizeOfOptionalHeader);

	//转换地址是否在头+节表中
	if (dwFoa < pOpo->SizeOfHeaders)
	{
		return dwFoa;
	}

	//遍历转换地址在哪个节中
	for (size_t i = 0; i < pFil->NumberOfSections; i++)
	{
		if ((dwFoa >= pSec[i].PointerToRawData) && (dwFoa < pSec[i].PointerToRawData + pSec[i].SizeOfRawData))
		{
			return dwFoa - pSec[i].PointerToRawData + pSec[i].VirtualAddress;
		}

	}

	return 0;
}
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值