获取PE文件信息的封装
2010-12-21 17:04
323 查看
工作之余,闲来无事,研究了一下PE文件的格式;虽然PE这方面的工具多如牛毛,用起来也非常直观,但是为了自己加深巩固理解,倒不如自己写一个小东东来一探PE究竟。代码如下【具体操纵可以参考注释】:
首先是PEFile.h
然后是PEFile.cpp
最后是AppMain.cpp进行调用测试。
首先是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; }
相关文章推荐
- 获取PE文件信息的封装
- 【原创】编程获取PE文件信息的方法(转)
- PE文件信息获取工具-PEINFO
- 壳的编写(4)-- 获取被加壳文件的PE信息
- 自己写的一个PE文件FileVersionInfo类,可以轻松获取PE文件版本信息
- iOS - 音乐播放器需要获取音乐文件的一些数据信息(封装获取封面图片的类)
- pe文件解析:读取pe信息获取文件资源
- iOS - 获取音视频文件的Metadata信息
- 获取UWP配置文件中的版本信息
- 【Android】获取手机中已安装apk文件信息(PackageInfo、ResolveInfo)(应用图片、应用名、包名等) .
- 使用批处理+WMI获取指定文件或目录所在的物理磁盘信息
- FTP服务的LIST指令获取的文件列表信息的解析
- 获取创建的新用户的信息及配置文件及目录
- C# 获取文件大小,创建时间,文件信息,FileInfo类的属性表
- 获取文件的信息stat() lstat() fstat()
- GDAL获取影像信息与ENVI头文件信息
- android从未安装的apk文件里获取信息(包信息,资源信息)
- 在托管应用程序中使用 DirectShow 组件获取视频文件截图和 FourCC 信息
- 获取配置文件中configSections的配置信息http://www.linuxmine.com/38234.html
- php学习读取视频文件来获取视频属性的信息