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);// 计算一下FileBufferDWORD 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; 虚拟地址 RVADWORD SizeOfRawData; 文件中占的大小DWORD PointerToRawData; 文件起始位置DWORD PointerToRelocations;DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics; 页表属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
页表属性,其实就是表述该页表有那些属性,使用VS 直接进去里面有解释的。这里就不多说了