4、文件与内存转换相关

4、文件与内存转换相关

FileBufferToImageBuffer

也是一样的长话短说。这里涉及了一点,就是内存对齐

PE头与节区之间 节区与节区时间会发生内存对齐。在文件中有一个文件对齐

image

在可选PE头中有这两个进行标识,之前也写过这个内存对齐的博客,这里就不多说了

下面贴几个代码

模拟内存拉伸的代码

PCHAR FileBufferToImageBuff(PCHAR pFileBuffer)
{
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((PCHAR)pDos + pDos->e_lfanew);
	PIMAGE_FILE_HEADER pFile = (PIMAGE_FILE_HEADER)((PCHAR)pNt + 4);
	PIMAGE_OPTIONAL_HEADER pOpt = (PIMAGE_OPTIONAL_HEADER)((PCHAR)pFile + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((PCHAR)pOpt + pFile->SizeOfOptionalHeader);

	// 分配ImageBuffer对应的内存空间
	DWORD dwImageSize = pOpt->SizeOfImage;
	PCHAR pImageBuffer = (PCHAR)malloc(dwImageSize);
	if (!pImageBuffer) {
		log_error("分配ImageBuffer对应的内存空间  error");
		return NULL;
	}
	memset(pImageBuffer, 0, dwImageSize);
	// 把FileBuff 拉伸到 ImageBuff
	// 拷贝PE头
	memcpy(pImageBuffer, pFileBuffer, pOpt->SizeOfHeaders);
	// 拷贝节区数据
	for (size_t i = 0; i < pFile->NumberOfSections; i++)
	{
		memcpy(
			pImageBuffer + pSec[i].VirtualAddress, 
			pFileBuffer + pSec[i].PointerToRawData,
			pSec[i].SizeOfRawData
		);
	}
	return pImageBuffer;
}

拉伸还原的代码

PCHAR ImageBuffToFileBuff(PCHAR ImageBuffer,PDWORD fileSize)
{
	// 定位结构
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageBuffer;
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(ImageBuffer + pDos->e_lfanew);
	PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PCHAR)pNt + 4);
	PIMAGE_OPTIONAL_HEADER pOpt = (PIMAGE_OPTIONAL_HEADER)((PCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
	// 定位节表结构
	PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((PCHAR)pOpt + pFil->SizeOfOptionalHeader);
	// 计算一下FileBuffer
	DWORD dwFileSize = pOpt->SizeOfHeaders;
	for (size_t i = 0; i < pFil->NumberOfSections; i++)
	{
		dwFileSize += pSec[i].SizeOfRawData;// 文件大小
	}
	PCHAR pFileBuffer = (PCHAR)malloc(dwFileSize);
	if (!pFileBuffer)
	{
		log_error("malloc falild");
		return NULL;
	}
	memset(pFileBuffer, 0, dwFileSize);
	// 拷贝头
	memcpy(pFileBuffer, ImageBuffer, pOpt->SizeOfHeaders);

	for (size_t i = 0; i < pFil->NumberOfSections; i++)
	{
		memcpy(
			pFileBuffer + pSec[i].PointerToRawData,
			ImageBuffer + pSec[i].VirtualAddress,
			pSec[i].SizeOfRawData
		);
	}

	return pFileBuffer;
}

保存文件的代码、

BOOL SaveFile(PCHAR FileBuffer, DWORD filesize)
{
	if (FileBuffer == NULL)
	{
		return FALSE;
	}
	FILE* pFile = fopen(OUT_PATH, "wb");
	fwrite(FileBuffer, filesize, 1, pFile);
	fclose(pFile);
	return FALSE;
}

RvaToFoa and FoaToRva

这里主要也是一样的,目的是为了把文件加载到内存的数据,在WinHex中进行定位,

首先我们知道PE头一样的。不一样的是各个页表,他们之间会被内存对齐,导致不一样的。 但是页表中有页的大小和起始地址数据。 所以这个问题也就有了解决方法,下面直接贴代码

DWORD RvaToFoa(PCHAR pBuffer, DWORD dwRva)
{
	if (pBuffer == NULL) return -1;
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuffer;
	PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);
	PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PCHAR)pNth + 4);
	PIMAGE_OPTIONAL_HEADER pOpt = (PIMAGE_OPTIONAL_HEADER)((CHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((PCHAR)pOpt + pFil->SizeOfOptionalHeader);

	if (dwRva <= pOpt->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 -1;
}

FoaToRva代码如下:

DWORD FoaToRva(PCHAR pBuffer, DWORD dwFoa)
{
	if (pBuffer == NULL) return -1;
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuffer;
	PIMAGE_NT_HEADERS pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);
	PIMAGE_FILE_HEADER pFil = (PIMAGE_FILE_HEADER)((PCHAR)pNth + 4);
	PIMAGE_OPTIONAL_HEADER pOpt = (PIMAGE_OPTIONAL_HEADER)((CHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)((PCHAR)pOpt + pFil->SizeOfOptionalHeader);

	if (dwFoa <= pOpt->SizeOfHeaders)	return dwFoa;

	for (size_t i = 0; i < pFil->NumberOfSections; i++)
	{
		if (dwFoa >= pSec[i].PointerToRawData && (dwFoa <= (pSec[i].PointerToLinenumbers + pSec[i].SizeOfRawData)))
		{
			return dwFoa - pSec[i].PointerToLinenumbers + pSec[i].VirtualAddress;
		}
	}

	return -1;
	return 0;
}

这里再复习一下。页表中含有的数据有什么。

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;  内存中的大小
    } Misc;
    DWORD   VirtualAddress;      虚拟地址 RVA
    DWORD   SizeOfRawData;       文件中占的大小
    DWORD   PointerToRawData;	 文件起始位置
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;     页表属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

页表属性,其实就是表述该页表有那些属性,使用VS 直接进去里面有解释的。这里就不多说了

posted @ 2024-12-19 19:56  未然king  阅读(4)  评论(0编辑  收藏  举报