PE文件格式(Portable Executable File Format )是windows下的可执行文件的格式, 从某种意义上讲,它反映了windows操作系统的工作方式, 对于它的了解, 可以帮助我们更加了解windows操作系统,对于windows下的编程,好处也是大大的。
在 本文中, 我并不打算大讲特讲PE文件的构成是什么,每个字段是什么意思, 这些资料可以说在网上是浩瀚如海,到处都是的, 用google一搜, 打开一看, 基本讲解的都是大同小异。 由于pe文件的结构比较庞大, 结构中套结构, 有的结构多达30多个字段, 光看这些字段都让人够晕的, 在加上有的字段是一个32位的DWORD值, 而每一位都有其特殊的含义,这样, 光把每个字段的含义看一遍过来, 估计也得2个小时。 而实际上, 这里面很多字段, 我们都不需要去了解, 也不需要去关注, 掌握那些关键字段就行了。
我觉得讲清楚一种技术, 最好的方法是例子, 通过例子, 先从感性上去感受一下,然后有了这种感性的认识,然后再深入理论, 这才是比较好的办法。所以, 我这里给大家提供一个例子, 这个例子是用VC6写的, 是一个C语言的控制台程序, 它要求提供一个PE文件名或者路径的参数, 然后分析这个文件的结构, 并且把关键字段打印出来。你可以一边看网上的关于PE文件结构的讲解, 一边对照本程序, 我相信, 通过理论和实践的结合, 你能很快的掌握PE文件的主要构成。 好了, 废话少说, 源码奉上:
// ShowPE.c
// Show The Main Structures Of the PE file
// Author: thinker
// Date: 11/28/2008
// E-Mail: cnhnyu@gmail.com
// QQ: 94483026
/*********************************************************
PE File Format
------------------------------- <--+
| MZ MS-DOS Header | |
------------------------------- | Dos Headers
| MS DOS Stub | |
------------------------------- <--+
| PE00 | |
------------------------------- |
| | |
| IMAGE_FILE_HEADER | | IMAGE_NT_HEADERS32
------------------------------- |
| | |
| IMAGE_OPTIONAL_HEADER32 | |
| | |
------------------------------- <--+
| Section Header 1 | |
|-----------------------------| |
| Section Header 2 | |
------------------------------- | Section Headers
| .............. | |
|-----------------------------| |
| Section Header N | |
------------------------------- <--+
| Section Data 1 | |
|-----------------------------| |
| Section Data 2 | |
------------------------------- | Section Datas
| ............... | |
------------------------------- |
| Section Data N | |
------------------------------- <--+
**********************************************************/
# include < stdio. h>
# include < windows. h>
# include < time . h>
// Data Directory Description
char szDataDirectory[ 16] [ 64] = {
"Export Directory" ,
"Import Directory" ,
"Resource Directory" ,
"Exception Directory" ,
"Security Directory" ,
"Base Relocation Table" ,
"Debug Directory" ,
"Architecture Specific Data" ,
"RVA of GP" ,
"TLS Directory" ,
"Load Configuration Directory" ,
"Bound Import Directory in headers" ,
"Import Address Table" ,
"Delay Load Import Descriptors" ,
"COM Runtime descriptor"
} ;
HANDLE hFile = NULL ;
HANDLE hFileMapping = NULL ;
void * pFileBase = NULL ;
IMAGE_DOS_HEADER * pDosHeader = NULL ;
IMAGE_NT_HEADERS * pNTHeader = NULL ;
IMAGE_SECTION_HEADER * pSectionHeader = NULL ;
DWORD RVA2FileOffset( DWORD dwRVA) ;
int main( int argc, char * * argv)
{
struct tm * ptm;
DWORD dwIndex;
IMAGE_IMPORT_DESCRIPTOR * pImportDescriptor = NULL ;
IMAGE_THUNK_DATA * pThunkData = NULL ;
IMAGE_IMPORT_BY_NAME * pImportByName = NULL ;
IMAGE_EXPORT_DIRECTORY * pExportDirectory = NULL ;
DWORD * pdw;
WORD * pw;
if ( argc ! = 2 )
{
printf ( "Usage:/n/t%s PEFile/n" , argv[ 0] ) ;
return - 1;
}
/*********************** Map the file to memory *************************/
hFile = CreateFile( argv[ 1] , GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL , OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL ) ;
if ( hFile = = INVALID_HANDLE_VALUE )
{
printf ( "Open File Error./n" ) ;
return - 1;
}
hFileMapping = CreateFileMapping( hFile, NULL , PAGE_READONLY, 0, 0, NULL ) ;
if ( ! hFileMapping )
{
CloseHandle( hFile) ;
printf ( "Create File Mapping Error./n" ) ;
return - 1;
}
pFileBase = MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0) ;
if ( ! pFileBase )
{
CloseHandle( hFileMapping) ;
CloseHandle( hFile) ;
printf ( "Map View Of File Error./n" ) ;
return - 1;
}
/*********************** Map end *****************************************/
// get the dos heaader pointer
pDosHeader = ( IMAGE_DOS_HEADER* ) pFileBase;
if ( pDosHeader- > e_magic ! = IMAGE_DOS_SIGNATURE )
{
printf ( "Unknow File Format./n" ) ;
goto End;
}
printf ( "%-35s%s/n/n" , "FileName:" , argv[ 1] ) ;
printf ( "%-35s%#010x/n" , "Dos Stub Size:" , pDosHeader- > e_lfanew - sizeof ( IMAGE_DOS_HEADER) ) ;
printf ( "%-35s%#010x/n" , "NT File RVA:" , pDosHeader- > e_lfanew) ;
// get the nt header pointer
pNTHeader = ( IMAGE_NT_HEADERS* ) ( ( char * ) pFileBase + pDosHeader- > e_lfanew) ;
if ( pNTHeader- > Signature ! = IMAGE_NT_SIGNATURE )
{
printf ( "Not NT File./n" ) ;
goto End;
}
// get the section header pointer
pSectionHeader = ( IMAGE_SECTION_HEADER* ) ( ( char * ) pNTHeader + sizeof ( IMAGE_NT_HEADERS) ) ;
printf ( "/n%-35s%s/n" , "nRun Platform:" , ( pNTHeader- > FileHeader. Machine = = IMAGE_FILE_MACHINE_I386) ? "Intel 386" : "Other" ) ;
printf ( "%-35s%d/n" , "NumOfSections:" , pNTHeader- > FileHeader. NumberOfSections) ;
ptm = localtime ( & pNTHeader- > FileHeader. TimeDateStamp) ;
printf ( "%-35s%02d/%02d/%04d %02d:%02d:%02d/n" , "FileCreateTime:" , ptm- > tm_mon + 1, ptm- > tm_mday, ptm- > tm_year + 1900,
ptm- > tm_hour, ptm- > tm_min, ptm- > tm_sec) ;
//printf("%.19s/n", asctime(ptm));
printf ( "%-35s%#010x/n" , "SizeofOptionHdr:" , pNTHeader- > FileHeader. SizeOfOptionalHeader) ;
printf ( "%-35s%s/n" , "File Type:" , ( pNTHeader- > FileHeader. Characteristics & IMAGE_FILE_DLL) ? "DLL" : "EXE" ) ;
printf ( "/n%-35s%s/n" , "Image Type:" , ( pNTHeader- > OptionalHeader. Magic = = 0x10B) ? "Exe Image" : "Other" ) ;
printf ( "%-35s%d.%d/n" , "Linker Version:" , pNTHeader- > OptionalHeader. MajorLinkerVersion, pNTHeader- > OptionalHeader. MinorLinkerVersion) ;
printf ( "%-35s%#010x/n" , "SizeofCode:" , pNTHeader- > OptionalHeader. SizeOfCode) ;
printf ( "%-35s%#010x/n" , "AddressOfEntryPoint:" , pNTHeader- > OptionalHeader. AddressOfEntryPoint) ;
printf ( "%-35s%#010x/n" , "DefaultLoadAddress:" , pNTHeader- > OptionalHeader. ImageBase) ;
printf ( "%-35s%#010x/n" , "SectionAlignment:" , pNTHeader- > OptionalHeader. SectionAlignment) ;
printf ( "%-35s%#010x/n" , "FileAlignment:" , pNTHeader- > OptionalHeader. FileAlignment) ;
printf ( "%-35s%d.%d/n" , "OS SystemVersion:" , pNTHeader- > OptionalHeader. MajorOperatingSystemVersion,
pNTHeader- > OptionalHeader. MinorOperatingSystemVersion) ;
printf ( "%-35s%d.%d/n" , "ImageVersion:" , pNTHeader- > OptionalHeader. MajorImageVersion,
pNTHeader- > OptionalHeader. MinorImageVersion) ;
printf ( "%-35s%d.%d/n" , "SubSystemVersion:" , pNTHeader- > OptionalHeader. MajorSubsystemVersion,
pNTHeader- > OptionalHeader. MinorSubsystemVersion) ;
printf ( "%-35s%#010d/n" , "SizeOfIamge:" , pNTHeader- > OptionalHeader. SizeOfImage) ;
printf ( "%-35s%#010d/n" , "SizeOfHeaders:" , pNTHeader- > OptionalHeader. SizeOfHeaders) ;
if ( pNTHeader- > OptionalHeader. Subsystem = = IMAGE_SUBSYSTEM_WINDOWS_GUI )
printf ( "%-35s%s/n" , "GUI System:" , "Windows GUI" ) ;
else if ( pNTHeader- > OptionalHeader. Subsystem = = IMAGE_SUBSYSTEM_WINDOWS_CUI)
printf ( "%-35s%s/n" , "GUI System:" , "Windows Console" ) ;
else
printf ( "%-35s%s/n" , "GUI System:" , "Other" ) ;
printf ( "/n-----------------------------Data Directory----------------------------------/n" ) ;
printf ( "#Index/t#Virtual Address/t#Size/t/t#%-32s/n" , "Directory Name" ) ;
for ( dwIndex = 0; dwIndex < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; dwIndex+ + )
{
printf ( "0x%02x/t0x%08x/t0x%08x/t%-50s/n" , dwIndex,
pNTHeader- > OptionalHeader. DataDirectory[ dwIndex] . VirtualAddress,
pNTHeader- > OptionalHeader. DataDirectory[ dwIndex] . Size, szDataDirectory[ dwIndex] ) ;
}
printf ( "/n/n-----------------------------Section Headers----------------------------------/n" ) ;
printf ( "#VirtualAddress/t#VirtualSize/t#PointerToRawData/t#SizeOfRawData/t#Name/n" ) ;
for ( dwIndex = 0; dwIndex < pNTHeader- > FileHeader. NumberOfSections; dwIndex+ + )
{
printf ( "0x%08x/t0x%08x/t0x%08x/t/t0x%08x/t%-10s/n" , pSectionHeader[ dwIndex] . VirtualAddress,
pSectionHeader[ dwIndex] . Misc. VirtualSize, pSectionHeader[ dwIndex] . PointerToRawData,
pSectionHeader[ dwIndex] . SizeOfRawData, pSectionHeader[ dwIndex] . Name) ;
}
// Import Table
printf ( "/n/n-------------------------Import Table-------------------------------------/n" ) ;
pImportDescriptor = ( IMAGE_IMPORT_DESCRIPTOR* ) ( ( char * ) pFileBase + RVA2FileOffset( pNTHeader- > OptionalHeader. DataDirectory[ 1] . VirtualAddress) ) ;
for ( ; * ( char * ) pImportDescriptor ; pImportDescriptor+ + )
{
printf ( "Import Lib: %s/n" , ( char * ) ( RVA2FileOffset( pImportDescriptor- > Name) + ( char * ) pFileBase) ) ;
pThunkData = ( IMAGE_THUNK_DATA* ) ( RVA2FileOffset( pImportDescriptor- > OriginalFirstThunk) + ( char * ) pFileBase) ;
for ( ; pThunkData- > u1. AddressOfData; pThunkData+ + )
{
if ( pThunkData- > u1. Ordinal & IMAGE_ORDINAL_FLAG32 ) // import by index
{
printf ( "/t0x%04x/n" , pThunkData- > u1. Ordinal & 0xffff) ;
}
else // import by name
{
pImportByName = ( IMAGE_IMPORT_BY_NAME* ) ( RVA2FileOffset( pThunkData- > u1. Ordinal) + ( char * ) pFileBase) ;
printf ( "/t0x%04x/t%s/n" , pImportByName- > Hint, pImportByName- > Name) ;
}
}
printf ( "/n" ) ;
}
if ( pNTHeader- > OptionalHeader. DataDirectory[ 0] . Size = = 0 ) // Export Table Not Exist
goto End;
// Export Table
printf ( "/n/n------------------------Export Table---------------------------------/n" ) ;
pExportDirectory = ( IMAGE_EXPORT_DIRECTORY* ) ( RVA2FileOffset( pNTHeader- > OptionalHeader. DataDirectory[ 0] . VirtualAddress) + ( char * ) pFileBase) ;
printf ( "Export Lib: /t%s/n" , ( char * ) ( RVA2FileOffset( pExportDirectory- > Name) + ( char * ) pFileBase) ) ;
printf ( "/tIndex/tName/t/t/n" ) ;
printf ( "/t------------------------------/n" ) ;
for ( dwIndex = 0; dwIndex < pExportDirectory- > NumberOfNames; dwIndex+ + )
{
pdw = ( DWORD* ) ( RVA2FileOffset( pExportDirectory- > AddressOfNames) + ( char * ) pFileBase) ;
pw = ( WORD* ) ( RVA2FileOffset( pExportDirectory- > AddressOfFunctions) + ( char * ) pFileBase) ;
printf ( "/t0x%04x/t%-20s/n" , dwIndex, ( char * ) ( RVA2FileOffset( pdw[ dwIndex] ) + ( char * ) pFileBase) , pw[ dwIndex] ) ;
}
End:
UnmapViewOfFile( pFileBase) ;
CloseHandle( hFileMapping) ;
CloseHandle( hFile) ;
return 0;
}
/*
Convert RVA To File Offset
*/
DWORD RVA2FileOffset( DWORD dwRVA)
{
DWORD dwNum, dwIndex;
if ( pNTHeader = = NULL )
return 0;
if ( pSectionHeader = = NULL )
return 0;
dwNum = pNTHeader- > FileHeader. NumberOfSections;
for ( dwIndex = 0; dwIndex < dwNum; dwIndex+ + )
{
if ( dwRVA > = pSectionHeader[ dwIndex] . VirtualAddress & &
dwRVA < = pSectionHeader[ dwIndex] . VirtualAddress + pSectionHeader[ dwIndex] . SizeOfRawData)
{
return dwRVA - pSectionHeader[ dwIndex] . VirtualAddress + pSectionHeader[ dwIndex] . PointerToRawData;
}
}
return 0;
}
<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>