8.2 PE文件的节

本质上讲,各节中的内容才是执行一个程序真正需要的东西,所有头和目录这些东西只是为了帮助找到它们。节由两个主要部分组成:一个是节描述,也叫作节头;另一个是原始的节数据。

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