本质上讲,各节中的内容才是执行一个程序真正需要的东西,所有头和目录这些东西只是为了帮助找到它们。节由两个主要部分组成:一个是节描述,也叫作节头;另一个是原始的节数据。
1.节头的结构
节头的C语言风格结构定义如下,Name字段是一个长度为8的字符数组,代表了节的名称,比较常见的节名为“.data”“.bss”和“.text”。代码如下:
typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
其中,比较重要的几个字段介绍如下。
·VirtualSize,内存中节所占的大小。
·VirtualAddress,内存中节的起始位置。
·SizeOfRawData,该程序文件节的大小,指的是保存在磁盘的物理文件中的大小。
·PointerToRawData,该程序文件节的起始位置,指的是保存在磁盘的物理文件中的起始位置。
·Characteristics,节的属性,4字节32位,标记32种属性。比较典型的几个位含义如下。 [1]
·位5 IMAGE_SCN_CNT_CODE,表示节中包含可执行代码。
·位7 IMAGE_SCN_CNT_UNINITIALIZED_DATA,表示节中包含未初始化数据,并需于执行开始前被初始化为全0,这通常是BSS节。
·位9 IMAGE_SCN_LNK_INFO,表示节中不包含映象数据,只有一些注释、描述等文档。
2.代码节
代码节主要包含执行代码,典型的节名有“.text”“.code”。
3.数据节
数据节包含的是已初始化的静态变量,典型的名称有“.data”“.idata”。
4.BSS节
BSS节包含的是未初始化的数据,典型的名称有“.bss”“bss”。
5.导出表
导出表常见于DLL文件,包含一些导出函数的入口点,导出表C语言风格结构定义如下:
typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; DWORD AddressOfNames; DWORD AddressOfNameOrdinals; } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
其中,比较重要的几个字段介绍如下:
·TimeDateStamp,文件生成的时间。
·Base,起始地址,也叫基址。
·Name,指向DLL名的相对虚拟地址RVA。
·NumberOfFunctions,AddressOfFunctions指向的数组的元素的个数。
·NumberOfNames,AddressOfNames指向的数组的元素的个数。
·AddressOfFunctions,函数地址数组ENT的RVA。
·AddressOfNames,函数名字数组EAT的RVA。
6.导入表
PE文件通常会使用来自于其他DLL的代码或数据,这些代码或数据就称为该PE的导入。当PE文件装入时,Windows加载器工作之一是定位所有被输入的函数和数据,并且让正在被装入的文件可以使用那些地址。这个过程是通过PE文件的导入表(Import Table)完成,导入表中保存的是函数名和其驻留DLL名等动态链接所需的信息(见图8-3),导入表C语言风格结构定义如下:
typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; } DUMMYUNIONNAME; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD ImportedDLLName; DWORD FirstThunk; } IMAGE_IMPORT_DESCRIPTOR; typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
其中,比较重要的几个字段介绍如下:
·OriginalFirstThunk,指向first thunk,IMAGE_THUNK_DATA,该thunk拥有Hint和Function name的地址。
·ImportedDLLName,表示导入的DLL名称,比如典型的kernel32.dll。
·FirstThunk,包含由IMAGE_THUNK_DATA定义的first thunk数组的虚地址,通过loader用函数虚地址初始化thunk。FirstThunk所指向的数组就称为输入地址表(Import Address Table,IAT)。
图8-3 PE导入表的结构以及主要字段 [2]
7.资源
PE文件运行以来的资源文件,比如对话框、菜单、图标等等。
[1] http://www.cppblog.com/oosky/archive/2006/11/24/15614.html
[2] http://www.dematte.org/2006/03/04/InterceptingWindowsAPIs.aspx