4、文件与内存转换相关
4、文件与内存转换相关
FileBufferToImageBuffer
也是一样的长话短说。这里涉及了一点,就是内存对齐
PE头与节区之间 节区与节区时间会发生内存对齐。在文件中有一个文件对齐
在可选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 直接进去里面有解释的。这里就不多说了