您的位置:首页 > 其它

获取PE文件信息的封装

2010-12-21 17:04 323 查看
工作之余,闲来无事,研究了一下PE文件的格式;虽然PE这方面的工具多如牛毛,用起来也非常直观,但是为了自己加深巩固理解,倒不如自己写一个小东东来一探PE究竟。代码如下【具体操纵可以参考注释】:

首先是PEFile.h

//--------------------------------------------------------------------
// Name:        PEFile.h
// Purpose:     封装了列举PE文件信息的操作。
// Author:      陈相礼
// Compiler:	VC8
// Modified by:
// Created:     11/06/09
// Licence:  
 
#pragma once
 
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <ImageHlp.h>
#pragma comment( lib, "ImageHlp" )
 
typedef struct _struMAP_FILE_STRUCT 
{
	HANDLE hFile;
	HANDLE hMapping;
	LPVOID lpImageBase;
}MAP_FILE_STRUCT, *PMAP_FILE_STRUCT;
 
class CPEFile
{
public:
	// 构造
	CPEFile() {};
	// 析构
	~CPEFile() {};
 
	bool LoadPEFile( char *szFilename );		// 载入PE的
	void PrintPEHeader();						// 打印PE头部
	void PrintOptionalHeader();					// 打印可选头部
	void PrintSectionInfo();					// 打印区块信息
	void PrintET();								// 打印导出表
	void PrintIAT();							// 打印导入表
	void UnLoadFile();							// 释放文件
 
protected:
	static void				CharToWCHAR( WCHAR* wchar, char* szSource );// 字符串转化
	bool					IsPEFile( LPVOID );// 检测是否为PE文件
	PIMAGE_FILE_HEADER		GetFileHeader( LPVOID ImageBase );// 取得PE头部
	PIMAGE_NT_HEADERS		GetNtHeaders( LPVOID ImageBase );// 取得NT头部
	PIMAGE_OPTIONAL_HEADER	GetOptionalHeader( LPVOID ImageBase );// 取得可选头部
	PIMAGE_SECTION_HEADER	GetFirstSectionHeader( LPVOID ImageBase );// 取得第一个节信息
	LPVOID					GetDirectoryEntryToData( LPVOID ImageBase, USHORT DirectoryEntry );// 转化
	LPVOID					RvaToPtr( PIMAGE_NT_HEADERS pNtH, LPVOID ImageBase, DWORD dwRVA );// 转化
 
private:
	MAP_FILE_STRUCT mMapFile;
};


然后是PEFile.cpp

//--------------------------------------------------------------------
// Name:        PEFile.cpp
// Purpose:     实现文件。
// Author:      陈相礼
// Compiler:	VC8
// Modified by:
// Created:     11/06/09
// Licence:  
 
#include "PEFile.h"
 
//--------------------------------------------------------------------
// Function:	载入PE文件
// Param:		<in>	文件路径名
//				<out>
// Return:		成功:true; 失败:false
bool CPEFile::LoadPEFile( char *szFilename )
{
	HANDLE hFile;
	HANDLE hMapping;
	LPVOID lpImageBase;
	LPTSTR  lpFilename;
 
	lpFilename = new WCHAR[MAX_PATH];
	CharToWCHAR( lpFilename, szFilename );
 
	hFile = CreateFile(		// 打开载入文件
		lpFilename,
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		0);
 
	if ( !hFile )
	{
		return false;
	}
 
	hMapping = CreateFileMapping(
		hFile,
		NULL,
		PAGE_READONLY,
		0,
		0,
		NULL);
	if ( !hMapping )
	{
		CloseHandle( hFile );
		return false;
	}
 
	lpImageBase = MapViewOfFile( 
		hMapping,
		FILE_MAP_READ,
		0,
		0,
		0);
	if ( !lpImageBase )
	{
		CloseHandle( hFile );
		CloseHandle( hMapping );
		return false;
	}
	
	if ( !IsPEFile( lpImageBase ) )
	{
		printf_s( "PE文件信息获取失败。请确保是PE文件,且文件未被使用!/n" );
		return false;
	}
 
	mMapFile.hFile = hFile;
	mMapFile.hMapping = hMapping;
	mMapFile.lpImageBase = lpImageBase;	
 
	delete []lpFilename;
 
	return true;
}
 
//--------------------------------------------------------------------
// Function:	输出PE文件头部信息
// Param:		<in>
//				<out>
// Return:		void
void CPEFile::PrintPEHeader()
{
	PIMAGE_FILE_HEADER pFileHeader = GetFileHeader( mMapFile.lpImageBase );
 
	tm createTime;
	printf_s("----------------------------PE头部信息----------------------------/n");
	switch ( pFileHeader->Machine )
	{
	case 0x14C:
		printf_s("可执行文件的目标CPU是:Intel i386/n");
		break;
	case 0x162:
		printf_s("可执行文件的目标CPU是:MIP R3000/n");
		break;
	case 0x166:
		printf_s("可执行文件的目标CPU是:MIP R4000/n");
		break;
	case 0x184:
		printf_s("可执行文件的目标CPU是:Alpha AXP/n");
		break;
	case 0x1F0:
		printf_s("可执行文件的目标CPU是:Power PC/n");
		break;
	default: printf_s("可执行文件的目标CPU未知!/n");
	}
 
	printf_s("文件的区块数目:%d/n", pFileHeader->NumberOfSections);
	gmtime_s( &createTime, (time_t *)&pFileHeader->TimeDateStamp );
	WCHAR	wBuf[64];
	char	cBuf[64];
	asctime_s(cBuf, 64, &createTime);
	CharToWCHAR( wBuf, cBuf );
	printf_s( "文件的创建时间GMT是:%ws/n", wBuf );
 
	printf_s("IAMGE_OPTIONAL_HEADER32结构大小:%d/n", pFileHeader->SizeOfOptionalHeader);
	
	if ( pFileHeader->Characteristics == 0x1000 )
	{
		printf_s("该文件为系统文件!/n");
	}
 
	if ( pFileHeader->Characteristics == 0x2000 )
	{
		printf_s("该文件为DLL文件!/n");
	}
}
 
//--------------------------------------------------------------------
// Function:	打印可选头部
// Param:		<in> 
//				<out>
// Return:		void
void CPEFile::PrintOptionalHeader()
{
	PIMAGE_OPTIONAL_HEADER	pOH = GetOptionalHeader( mMapFile.lpImageBase );
 
	printf_s("----------------------------可选头部信息----------------------------/n");
	printf_s("/n连接器的主版本号:%d,次版本号:%d/n",pOH->MajorLinkerVersion,pOH->MinorLinkerVersion);
	printf_s("所有含有代码区块的总大小:%ld/n",pOH->SizeOfCode);
	printf_s("所有初始化数据区块的总大小:%ld/n",pOH->SizeOfInitializedData);
	printf_s("所有未初始化数据区块的总大小:%ld/n",pOH->SizeOfUninitializedData);
	printf_s("程序执行入口R***(AddressOfEntryPoint):%X/n",pOH->AddressOfEntryPoint);
	printf_s("代码区块起始RVA(BaseOfCode):%X/n",pOH->BaseOfCode);
	printf_s("数据区块起始RVA(BaseOfData):%X/n",pOH->BaseOfData);
	printf_s("数据默认装入基地址(ImageBase):%X/n",pOH->ImageBase);
	printf_s("操作系统主版本号:%d/n",pOH->MajorOperatingSystemVersion);
	printf_s("操作系统次版本号:%d/n",pOH->MinorOperatingSystemVersion);
	printf_s("所需要的的子系统主版本号:%d/n",pOH->MajorSubsystemVersion);
	printf_s("所需要的的子系统次版本号:%d/n",pOH->MinorSubsystemVersion);
	printf_s("映像装入内存后的总尺寸(SizeOfIamge):%d/n",pOH->SizeOfImage);
	printf_s("DOS头,PE头,区块表总大小:%d/n",pOH->SizeOfHeaders);
	printf_s("映像效验和:%ld/n",pOH->CheckSum);
	printf_s("文件子系统:%d/n",pOH->Subsystem);
	printf_s("数据目录表的项数:%d/n",pOH->NumberOfRvaAndSizes);
}
 
//--------------------------------------------------------------------
// Function:	打印PE区块信息
// Param:		<in> 
//				<out>
// Return:		void
void CPEFile::PrintSectionInfo()
{
	PIMAGE_FILE_HEADER		pFH	=	GetFileHeader( mMapFile.lpImageBase );
	if ( !pFH )
	{
		return;
	}
	PIMAGE_SECTION_HEADER	pSH	=	GetFirstSectionHeader( mMapFile.lpImageBase );
	printf_s("----------------------------PE文件区块信息----------------------------/n");
	for ( int i = 0; i < pFH->NumberOfSections; ++i, ++pSH )
	{
		printf_s("段名:%s/t",(char *)pSH->Name);
		printf_s("VirtualSize:%x/t",pSH->Misc);
		printf_s("VirtualAddress:%x/t",pSH->VirtualAddress);
		printf_s("SizeOfRawData:%x/t",pSH->SizeOfRawData);
		printf_s("SizeOfRawData:%x/t",pSH->SizeOfRawData);
		printf_s("文件属性(Characteristics):%x/n",pSH->Characteristics);
	}
}
 
//--------------------------------------------------------------------
// Function:	打印导出表信息
// Param:		<in> 
//				<out>
// Return:		void
void CPEFile::PrintET()
{
	IMAGE_EXPORT_DIRECTORY	*pExport	=	(IMAGE_EXPORT_DIRECTORY *)GetDirectoryEntryToData( mMapFile.lpImageBase, IMAGE_DIRECTORY_ENTRY_EXPORT );
	printf_s("----------------------------PE导出表----------------------------/n");
	if ( !pExport )
	{
		printf_s("不存在输出模块!/n");
		return ;
	}
 
	printf_s("模块的真实名称:%s/n", (char *)::ImageRvaToVa( GetNtHeaders( mMapFile.lpImageBase ), mMapFile.lpImageBase, pExport->Name, NULL ));
	int num;
	num = pExport->NumberOfFunctions;
	printf_s("函数中函数模块的个数为:%d/n", num);
	DWORD	*AddressF	=	(DWORD *)::ImageRvaToVa( GetNtHeaders( mMapFile.lpImageBase ), mMapFile.lpImageBase, pExport->AddressOfFunctions, NULL );
	DWORD	*AddressName	=	(DWORD *)::ImageRvaToVa( GetNtHeaders( mMapFile.lpImageBase ), mMapFile.lpImageBase, pExport->AddressOfNames, NULL );
	DWORD	*AddressName0	=	(DWORD *)::ImageRvaToVa( GetNtHeaders( mMapFile.lpImageBase ), mMapFile.lpImageBase, pExport->AddressOfNameOrdinals, NULL );
 
	for ( int i = 0; i < num; ++i, ++AddressName, ++AddressF, ++AddressName0 )
	{
		printf_s("函数名称:%-30s,地址:%-4x,序列号:%d/n", (char *)ImageRvaToVa( GetNtHeaders( mMapFile.lpImageBase ),mMapFile.lpImageBase, *AddressName, NULL ), *AddressF, *AddressName0 );
	}
}
 
//--------------------------------------------------------------------
// Function:	打印导入表信息
// Param:		<in> 
//				<out>
// Return:		void
void CPEFile::PrintIAT()
{
	PIMAGE_IMPORT_DESCRIPTOR	pImport = (IMAGE_IMPORT_DESCRIPTOR *)GetDirectoryEntryToData( mMapFile.lpImageBase, IMAGE_DIRECTORY_ENTRY_IMPORT );
 
	printf_s("----------------------------PE导入表----------------------------/n");
	if ( !pImport )
	{
		printf_s("不存在输入模块!/n");
		return;
	}
 
	while ( pImport->FirstThunk )
	{
		char *pszDllName = (char *)RvaToPtr( GetNtHeaders(mMapFile.lpImageBase), mMapFile.lpImageBase, pImport->Name );
		printf_s( "/n输入模块:%s/n", pszDllName );
		IMAGE_THUNK_DATA	*pThunk =	(IMAGE_THUNK_DATA *)(::ImageRvaToVa( GetNtHeaders( mMapFile.lpImageBase ), mMapFile.lpImageBase,pImport->OriginalFirstThunk,NULL ) );
 
		int num = 0;
		if ( pThunk == NULL )
		{
			return;
		}
 
		while ( pThunk->u1.Function )
		{
			char *pszFunName = (char *)(::ImageRvaToVa((PIMAGE_NT_HEADERS)GetNtHeaders( mMapFile.lpImageBase ), mMapFile.lpImageBase, (unsigned long)pThunk->u1.AddressOfData, NULL ));
			PDWORD lpAddr	=	(DWORD*)(::ImageRvaToVa(GetNtHeaders(mMapFile.lpImageBase), mMapFile.lpImageBase, pImport->FirstThunk, NULL )) + num; 
			if ( pszFunName == NULL )
			{
				break;
			}
			printf_s("从此模块导入的函数:%-30s", pszFunName + 2);
			printf_s("函数地址:%x/n", lpAddr);
			num++;
			pThunk++;
		}
		pImport++;
	}
}
 
//--------------------------------------------------------------------
// Function:	释放文件
// Param:		<in> 
//				<out>
// Return:		void
void CPEFile::UnLoadFile()
{
	if ( mMapFile.lpImageBase )
	{
		UnmapViewOfFile( mMapFile.lpImageBase );
	}
 
	if ( mMapFile.hMapping )
	{
		CloseHandle( mMapFile.hMapping );
	}
 
	if ( mMapFile.hFile )
	{
		CloseHandle( mMapFile.hFile );
	}
}
 
//--------------------------------------------------------------------
// Function:	字符串转化为宽字符
// Param:		<in>	源字符串指针
//				<out>	转化后的宽字符指针
// Return:		void
void CPEFile::CharToWCHAR( WCHAR* wchar, char* szSource )
{
	int		nLen	=	strlen( szSource ) + 1;
	int		nwLen	=	MultiByteToWideChar( CP_ACP, 0, szSource, nLen, NULL, 0 );
	MultiByteToWideChar( CP_ACP, 0, szSource, nLen, wchar, nwLen );
}
 
//--------------------------------------------------------------------
// Function:	检测PE有效性
// Param:		<in>	文件内存镜像
//				<out>
// Return:		有效:true; 无效:false
bool CPEFile::IsPEFile( LPVOID ImageBase )
{
	PIMAGE_DOS_HEADER pDH	= NULL;
	PIMAGE_NT_HEADERS pNtH	= NULL;
 
	if ( !ImageBase )
	{
		return false;
	}
 
	// 检测DOS头
	pDH = (PIMAGE_DOS_HEADER)ImageBase;
	if ( pDH->e_magic != IMAGE_DOS_SIGNATURE )
	{
		return false;
	}
 
	// 检测PE头部
	pNtH = (PIMAGE_NT_HEADERS32)( (DWORD)pDH + pDH->e_lfanew );
	if ( pNtH->Signature != IMAGE_NT_SIGNATURE )
	{
		return false;
	}
 
	return true;
}
 
//--------------------------------------------------------------------
// Function:	获取PE头部
// Param:		<in>	文件内存镜像
//				<out>
// Return:		PE头部指针
PIMAGE_FILE_HEADER CPEFile::GetFileHeader( LPVOID ImageBase )
{
	PIMAGE_NT_HEADERS	pNtH	=	NULL;
	PIMAGE_FILE_HEADER	pFH		=	NULL;
	pNtH	=	GetNtHeaders( ImageBase );
	pFH		=	&pNtH->FileHeader;
	return pFH;
}
 
//--------------------------------------------------------------------
// Function:	获取NT头部
// Param:		<in>	文件内存镜像
//				<out>
// Return:		NT结构指针
PIMAGE_NT_HEADERS CPEFile::GetNtHeaders( LPVOID ImageBase )
{
	if ( !IsPEFile( ImageBase ) )
	{
		return NULL;
	}
 
	PIMAGE_DOS_HEADER	pDH		=	(PIMAGE_DOS_HEADER)ImageBase;
	PIMAGE_NT_HEADERS	pNtH	=	(PIMAGE_NT_HEADERS)( (DWORD)pDH + pDH->e_lfanew );
 
	return pNtH;
}
 
//--------------------------------------------------------------------
// Function:	获取可选头部
// Param:		<in>	文件镜像基址
//				<out>
// Return:		PE可选头指针
PIMAGE_OPTIONAL_HEADER CPEFile::GetOptionalHeader( LPVOID ImageBase )
{
	PIMAGE_OPTIONAL_HEADER pOH	=	&(GetNtHeaders( ImageBase ))->OptionalHeader;
	return pOH;
}
 
//--------------------------------------------------------------------
// Function:	获取第一个节信息
// Param:		<in>	文件镜像基址
//				<out>
// Return:		PE节头指针
PIMAGE_SECTION_HEADER CPEFile::GetFirstSectionHeader( LPVOID ImageBase )
{
	PIMAGE_NT_HEADERS		pNtH	=	GetNtHeaders( ImageBase );
	PIMAGE_SECTION_HEADER	pSH		=	IMAGE_FIRST_SECTION( pNtH );
 
	return pSH;
}
 
LPVOID CPEFile::GetDirectoryEntryToData( LPVOID ImageBase, USHORT DirectoryEntry )
{
	DWORD	dwDataStartRVA;
	LPVOID	pDirData	=	NULL;
	PIMAGE_NT_HEADERS	pNtH	=	NULL;
	PIMAGE_OPTIONAL_HEADER	pOH	=	NULL;
 
	pNtH	=	GetNtHeaders( ImageBase );
	if ( !pNtH )
	{
		return	NULL;
	}
 
	pOH	=	GetOptionalHeader( ImageBase );
	if ( !pOH )
	{
		return	NULL;
	}
 
	dwDataStartRVA	=	pOH->DataDirectory[DirectoryEntry].VirtualAddress;
	if ( !dwDataStartRVA )
	{
		return NULL;
	}
 
	pDirData	=	RvaToPtr( pNtH, ImageBase, dwDataStartRVA );
	if ( !pDirData )
	{
		return NULL;
	}
 
	return pDirData;
}
 
LPVOID CPEFile::RvaToPtr( PIMAGE_NT_HEADERS pNtH, LPVOID ImageBase, DWORD dwRVA )
{
	return ::ImageRvaToVa( pNtH, ImageBase, dwRVA, NULL );
}


最后是AppMain.cpp进行调用测试。

//--------------------------------------------------------------------
// Name:        AppMain.cpp
// Purpose:     测试主程序。
// Author:      陈相礼
// Compiler:	VC8
// Modified by:
// Created:     11/06/09
// Licence:  
 
#include "PEFile.h"
 
int main( int argc, char **argv )
{
	//char *filename = "C://Documents and Settings//Administrator//桌面//Stud_PE//Stud_PE.exe";
	char *filename = "C://Documents and Settings//Administrator//桌面//Stud_PE//PSAPI.DLL";
	CPEFile pefile;
	pefile.LoadPEFile(filename);
	pefile.PrintPEHeader();
	pefile.PrintOptionalHeader();
	pefile.PrintSectionInfo();
	pefile.PrintET();
	pefile.PrintIAT();
	pefile.UnLoadFile();
	system( "pause" );
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: