PE课后作业参考代码(含测试代码)

2020年5月28日 00:12:46

PEToolkit.cpp

#include "headers.h"

// 读取PE文件到内存中,返回读取的字节数;读取失败返回0
DWORD ReadPEFile(LPCSTR lpszFile, LPVOID *pFileBuffer)
{
   
	FILE *pFile = NULL;
	DWORD dwFileSize = 0;
	pFile = fopen(lpszFile, "rb");
	if (pFile == NULL) 
	{
   
		printf("打开文件失败\n");
		return 0;
	}
	fseek(pFile, 0, SEEK_END);
	dwFileSize = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);
	*pFileBuffer = malloc(dwFileSize);
	if (*pFileBuffer == NULL)
	{
   
		printf("分配内存失败\n");
		fclose(pFile);
		return 0;
	}	
	DWORD dwRead = fread(*pFileBuffer, 1, dwFileSize, pFile);
	fclose(pFile);
	if (dwRead != dwFileSize)
	{
   
		printf("文件大小 = %d\t实际写入内存字节 = %d\t写入失败\n", dwFileSize, dwRead);
		return 0;
	}
	if (!IsPEFile(*pFileBuffer, dwRead))
	{
   
		printf("不是有效的PE文件\n");
		return 0;
	}
	return dwRead;
}

// 验证是否PE文件
BOOL IsPEFile(LPVOID pFileBuffer, DWORD dwSize)
{
   
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
	PIMAGE_SECTION_HEADER pSectionHeader = \
		(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	
	if (*((PWORD)pDosHeader) != IMAGE_DOS_SIGNATURE)
	{
   
		printf("不是有效的MZ标志\n");
		return FALSE;
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
   
		printf("不是有效的PE标记\n");
		return FALSE;
	}

	return TRUE;
}

// 打印PE头信息
VOID PrintNTHeaders(LPCSTR lpszFile)
{
   
	LPVOID pFileBuffer = NULL;
	DWORD dwFileSize = ReadPEFile(lpszFile, &pFileBuffer);
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
	PIMAGE_SECTION_HEADER pSectionHeader = \
		(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
		
	if (dwFileSize == 0)
	{
   
		printf("读取文件失败\n");
		return;
	}

	//打印DOS头
	puts("----DOS HEADER----");
	printf("e_magic = %x\n", pDosHeader->e_magic);
	printf("e_lfanew = %x\n", pDosHeader->e_lfanew);	
	//打印NT头	
	printf("----标准PE头----\n");
	printf("Machine = %x\n", pPEHeader->Machine);
	printf("NumberOfSections = %x\n", pPEHeader->NumberOfSections);
	printf("TimeDateStamp = %x\n", pPEHeader->TimeDateStamp);
	printf("PointerToSymbolTable = %x\n", pPEHeader->PointerToSymbolTable);
	printf("NumberOfSymbols = %x\n", pPEHeader->NumberOfSymbols);
	printf("SizeOfOptionalHeader = %x\n", pPEHeader->SizeOfOptionalHeader);
	printf("Characteristics = %x\n", pPEHeader->Characteristics);
	//可选PE头	
	printf("----可选PE头----\n");
	printf("Magic = %x\n", pOptionHeader->Magic);
	printf("MajorLinkerVersion = %x\n", pOptionHeader->MajorLinkerVersion);
	printf("MinorLinkerVersion = %x\n", pOptionHeader->MinorLinkerVersion);
	printf("SizeOfCode = %x\n", pOptionHeader->SizeOfCode);
	printf("SizeOfInitializedData = %x\n", pOptionHeader->SizeOfInitializedData);
	printf("SizeOfUninitializedData = %x\n", pOptionHeader->SizeOfUninitializedData);
	printf("AddressOfEntryPoint = %x\n", pOptionHeader->AddressOfEntryPoint);
	printf("BaseOfCode = %x\n", pOptionHeader->BaseOfCode);
	printf("BaseOfData = %x\n", pOptionHeader->BaseOfData);
	printf("ImageBase = %x\n", pOptionHeader->ImageBase);
	printf("SectionAlignment = %x\n", pOptionHeader->SectionAlignment);
	printf("FileAlignment = %x\n", pOptionHeader->FileAlignment);
	printf("MajorOperatingSystemVersion = %x\n", pOptionHeader->MajorOperatingSystemVersion);
	printf("MinorOperatingSystemVersion = %x\n", pOptionHeader->MinorOperatingSystemVersion);
	printf("MajorImageVersion = %x\n", pOptionHeader->MajorImageVersion);
	printf("MinorImageVersion = %x\n", pOptionHeader->MinorImageVersion);
	printf("MajorSubsystemVersion = %x\n", pOptionHeader->MajorSubsystemVersion);
	printf("MinorSubsystemVersion = %x\n", pOptionHeader->MinorSubsystemVersion);
	printf("Win32VersionValue = %x\n", pOptionHeader->Win32VersionValue);
	printf("SizeOfImage = %x\n", pOptionHeader->SizeOfImage);
	printf("SizeOfHeaders = %x\n", pOptionHeader->SizeOfHeaders);
	printf("CheckSum = %x\n", pOptionHeader->CheckSum);
	printf("Subsystem = %x\n", pOptionHeader->Subsystem);
	printf("DllCharacteristics = %x\n", pOptionHeader->DllCharacteristics);
	printf("SizeOfStackReserve = %x\n", pOptionHeader->SizeOfStackReserve);
	printf("SizeOfStackCommit = %x\n", pOptionHeader->SizeOfStackCommit);
	printf("SizeOfHeapReserve = %x\n", pOptionHeader->SizeOfHeapReserve);
	printf("SizeOfHeapCommit = %x\n", pOptionHeader->SizeOfHeapCommit);
	printf("LoaderFlags = %x\n", pOptionHeader->LoaderFlags);
	printf("NumberOfRvaAndSizes = %x\n", pOptionHeader->NumberOfRvaAndSizes);
	//打印节表	
	char sectionName[9];
	for (int i = 0; i < pPEHeader->NumberOfSections; i++)
	{
   
		memset(sectionName, 0, 9);
		memcpy(sectionName, pSectionHeader->Name, 8);
		printf("----节表: [%s]----\n", sectionName);
		printf("VirtualSize = %x\n", pSectionHeader->Misc.VirtualSize);
		printf("VirtualAddress = %x\n", pSectionHeader->VirtualAddress);
		printf("SizeOfRawData = %x\n", pSectionHeader->SizeOfRawData);
		printf("PointerToRawData = %x\n", pSectionHeader->PointerToRawData);
		printf("Characteristics = %x\n", pSectionHeader->Characteristics);
		pSectionHeader++;
	}
	//释放内存
	free(pFileBuffer);
}

// 将 FileBuffer 拉伸成 ImageBuffer 并写入到新的缓冲区
// 返回 ImageBuffer 的大小;失败返回0
DWORD CopyFileBufferToImageBuffer(LPVOID pFileBuffer, LPVOID *pImageBuffer)
{
   
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
	PIMAGE_SECTION_HEADER pSectionHeader = \
		(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);

	*pImageBuffer = malloc(pOptionHeader->SizeOfImage);
	if (*pImageBuffer == NULL)
	{
   
		printf("分配内存失败\n");
		return 0;
	}
	memset(*pImageBuffer, 0, pOptionHeader->SizeOfImage);
	// 复制DOS头+PE头+可选PE头+节表+文件对齐
	memcpy(*pImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);
	// 遍历节表,复制所有节	
	for (int i = 0; i < pPEHeader->NumberOfSections; i++)
	{
   
		memcpy((LPVOID)((DWORD)(*pImageBuffer) + pSectionHeader[i].VirtualAddress), \
			(LPVOID)((DWORD)pFileBuffer + pSectionHeader[i].PointerToRawData), \
			pSectionHeader[i].SizeOfRawData);
	}
	return pOptionHeader->SizeOfImage;
}

// 将 ImageBuffer 变成文件对齐的 FileBuffer 写入新的缓冲区
// 返回复制的大小,失败返回0
DWORD CopyImageBufferToFileBuffer(LPVOID pImageBuffer, LPVOID *pNewBuffer)
{
   
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
	PIMAGE_SECTION_HEADER pSectionHeader = \
		(PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	
	// 最后一个节表
	PIMAGE_SECTION_HEADER pLastSectionHeader = pSectionHeader + pPEHeader->NumberOfSections - 1;
	// 计算要复制的字节
	// 这一步有BUG,当最后一个节后面还有数据时(多见于控制台程序),丢失数据
	DWORD dwFileBufferSize = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
	*pNewBuffer = malloc(dwFileBufferSize);	
	if (*pNewBuffer == NULL)
	{
   
		printf("分配内存失败\n");
		return 0;
	}
	memset(*pNewBuffer, 0, dwFileBufferSize);
	// 复制DOS头+PE头+可选PE头+节表+文件对齐
	memcpy(*pNewBuffer, pImageBuffer, pOptionHeader->SizeOfHeaders);
	// 遍历节表,复制文件对齐后的节	
	for (int i = 0; i < pPEHeader->NumberOfSections; i++)
	{
   
		memcpy((LPVOID)((DWORD)(*pNewBuffer) + pSectionHeader[i].PointerToRawData), \
			(LPVOID)((DWORD)pImageBuffer + pSectionHeader[i].VirtualAddress), \
			pSectionHeader[i].SizeOfRawData);
	}
	return dwFileBufferSize;
}

// 内存数据写入文件
BOOL MemoryToFile(LPVOID pMemBuffer, DWORD dwSize, LPCSTR lpszFile)
{
   
	FILE *fp = NULL;
	fp = fopen(lpszFile, "wb+");
	if (fp == NULL)
	{
   
		printf("打开文件失败\n");
		return FALSE;
	}
	DWORD dwWritten = fwrite(pMemBuffer, 1, dwSize, fp);
	if (dwWritten != dwSize)
	{
   
		printf("写入了 %d 字节,不等于 %d\n", dwWritten, dwSize);
		fclose(fp);
		return FALSE;
	}
	fclose(fp);
	return TRUE;
}

// 向代码节添加MessageBox代码
// 向代码节添加代码不需要担心内存对齐后大小发生变化
// 默认第一个节是代码节,但是这样判断不一定准确,应该遍历节表,根据属性找代码节
BOOL AddCodeToCodeSec(LPCSTR lpszFile, LPCSTR lpszOutFile)
{
   
	BYTE shellcode[] =
	{
   
		0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, // push 0 push 0 push 0 push 0
		0xE8, 0x00, 0x00, 0x00, 0x00,					// call MessageBoxA
		0xE9, 0x00, 0x00, 0x00, 0x00					// jmp OEP
	};
	DWORD dwShellCodeSize = 18;
	DWORD dwCodeRva = 0; // 插入的位置RVA
	LPVOID pFileBuffer = NULL;
	LPVOID pImageBuffer = NULL;
	LPVOID pNewBuffer = NULL;
	
	DWORD dwFileBufferSize = 0;
	DWORD dwImageBufferSize = 0;
	DWORD dwNewBufferSize = 0;
	// 读取PE到内存中
	if ((dwFileBufferSize = ReadPEFile(lpszFile, &pFileBuffer)) == 0)
	{
   
		printf("读取失败\n");
		return FALSE;
	}
// 拉伸成内存映像
dwImageBufferSize = CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
if (0 == dwImageBufferSize)
{
   
	free(pFileBuffer);
	return FALSE;
}
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4
  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值