PE工具函数(新)

这篇博客介绍了关于PE文件的一些常见操作,包括在32位多字节字符集环境下的编译细节。
摘要由CSDN通过智能技术生成

说明

一些常见的PE操作。。

2021年3月7日

#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif // !_CRT_SECURE_NO_WARNINGS


#include "PE.h"
#include <stdio.h>
#include <WINDOWS.H>
#include <STRING.h>
#include <MALLOC.H>
#include "DebugTool.h"
#include "Win32API.h"






// 读取文件到内存中,返回读取的字节数;读取失败返回0
DWORD FileToMemory(LPCSTR lpszFile, LPVOID *pFileBuffer)
{
   
	// 打开文件,权限是读共享
	HANDLE hFile = pCreateFileA(lpszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hFile)
	{
   
		PrintDebugInfo("打开文件失败\n");
		return 0;
	}

	// 判断文件大小
	LARGE_INTEGER nFileSize = {
    0 };
	pGetFileSizeEx(hFile, &nFileSize);
	if (nFileSize.QuadPart >= 0xFFFFFFFFull)
	{
   
		PrintDebugInfo("源文件过大,无法处理(%lld)\n", nFileSize.QuadPart);
		pCloseHandle(hFile);
		return 0;
	}
	pSetFilePointer(hFile, 0, NULL, FILE_BEGIN);
	//PrintDebugInfo("文件大小:%d 字节\n", nFileSize.LowPart);

	LPVOID pFile = pVirtualAlloc(NULL, nFileSize.LowPart, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (pFile == NULL)
	{
   
		PrintDebugInfo("申请内存失败\n");
		pCloseHandle(hFile);
		return 0;
	}

	memset(pFile, 0, nFileSize.LowPart);

	// 读文件
	DWORD dwRead = 0;
	BOOL bRet = FALSE;
	bRet = pReadFile(hFile, pFile, nFileSize.LowPart, &dwRead, NULL);
	if (bRet == FALSE)
	{
   
		PrintDebugInfo("读取文件错误:%d\n", GetLastError());
		pVirtualFree(pFile, 0, MEM_RELEASE);
		pCloseHandle(hFile);
		return 0;
	}

	if (dwRead != nFileSize.LowPart)
	{
   
		PrintDebugInfo("期望读取:%d,实际读取:%d\n", nFileSize.LowPart, dwRead);
		pVirtualFree(pFile, 0, MEM_RELEASE);
		pCloseHandle(hFile);
		return 0;
	}

	pCloseHandle(hFile);
	*pFileBuffer = pFile;
	return nFileSize.LowPart;
}

// 验证是否是合法的32位PE文件
BOOL Is32PEFile(LPVOID pFileBuffer, DWORD dwSize)
{
   
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
   
		PrintDebugInfo("不是有效的MZ标志 %x != %x", pDosHeader->e_magic, IMAGE_DOS_SIGNATURE);
		return FALSE;
	}
	if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
	{
   
		PrintDebugInfo("不是有效的PE标记");
		return FALSE;
	}
	if (pNtHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
	{
   
		PrintDebugInfo("不是32位PE程序");
		return FALSE;
	}
	return TRUE;
}

// 将 FileBuffer 拉伸成 ImageBuffer 并写入到新的缓冲区
// 返回 ImageBuffer 的大小;失败返回0
DWORD FileBufferToImageBuffer(LPVOID pFileBuffer, LPVOID *pImageBuffer, DWORD flProtect)
{
   
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(
		(DWORD)pNtHeader +
		sizeof(pNtHeader->Signature) +
		sizeof(pNtHeader->FileHeader) +
		pNtHeader->FileHeader.SizeOfOptionalHeader);

	*pImageBuffer = pVirtualAlloc(NULL, pNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, flProtect);
	if (*pImageBuffer == NULL)
	{
   
		PrintDebugInfo("分配内存失败\n");
		return 0;
	}
	memset(*pImageBuffer, 0, pNtHeader->OptionalHeader.SizeOfImage);

	// 复制所有头(DOS头,PE头,可选PE头)和节表
	memcpy(*pImageBuffer, pFileBuffer, pNtHeader->OptionalHeader.SizeOfHeaders);

	// 遍历节表,复制所有节	
	for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
	{
   
		memcpy((PBYTE)(*pImageBuffer) + pSectionHeader[i].VirtualAddress,
			(PBYTE)pFileBuffer + pSectionHeader[i].PointerToRawData,
			pSectionHeader[i].SizeOfRawData);
	}
	return pNtHeader->OptionalHeader.SizeOfImage;
}

// 将 ImageBuffer 变成文件对齐的 FileBuffer 写入新的缓冲区
// 返回复制的大小,失败返回0
DWORD ImageBufferToFileBuffer(LPVOID pImageBuffer, LPVOID *pFileBuffer)
{
   
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(
		(DWORD)pNtHeader +
		sizeof(pNtHeader->Signature) +
		sizeof(pNtHeader->FileHeader) +
		pNtHeader->FileHeader.SizeOfOptionalHeader);

	// 最后一个节表
	PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + pNtHeader->FileHeader.NumberOfSections - 1;

	// 计算要复制的字节
	// 这一步有BUG,当最后一个节后面还有数据时,这些数据会丢失
	DWORD dwFileBufferSize = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;

	*pFileBuffer = pVirtualAlloc(NULL, dwFileBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (*pFileBuffer == NULL)
	{
   
		PrintDebugInfo("分配内存失败\n");
		return 0;
	}
	memset(*pFileBuffer, 0, dwFileBufferSize);

	// 复制所有头(DOS头,PE头,可选PE头)和节表
	memcpy(*pFileBuffer, pImageBuffer, pNtHeader->OptionalHeader.SizeOfHeaders);

	// 遍历节表,复制所有节	
	for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
	{
   
		memcpy((PBYTE)(*pFileBuffer) + pSectionHeader[i].PointerToRawData,
			(PBYTE)pImageBuffer + pSectionHeader[i].VirtualAddress,
			pSectionHeader[i].SizeOfRawData);
	}

	return dwFileBufferSize;
}

// 内存数据写入文件
BOOL MemoryToFile(LPVOID pMemBuffer, DWORD dwSize, LPCSTR lpszFile)
{
   
	// 打开文件,权限是独占写
	HANDLE hFile = pCreateFileA(lpszFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hFile)
	{
   
		PrintDebugInfo("打开文件失败\n");
		return FALSE;
	}
	BOOL bRet = FALSE;
	DWORD dwWritten = 0;
	bRet = pWriteFile(hFile, pMemBuffer, dwSize, &dwWritten, NULL);
	if (!bRet)
	{
   
		PrintDebugInfo("写文件错误:%d\n", GetLastError());
		pCloseHandle(hFile);
		return FALSE;
	}
	pCloseHandle(hFile);
	return TRUE;
}

// 计算对齐的函数,如偏移为900,对齐为1000h,返回1000h
DWORD Align(DWORD dwOffset, DWORD dwAlign)
{
   
	// 如果偏移小于对齐,向上取整
	if (dwOffset <= dwAlign) return dwAlign;
	// 如果偏移大于对齐且不能除尽,向上取整
	if (dwOffset % dwAlign)
	{
   
		return (dwOffset / dwAlign + 1) * dwAlign;
	}
	// 如果能除尽,直接返回offset
	return dwOffset;
}

// RVA 转 FOA
DWORD RvaToFoa(LPVOID pFileBuffer, DWORD dwRva)
{
   
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(
		(DWORD)pNtHeader +
		sizeof(pNtHeader->Signature) +
		sizeof(pNtHeader->FileHeader) +
		pNtHeader->FileHeader.SizeOfOptionalHeader);

	if (dwRva < pNtHeader->OptionalHeader.SizeOfHeaders)
	{
   
		return dwRva;
	}

	// 遍历节表,确定偏移属于哪一个节	
	for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
	{
   
		if (dwRva >= pSectionHeader[i].VirtualAddress && \
			dwRva < pSectionHeader[i].VirtualAddress + pSectionHeader[i].Misc.VirtualSize)
		{
   
			
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值