Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5381559
  • 博文数量: 671
  • 博客积分: 10010
  • 博客等级: 上将
  • 技术积分: 7310
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-14 09:56
文章分类

全部博文(671)

文章存档

2011年(1)

2010年(2)

2009年(24)

2008年(271)

2007年(319)

2006年(54)

我的朋友

分类:

2007-04-19 10:59:36

在win32 SDK的文件winnt.h中有PE文件格式的定义。本文所用到的变量,如果没有特别说明,都在文件winnt.h中定义。

有关一些PE头文件结构一般都有32位和64位之分,如IMAGE_NT_HEADERS32和IMAGE_NT_HEADERS64等,除了在64位版本中的一些扩展域外,这些结构总是一样的。是采用32位还是64位,需要用#define _WIN64来定义,如果没有这种定义,则采用的是32位的文件结构。编译器将根据此定义选择相应的编译模式。

2.3.1  MS-DOS头部

MS-DOS头部占据了PE文件的头64个字节,描述它内容的结构如下:

l           

// 此结构包含于WINNT.H中

//

typedef struct _IMAGE_DOS_HEADER {   // DOS的.EXE头部

    WORD e_magic;       // 魔术数字

    WORD e_cblp;        // 文件最后页的字节数

    WORD e_cp;          // 文件页数

    WORD e_crlc;        // 重定义元素个数

    WORD e_cparhdr;     // 头部尺寸,以段落为单位

    WORD e_minalloc;    // 所需的最小附加段

    WORD e_maxalloc;    // 所需的最大附加段

    WORD e_ss;          // 初始的SS值(相对偏移量)

    WORD e_sp;          // 初始的SP值

    WORD e_csum;        // 校验和

    WORD e_ip;          // 初始的IP值

    WORD e_cs;          // 初始的CS值(相对偏移量)

    WORD e_lfarlc;      // 重分配表文件地址

    WORD e_ovno;        // 覆盖号

    WORD e_res[4];      // 保留字

    WORD e_oemid;       // OEM标识符(相对e_oeminfo)

    WORD e_oeminfo;     // OEM信息

    WORD e_res2[10];    // 保留字

    LONG e_lfanew;      // 新exe头部的文件地址

} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

l           

其中第一个域e_magic,被称为魔术数字,它用于表示一个MS-DOS兼容的文件类型。所有MS-DOS兼容的可执行文件都将这个值设为0x5A4D,表示ASCII字符MZ。MS-DOS头部之所以有的时候被称为MZ头部,就是这个缘故。还有许多其他的域对于MS-DOS操作系统来说都有用,但是对于Windows NT来说,这个结构中只有一个有用的域——最后一个域e_lfnew,一个4字节的文件偏移量,PE文件头部就是由它定位的。

2.3.2  IMAGE_NT_HEADER头部

PE Header是紧跟在MS-DOS头部和实模式程序残余之后的,描述它内容的结构   如下:

l           

typedef struct  _IMAGE_NT_HEADERS {

    DWORD Signature;                           // PE文件头标志:"PE\0\0"

    IMAGE_FILE_HEADER FileHeader;               // PE文件物理分布的信息

    IMAGE_OPTIONAL_HEADER32 OptionalHeader; // PE文件逻辑分布的信息

} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

紧接PE文件头标志之后是PE文件头结构,由20个字节组成,它被定义为:

l           

typedef struct _IMAGE_FILE_HEADER {

    WORD    Machine;

    WORD    NumberOfSections;

    DWORD   TimeDateStamp;

    DWORD   PointerToSymbolTable;

    DWORD   NumberOfSymbols;

    WORD    SizeOfOptionalHeader;

    WORD    Characteristics;

} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

#define IMAGE_SIZEOF_FILE_HEADER 20

l           

其中请注意这个文件头部的大小已经定义在这个包含文件之中了,这样一来,想要得到这个结构的大小就很方便了。

Machine:表示该程序要执行的环境及平台,现在已知的值如表2.1所示。

应用程序执行的环境及平台代码

IMAGE_FILE_MACHINE_I386(0x14c)

Intel 80386  处理器以上

0x014d

Intel 80486 处理器以上

0x014e

Intel Pentium 处理器以上

0x0160

R3000(MIPS)处理器,big endian

IMAGE_FILE_MACHINE_R3000(0x162)

R3000(MIPS)处理器,little endian

IMAGE_FILE_MACHINE_R4000(0x166)

R4000(MIPS)处理器,little endian

IMAGE_FILE_MACHINE_R10000(0x168)

R10000(MIPS)处理器,little endian

IMAGE_FILE_MACHINE_ALPHA(0x184)

DEC Alpha AXP处理器

IMAGE_FILE_MACHINE_POWERPC(0x1f0)

IBM Power PC,little endian

NumberOfSections:段的个数。

TimeDateStamp:文件建立的时间。可用这个值来区分同一个文件的不同的版本,即使它们的商业版本号相同。这个值的格式并没有明确的规定,但是很显然地大多数的C编译器都把它定为从1970.1.1 00:00:00以来的秒数(time_t)。这个值有时也被用做绑定输入目录表。注意:一些编译器将忽略这个值。

PointerToSymbolTable及NumberOfSymbols:用在调试信息中,用途不太明确,不过它们的值总为0。

SizeOfOptionalHeader:可选头的长度(sizeof IMAGE_OPTIONAL_HEADER),可以用它来检验PE文件的正确性。

Characteristics:是一个标志的集合,其大部分位用于OBJ或LIB文件中。

文件头下面就是可选择头,这是一个叫做IMAGE_OPTIONAL_HEADER的结构,由224个字节组成。虽然它的名字是“可选头部”,但是请确信:这个头部并非“可选”,而是“必需”的。可选头部包含了很多关于可执行映像的重要信息。例如,初始的堆栈大小、程序入口点的位置、首选基地址、操作系统版本、段对齐的信息等。IMAGE_ OPTIONAL_HEADER结构如下:

l           

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES     16

typedef struct _IMAGE_OPTIONAL_HEADER {

    //

    // 标准域

    //

    WORD    Magic;                    

    BYTE    MajorLinkerVersion;        

    BYTE    MinorLinkerVersion;        

    DWORD   SizeOfCode;                  

    DWORD   SizeOfInitializedData;      

    DWORD   SizeOfUninitializedData;        

    DWORD   AddressOfEntryPoint;        

    DWORD   BaseOfCode;                  

    DWORD   BaseOfData;                  

    //

    // NT附加域      

    //

    DWORD   ImageBase;                   

    DWORD   SectionAlignment;           

    DWORD   FileAlignment;          

    WORD    MajorOperatingSystemVersion;

    WORD    MinorOperatingSystemVersion;

    WORD    MajorImageVersion;       

    WORD    MinorImageVersion;       

    WORD    MajorSubsystemVersion;      

    WORD    MinorSubsystemVersion;      

    DWORD   Win32VersionValue;      

    DWORD   SizeOfImage;                

    DWORD   SizeOfHeaders;          

    DWORD   CheckSum;                

    WORD    Subsystem;                   

    WORD    DllCharacteristics;     

    DWORD   SizeOfStackReserve;     

    DWORD   SizeOfStackCommit;      

    DWORD   SizeOfHeapReserve;      

    DWORD   SizeOfHeapCommit;           

    DWORD   LoaderFlags;                

    DWORD   NumberOfRvaAndSizes;        

    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;

l           

其中参数含义如下所述。

Magic:这个值好像总是0x010b。

MajorLinkerVersion及MinorLinkerVersion:链接器的版本号,这个值不太可靠。

SizeOfCode:可执行代码的长度。

SizeOfInitializedData:初始化数据的长度(数据段)。

SizeOfUninitializedData:未初始化数据的长度(bss段)。

AddressOfEntryPoint:代码的入口RVA地址,程序从这儿开始执行,常称为程序的原入口点OEP(Original Entry Point)。

BaseOfCode:可执行代码起始位置。

BaseOfData:初始化数据起始位置。

ImageBase:载入程序首选的RVA地址。这个地址可被Loader改变。

SectionAlignment:段加载后在内存中的对齐方式。

FileAlignment:段在文件中的对齐方式。

MajorOperatingSystemVersion及MinorOperatingSystemVersion:操作系统版本。

MajorImageVersion及MinorImageVersion:程序版本。

MajorSubsystemVersion及MinorSubsystemVersion:子系统版本号,这个域系统支持。例如,程序运行于NT下,子系统版本号如果不是4.0,对话框不能显示3D风格。

Win32VersionValue:这个值总是为0。

SizeOfImage:程序调入后占用内存大小(字节),等于所有段的长度之和。

SizeOfHeaders:所有文件头长度之和,它等于从文件开始到第一个段的原始数据之间的大小。

CheckSum:校验和,仅用在驱动程序中,在可执行文件中可能为0。它的计算方法Microsoft不公开,在imagehelp.dll中的CheckSumMappedFile()函数可以计算它。

Subsystem:一个标明可执行文件所期望的子系统的枚举值。

DllCharacteristics:DLL状态。

SizeOfStackReserve:保留堆栈大小。

SizeOfStackCommit:启动后实际申请的堆栈数,可随实际情况变大。

SizeOfHeapReserve:保留堆大小。

SizeOfHeapCommit:实际堆大小。

LoaderFlags:目前没有用。

NumberOfRvaAndSizes:下面的目录表入口个数,这个值也不可靠,可用常数IMAGE_NUMBEROF_DIRECTORY_ENTRIES来代替它,这个值在目前Windows版本中设为16。注意,如果这个值不等于16,那么这个数据结构大小就不能固定下来,也就不能确定其他变量位置。

DataDirectory:是一个IMAGE_DATA_DIRECTORY数组,数组元素个数为IMAGE_NUMBEROF_DIRECTORY_ENTRIES,结构如下:

l           

typedef struct _IMAGE_DATA_DIRECTORY {

    DWORD   VirtualAddress;         // 起始RVA地址

    DWORD   Size;                      // 长度

} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

2.3.3  IMAGE_SECTION_HEADER头部

PE文件格式中,所有的节头部位于可选头部之后。每个节头部为40个字节长,并且没有任何填充信息。节头部被定义为以下的结构:

l           

#define IMAGE_SIZEOF_SHORT_NAME 8

typedef struct _IMAGE_SECTION_HEADER {

    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];   // 节表名称,如".text"

    union {

        DWORD   PhysicalAddress;        // 物理地址

        DWORD   VirtualSize;            // 真实长度

    } Misc;

    DWORD   VirtualAddress;                 // RVA

    DWORD   SizeOfRawData;                  // 物理长度

    DWORD   PointerToRawData;               // 节基于文件的偏移量

    DWORD   PointerToRelocations;           // 重定位的偏移

    DWORD   PointerToLinenumbers;           // 行号表的偏移

    WORD    NumberOfRelocations;         // 重定位项数目

    WORD    NumberOfLinenumbers;         // 行号表的数目

    DWORD   Characteristics;            // 节属性

} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

l           

其中IMAGE_SIZEOF_SHORT_NAME等于8。注意,如果不是这个值,那么这个数据结构大小就不能固定下来,也就不能确定其他变量位置。

阅读(1781) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~