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 src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>