解析PE文件代码

功能类似PEID,图形界面暂时没做出来 暑假学学QT
读文件只能在主函数里写文件路径 , 是有点low… (流下了没技术的泪水)
头文件代码:

#pragma once
#include<Windows.h>
class CPe
{
private:
	PTCHAR ptcFilePath;								//PE文件路径
	IMAGE_DOS_HEADER pe_cDosHeader;					
	IMAGE_NT_HEADERS32 pe_cNtHeader;
	PIMAGE_SECTION_HEADER pe_pSectionHeader;
	PBYTE pe_lpImageBase;							//手动装载PE时文件首指针,这里写byte是因为文件操作一般以字节为单位
public:
	CPe();
	~CPe();
	void PrintPE();
	void LordPE(HANDLE , DWORD);             //二参是直到节表的总大小,因为硬盘内存一个样
	HANDLE Init(TCHAR[]);
	int GetImportTablePtr(OUT PIMAGE_DATA_DIRECTORY);
	int GetNtHeadr32Ptr(OUT PIMAGE_NT_HEADERS32);
	int GetImageBasePtr(OUT PBYTE);
	void PrintImport();
};

函数实现

#include "CPe.h"
#include <Windows.h>
#include<stdio.h>

CPe::CPe() 
{
	memset(this, 0, sizeof(CPe));
}
CPe::~CPe()
{
	if (pe_pSectionHeader)
		delete[] pe_pSectionHeader;
	pe_pSectionHeader = NULL;
	if (pe_lpImageBase)
		delete[] pe_lpImageBase;
	pe_lpImageBase = NULL;
}
int CPe::GetImportTablePtr(OUT PIMAGE_DATA_DIRECTORY p)
{
	p = this->pe_cNtHeader.OptionalHeader.DataDirectory + 1; 
	return 1;
}
int CPe::GetNtHeadr32Ptr(OUT PIMAGE_NT_HEADERS32 p)
{
	p = &(this->pe_cNtHeader);
	return 1;
}
int CPe::GetImageBasePtr(OUT PBYTE p)
{
	p = this->pe_lpImageBase;
	return 1;
}
HANDLE CPe::Init(TCHAR tcFilePath[])
{
	bool blFlag = false;
	ptcFilePath = tcFilePath;
	DWORD dwTempNum = 0;
	HANDLE hPeFile = CreateFile(tcFilePath, GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
	if (INVALID_HANDLE_VALUE == hPeFile)
		return 0;

	ReadFile(hPeFile, &pe_cDosHeader, sizeof(IMAGE_DOS_HEADER), &dwTempNum, NULL);
	if (sizeof(IMAGE_DOS_HEADER) != dwTempNum)
		return NULL;

	if (0x5a4d != pe_cDosHeader.e_magic)
		return NULL;                           //此文件不是一个有效的PE文件,或者PE文件魔数遭到修改

	SetFilePointer(hPeFile, pe_cDosHeader.e_lfanew, NULL, FILE_BEGIN);
	ReadFile(hPeFile, &pe_cNtHeader, sizeof(IMAGE_NT_HEADERS32), &dwTempNum, NULL);
	if (sizeof(IMAGE_NT_HEADERS32) != dwTempNum)
		return NULL;
	if (0x4550 != pe_cNtHeader.Signature)
		return NULL;                           //PE指纹不存在

	pe_pSectionHeader = new IMAGE_SECTION_HEADER[pe_cNtHeader.FileHeader.NumberOfSections];
	memset(pe_pSectionHeader, 0, sizeof(IMAGE_SECTION_HEADER) * pe_cNtHeader.FileHeader.NumberOfSections);
	ReadFile(hPeFile, pe_pSectionHeader, sizeof(IMAGE_SECTION_HEADER) * pe_cNtHeader.FileHeader.NumberOfSections, &dwTempNum, NULL);
	if (dwTempNum != sizeof(IMAGE_SECTION_HEADER) * pe_cNtHeader.FileHeader.NumberOfSections)
		return NULL;

	return hPeFile;
}

void CPe::PrintImport()
{
	PIMAGE_IMPORT_DESCRIPTOR pImportor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->pe_lpImageBase + this->pe_cNtHeader.OptionalHeader.DataDirectory[1].VirtualAddress);
	while (pImportor->Characteristics)
	{
		DWORD dwThunkRVA = pImportor->OriginalFirstThunk == NULL ? pImportor->FirstThunk : pImportor->OriginalFirstThunk;
		PIMAGE_THUNK_DATA32 pThunk = reinterpret_cast<PIMAGE_THUNK_DATA32>(this->pe_lpImageBase + dwThunkRVA);
		while (pThunk->u1.AddressOfData)
		{
			if (pThunk->u1.AddressOfData & 0x80000000)
			{
				printf("%s	-------->	%x\n", this->pe_lpImageBase + pImportor->Name, pThunk->u1.AddressOfData & 0x7fffffff);
			}
			else
			{
				printf("%s	-------->	%s\n", this->pe_lpImageBase + pImportor->Name,this->pe_lpImageBase+pThunk->u1.AddressOfData+2); // +2因为最后又指向了_IMAGE_IMPORT_BY_NAME
			}
			pThunk++;
		}
		pImportor++;
	}
}

void CPe::LordPE(HANDLE hFile, DWORD dwSize)
{
	DWORD dwTempNum = 0;
	SetFilePointer(hFile, NULL, NULL, FILE_BEGIN);
	pe_lpImageBase = new byte[this->pe_cNtHeader.OptionalHeader.SizeOfImage];
	if (!pe_lpImageBase)
		return;

	memset(pe_lpImageBase, 0, this->pe_cNtHeader.OptionalHeader.SizeOfImage);
	ReadFile(hFile, pe_lpImageBase, dwSize, &dwTempNum, NULL);
	if (dwSize != dwTempNum)
		return;
	for (int i = 0; i < this->pe_cNtHeader.FileHeader.NumberOfSections; i++)
	{
		SetFilePointer(hFile, this->pe_pSectionHeader[i].PointerToRawData, NULL, FILE_BEGIN);//
		ReadFile(hFile, pe_lpImageBase + this->pe_pSectionHeader[i].VirtualAddress, this->pe_pSectionHeader[i].SizeOfRawData, &dwTempNum, NULL);
	}
	//至此 手动装载PE已经完成   装载PE的目的是更方便的找数据目录项

}

void CPe::PrintPE()
{
	TCHAR tcDivide[60] = "********************************************************";
	printf("主要信息\n%s\n", tcDivide);//
	printf("文件路径:%s\n", this->ptcFilePath);//
	printf("入口点:%08x\n", this->pe_cNtHeader.OptionalHeader.AddressOfEntryPoint);//
	//printf("文件偏移:%08x\n",p.pe_cNtHeader.OptionalHeader.);   //看不懂这个参数
	printf("链接器版本:%02d.%02d\n", this->pe_cNtHeader.OptionalHeader.MajorLinkerVersion, this->pe_cNtHeader.OptionalHeader.MinorLinkerVersion);//
	//printf("文件大小:%08x\n",);
	//printf("首字节:%2x,%2x,%2x,%2x\n",);   //本程序没有读入文件,只读了头,so  阉割此功能
	if (3 == this->pe_cNtHeader.OptionalHeader.Subsystem)
		printf("子系统:Win32 Console\n");
	else
		printf("子系统:%08x\n", this->pe_cNtHeader.OptionalHeader.Subsystem);//映射懒得写了。
	printf("%s\n\n\n", tcDivide);//

	printf("基本信息\n%s\n", tcDivide);
	printf("入口点:%08x\t子系统:%08x\n", this->pe_cNtHeader.OptionalHeader.AddressOfEntryPoint, this->pe_cNtHeader.OptionalHeader.Subsystem);//
	printf("映像基址:%08x\t区段数量%08x\n", this->pe_cNtHeader.OptionalHeader.ImageBase, this->pe_cNtHeader.FileHeader.NumberOfSections);//
	printf("映像大小:%08x\t时间戳:%08x\n", this->pe_cNtHeader.OptionalHeader.SizeOfImage, this->pe_cNtHeader.FileHeader.TimeDateStamp);//

	printf("代码基址:%08x\t头部大小:%08x\n", this->pe_cNtHeader.OptionalHeader.BaseOfCode, this->pe_cNtHeader.OptionalHeader.SizeOfHeaders);//
	printf("数据基址:%08x\t特性:%08x\n", this->pe_cNtHeader.OptionalHeader.BaseOfData, this->pe_cNtHeader.FileHeader.Characteristics);//
	printf("区段对齐:%08x\t校检和:%08x\n", this->pe_cNtHeader.OptionalHeader.SectionAlignment, this->pe_cNtHeader.OptionalHeader.CheckSum);//
	printf("文件对齐:%08x\t可选头部大小:%08x\n", this->pe_cNtHeader.OptionalHeader.FileAlignment, this->pe_cNtHeader.FileHeader.SizeOfOptionalHeader);//
	printf("幻数:%08x\t数据目录项的个数:%08x\n", this->pe_cNtHeader.OptionalHeader.Magic, this->pe_cNtHeader.OptionalHeader.NumberOfRvaAndSizes);//
	printf("%s\n\n\n", tcDivide);

	printf("目录信息\n%s\n", tcDivide);
	printf("导出表的RVA及大小:%08x		%08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[0].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[0].Size);
	printf("导入表的RVA及大小:%08x		%08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[1].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[1].Size);
	printf("资源的RVA及大小:%08x		%08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[2].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[2].Size);
	printf("TLS表的RVA及大小:%08x		%08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[9].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[9].Size);
	printf("调试的RVA及大小:%08x		%08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[6].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[6].Size);
	printf("%s\n\n\n", tcDivide);

}

主函数实现:

#include<stdio.h>
#include<Windows.h>
#include"CPe.h"
int main(void)
{
	TCHAR tcPath[MAX_PATH] = "D:\\test\\exper.exe";
	CPe cPeData;
	HANDLE hFile = cPeData.Init(tcPath);              //文件指针此时已经指向节表末尾
	cPeData.LordPE(hFile,SetFilePointer(hFile,NULL,NULL,FILE_CURRENT));
	cPeData.PrintPE();
	cPeData.PrintImport();
	getchar();

	
}
发布了25 篇原创文章 · 获赞 13 · 访问量 2982

猜你喜欢

转载自blog.csdn.net/qq_43445167/article/details/94553862