PE(Portable Executable) File Format(Chinese) - PE(可移植的可执行文件) 文件格式说明(中文)

PE文件结构(PE文件简介)
[2008/3/27 15:56:00| By:perfecter]

1 PE文件简介

PEPortable Executable,可移植的可执行文件)文件是指在Microsoft Windows95及其之后的Microsoft操作系统上运行的可执行文件,包括.EXE文件和.DLL文件。

可移植性(Portable)是指在任何机器(Intel 386 MIPS Alpha Power PC 等)上的Microsoft Windows操作系统都可以使用相同的可执行文件格式,使得程序加载器以及程序开发工具不需要针对每一个新的操作系统重写。

2 相关概念

     RVARelative Virtual Address

当被装载到内存中,可执行文件的某一个项目相对于基地址的偏移。比如一个可执行文件被装载到虚拟地址空间的0x40000处,其中有一个项目位于0x401464处,那么它的RVA就是0x1464。虚拟地址(0x401464- 基地址(0x400000= RVA0x1464

     Section()

PE文件中最基本的代码或者数据单元。例如,PE文件中的所有代码可以被放在同一个节中,或者每一个函数都可以被放到不同的节中去。节有点类似于Intel 8086的段。PE文件可以有多个节,像.text(代码节)以及.data(数据节)节等。

3 PE文件结构

下面就是一个典型的PE文件的结构示意图:

MS-DOS

 

Offset to
PE Header

MS DOS 2.0 Stub Program

 

Magic Number

PE Header

 

 

Optional header 

 

 

Section headers

 

 

Sections

 

 

PE文件结构(PE文件头一)
[2008/3/27 15:58:00| By:perfecter]

3 PE文件结构

     MS-DOS

MS-DOS头在winnt.h中定义成为IMAGE_DOS_HEADER,这个结构中,最需要关心的是成员e_lfanew,它给出了PE Header在文件中的偏移量。比如,e_lfanew的值是0xE0,则PE Header在文件距离开头0xE0处。

     MS DOS 2.0 Stub Program

这是一段DOS程序,如果把win32的可执行文件放到dos上执行,这段代码将在屏幕上显示类似于“This program can not run in dos”的信息。

     Magic NumberPE Header

这才是真正的win32可执行文件的开始。Magic Number是一个DWORD类型的数,值是0x4550,对应的ASCII值就是“PE”PE Headerwinnt.h里被定义成为:

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;

其中:

Machine:声明PE文件是在那种CPU架构下运行,它可以是下表中所列出的值:(通常PE文件运行在x86系列的CPU架构下,这个值就应该是0x 14C 。)

标志

说明

IMAGE_FILE_MACHINE_UNKNOWN

0x0

假定在所有机器上运行

IMAGE_FILE_MACHINE_AM33

0x1d3

Matsushita AM33

IMAGE_FILE_MACHINE_AMD64

0x8664

x64

IMAGE_FILE_MACHINE_ARM

0x 1c 0

ARM little endian

IMAGE_FILE_MACHINE_EBC

0xebc

EFI byte code

IMAGE_FILE_MACHINE_I386

0x 14c

Intel 386家族及其兼容CPU

IMAGE_FILE_MACHINE_IA64

0x200

Intel Itanium处理器家族

IMAGE_FILE_MACHINE_M32R

0x9041

Mitsubishi M32R little endian

IMAGE_FILE_MACHINE_MIPS16

0x266

MIPS16

IMAGE_FILE_MACHINE_MIPSFPU

0x366

MIPS with FPU

IMAGE_FILE_MACHINE_MIPSFPU16

0x466

MIPS16 with FPU

IMAGE_FILE_MACHINE_POWERPC

0x 1f 0

Power PC little endian

IMAGE_FILE_MACHINE_POWERPCFP

0x 1f 1

有浮点支持的Power PC

IMAGE_FILE_MACHINE_R4000

0x166

MIPS little endian

IMAGE_FILE_MACHINE_SH3

0x 1a 2

Hitachi SH3

IMAGE_FILE_MACHINE_SH3DSP

0x 1a 3

Hitachi SH3 DSP

IMAGE_FILE_MACHINE_SH4

0x 1a 6

Hitachi SH4

IMAGE_FILE_MACHINE_SH5

0x 1a 8

Hitachi SH5

IMAGE_FILE_MACHINE_THUMB

0x 1c 2

Thumb

IMAGE_FILE_MACHINE_WCEMIPSV2

0x169

MIPS little-endian WCE v2

NumberOfSections表示PE文件中节的数量。

TimeDateStamp:链接器产生这个文件的时间,是自从 1969 12 3 1 4:00 P.M. 之后的总秒数。

PointerToSymbolTableNumberOfSymbols一般只对COFFCommon Object File Format)格式文件有用。

SizeOfOptionalHeader它是Optional header的大小,也就是sizeof(IMAGE_OPTIONAL_HEADER)Optional header被定义成为IMAGE_OPTIONAL_HEADER结构)。

Characteristics声明这个PE文件的性质,它可以是下表列出的值,并且可以按位或:(对于一个DLL文件,这个值应该通常是0x2102;对于一个EXE文件,这个值通常是0x0103

标志

描述

IMAGE_FILE_RELOCS_STRIPPED

0x0001

用于Windows CEWindows NT以及后续操作系统。声明此PE文件没有基础重定位,并且必须装载到预先定义的基地址。如果基地址不可用,装载器将报错。

IMAGE_FILE_EXECUTABLE_IMAGE

0x0002

这是一个可执行文件。

IMAGE_FILE_LINE_NUMS_STRIPPED

0x0004

这一位应该置零。

IMAGE_FILE_LOCAL_SYMS_STRIPPED

0x0008

这一位应该置零。

IMAGE_FILE_AGGRESSIVE_WS_TRIM

0x0010

建议不要再Windows 2000机器后续系统中使用,应该置零。

IMAGE_FILE_LARGE_ADDRESS_ AWARE

0x0020

程序可以处理大于 2G 的地址。

 

0x0040

此位为将来使用而保留。

IMAGE_FILE_BYTES_REVERSED_LO

0x0080

这一位应该置零。

IMAGE_FILE_32BIT_MACHINE

0x0100

机器以32位架构为基础。

IMAGE_FILE_DEBUG_STRIPPED

0x0200

调试信息已经被移除。

IMAGE_FILE_REMOVABLE_RUN_ FROM_SWAP

0x0400

如果文件位于可移动的媒体上,那么将整个文件读入交换文件。

IMAGE_FILE_NET_RUN_FROM_SWAP

0x0800

如果文件位于网络上,那么将整个文件读入交换文件。

IMAGE_FILE_SYSTEM

0x1000

文件是一个系统文件,不是用户文件

IMAGE_FILE_DLL

0x2000

文件是一个动态链接库,虽然它们不能直接运行,也被认为是一个可执行文件。

IMAGE_FILE_UP_SYSTEM_ONLY

0x4000

只能在单芯片机器上运行

IMAGE_FILE_BYTES_REVERSED_HI

0x8000

这一位应该置零。

 

 

PE文件结构(PE文件头二)
[ 2008/4/1 9:05 :00| By:perfecter]

     Optional header

从字面上看,这个文件头是可选的,但实际上它是PE文件中必不可少的。它在winnt.h中被定义称为:

typedef struct _IMAGE_OPTIONAL_HEADER {

    WORD    Magic;

    BYTE    MajorLinkerVersion;

    BYTE    MinorLinkerVersion;

    DWORD   SizeOfCode;

    DWORD   SizeOfInitializedData;

    DWORD   SizeOfUninitializedData;

    DWORD   AddressOfEntryPoint;

    DWORD   BaseOfCode;

    DWORD   BaseOfData;

    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_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

其中:

Magic声明PE文件的状态,如果是普通的PE文件,值为0x10B;如果是只读的,值为0x107

MajorLinkerVersionMinorLinkerVersion链接器的版本号,但实际上这两个值并不可靠,某些链接器不会设置这两个值。

SizeOfCode所有代码节的大小。

SizeOfInitializedDataSizeOfUninitializedData所有已初始化数据节、未初始化数据节的大小。

AddressOfEntryPoint这是一个RVA。当PE文件被装载到内存中以后,第一条可执行指令的地址。对于设备驱动,这是初始化函数的地址;对于DLL,这个入口点是可选的,如果DLL没有入口点,则这个值必须为零。

BaseOfCodeBaseOfData代码的RVA,已初始化数据的RVA

ImageBasePE文件的优先装载地址。比如,这个值是0x10000000,则装载器会将PE文件优先装载到虚拟内存地址0x10000000中。通常.EXE文件的这个值是0x00400000.DLL文件的是0x10000000

SectionAlignmentPE文件装载到内存后,节的对齐粒度,必须大于等于FileAlignmentWIN32下,一般是0x1000WIN64下,一般是0x2000

FileAlignmentPE文件中,节的对齐粒度。一般情况下是0x200的倍数。

MajorOperatingSystemVersionMinorOperatingSystemVersion期望的操作系统版本。

MajorImageVersionMinorImageVersion期望的PE文件版本,某些链接器不设定这个值。

MajorSubsystemVersionMinorSubsystemVersion期望的子系统版本。

Win32VersionValue这个是保留的,必须是0

SizeOfImagePE文件装载到内存后,整个镜像的大小,必须是SectionAlignment的整数倍。

SizeOfHeadersMS-DOS头、MS DOS 2.0 Stub ProgramMagic NumberPE HeaderOptional header大小之和,必须是FileAlignment的整数倍。

CheckSum对于普通的PE文件,这个值是0

Subsystem声明PE文件在什么样的系统上运行,可以是下表中的值:(对于WINDOWS开发,通常选择第三项或者第四项)

Constant

Value

Description

IMAGE_SUBSYSTEM_UNKNOWN

  0

未知子系统。

IMAGE_SUBSYSTEM_NATIVE

  1

设备驱动以及WINDOWS内部程序。

IMAGE_SUBSYSTEM_WINDOWS_GUI

  2

WINDOWS GUI 程序。

IMAGE_SUBSYSTEM_WINDOWS_CUI

  3

WINDOWS控制台程序。

IMAGE_SUBSYSTEM_POSIX_CUI

  7

Posix字符子系统程序。

IMAGE_SUBSYSTEM_WINDOWS_CE_GUI

  9

Windows CE

IMAGE_SUBSYSTEM_EFI_APPLICATION

10

可扩展固件程序。

IMAGE_SUBSYSTEM_EFI_BOOT_ SERVICE_DRIVER

11

启动服务的EFI驱动。

IMAGE_SUBSYSTEM_EFI_RUNTIME_ DRIVER

12

运行时的EFI驱动。

IMAGE_SUBSYSTEM_EFI_ROM

13

EFI只读镜像。

IMAGE_SUBSYSTEM_XBOX

14

XBOX

DllCharacteristics声明DLL文件的性质,可以是下表中的值:(如果没有特别需要,这个值是零)

常量

描述

 

0x0001

保留的,必须为零。

 

0x0002

保留的,必须为零。

 

0x0004

保留的,必须为零。

 

0x0008

保留的,必须为零。

IMAGE_DLL_CHARACTERISTICS_

DYNAMIC_BASE

0x0040

DLL可以在运行时被重置。

IMAGE_DLL_CHARACTERISTICS_

FORCE_INTEGRITY

0x0080

强制进行代码完整性检查。

IMAGE_DLL_CHARACTERISTICS_

NX_COMPAT

0x0100

映像是NX兼容的。

IMAGE_DLLCHARACTERISTICS_ NO_ISOLATION

0x0200

不隔离映像文件。

IMAGE_DLLCHARACTERISTICS_ NO_SEH

0x0400

不使用结构化异常处理。

IMAGE_DLLCHARACTERISTICS_ NO_BIND

0x0800

不绑定映像

 

0x1000

保留的,必须为零。

IMAGE_DLLCHARACTERISTICS_ WDM_DRIVER

0x2000

WDM驱动。

IMAGE_DLLCHARACTERISTICS_ TERMINAL_SERVER_AWARE

0x8000

终端服务器

SizeOfStackReserve预留栈的大小,一般默认为0x10000

SizeOfStackCommit提交栈的大小,一般默认为0x1000

SizeOfHeapReserve预留堆的大小,一般默认为0x10000

SizeOfHeapCommit提交堆的大小,一般默认为0x1000

LoaderFlags保留的,必须为零。

NumberOfRvaAndSizes之后的数据目录的数量,强烈建议使用默认的16

DataDirectory数据目录,每一个对应一个节,声明该节的RVA和大小。

     Section headers

每一个节对应一个与之相关的节头,节头声明了节的大小、RVA以及的性,在winnt.h中,节头定义如下:

#define IMAGE_SIZEOF_SHORT_NAME 8

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;

其中:

Name一个8字节长度的变量,给出节的名字。如果名字中的字符少于8字节,则用NULL填充;如果刚好等于8字节,则不需要以NULL结束。一般情况下,代码节名称为“.text”,数据节为“.data”

Misc这是一个联合体,在可执行映像中,使用的是VirtualSize,声明对应的节的大小。

VirtualAddressPE文件读入内存后,对应节的RVA

SizeOfRawData磁盘上,节根据FileAlignment对齐后的大小,必须是FileAlignment的倍数。

PointerToRawData从文件开头到对应节的偏移量。

PointerToRelocations

PointerToLinenumbers

NumberOfRelocations

NumberOfLinenumbers以上四个变量在可执行文件中用不到。

Characteristics声明节的性质:可以是下表中的值,并可以按位或:

标志

描述

IMAGE_SCN_CNT_CODE

0x00000020

节包含可执行代码。

IMAGE_SCN_CNT_INITIALIZED_DATA

0x00000040

节包含已经初始化的数据。

IMAGE_SCN_CNT_UNINITIALIZED_ DATA

0x00000080

节包含未初始化的数据。

IMAGE_SCN_LNK_INFO

0x00000200

节包含注释或其他信息。只用于目标文件。

IMAGE_SCN_LNK_REMOVE

0x00000800

节不是映像的一部分,只用于目标文件。

IMAGE_SCN_LNK_COMDAT

0x00001000

节包含COMDAT数据。只用于目标文件。

IMAGE_SCN_GPREL

0x00008000

节包含引用全局指针的数据。

IMAGE_SCN_LNK_NRELOC_OVFL

0x01000000

节包含扩展重定位。

IMAGE_SCN_MEM_DISCARDABLE

0x02000000

根据需要,节可被废弃。

IMAGE_SCN_MEM_NOT_CACHED

0x04000000

节不可被缓存。

IMAGE_SCN_MEM_NOT_PAGED

0x08000000

节不可被分页。

IMAGE_SCN_MEM_SHARED

0x10000000

节可在内存中被共享。

IMAGE_SCN_MEM_EXECUTE

0x20000000

节可以执行。

IMAGE_SCN_MEM_READ

0x40000000

节可被读取。

IMAGE_SCN_MEM_WRITE

0x80000000

节可被写入。

 

 

PE文件结构()
[2008/4/2 15:07:00| By:perfecter]

     Sections

每一个节对应一个节头,节的数量必须与PE HeaderNumberOfSections声明的相一致。几个比较常见的节是:输出符号节、输入符号节、数据节、重定位节和代码节。比较复杂的是输出符号节、输入符号节和重定位节:

I.             输出符号节

输出符号节,包含一些可以供其他映像文件使用的符号信息。GetProcAddress()函数就是通过这个节找到需要的函数的。

输出符号包含若干个表,见下表。通常只需要输出目录表(Export directory table)和输出地址表(Export address table)。

表名

描述

Export directory table

这个表说明其他输出标的位置和大小。

Export address table

输出表的RVA数组,是可执行文件内可执行代码节和数据节中的输出函数和数据的真实地址。利用这个表,其他的映像可以使用这些符号。

Name pointer table

按升序排列的公共输出名的数组。

Ordinal table

Name pointer table的成员顺序排序的数组。因此,Name pointer table Ordinal table相同数量的成员。 每一个序数都是一个指向Export address table的索引。

Export name table

一组连续的以NULL结尾的ASCII字符。Name pointer table的成员指向这个区域。这些是输入或输出符号的公共名称;它们没有必要和在映像内部使用的私有名称相同。

当其他的映像文件利用名称导入一个符号,Win32装载器在Name pointer table中寻找与之符合的字符。如果找到相符的字符,序号被用来在Ordinal table中查找相应的成员(就是说,两个表有相同的索引)。找到的序号是指向Export address table的一个索引,指向的成员给出了期望的符号的真实位置。

如果其他的映像文件利用序号导入一个符号,就不需要在Name pointer table中来查找符合的字符。直接使用序号效率会更高。

?  Export directory table

winnt.h中,Export directory table被定义为如下结构:

typedef struct _IMAGE_EXPORT_DIRECTORY {

    DWORD   Characteristics;

    DWORD   TimeDateStamp;

    WORD    MajorVersion;

    WORD    MinorVersion;

    DWORD   Name;

    DWORD   Base;

    DWORD   NumberOfFunctions;

    DWORD   NumberOfNames;

    DWORD   AddressOfFunctions;     // RVA from base of image

    DWORD   AddressOfNames;         // RVA from base of image

    DWORD   AddressOfNameOrdinals;  // RVA from base of image

} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

Characteristics保留的,必须为零。

TimeDateStamp输出数据被建立的时间。

MajorVersion主版本数字,可以被用户设定。

MinorVersion次版本数字,可以被用户设定。

Name包含此DLL名称的ASCII字符串的地址,与镜像基地址相关。

Base输出符号的起始数字,通常是1

NumberOfFunctionsExport address table中的入口个数。

NumberOfNamesName pointer table中的名称个数。

AddressOfFunctionsExport address table的地址,与镜像基地址相关。

AddressOfNamesName pointer table的地址,与镜像基地址相关。

AddressOfNameOrdinalsExport name table的地址,与镜像基地址相关。

? 

 

表间图示

II.           输入符号节

所有需要导入符号的影响文件,都需要一个称之为.idata的节。导入信息的典型结构如下图所示:

Directory Table

 

 

 

Null Directory Entry

DLL1 Import Lookup Table

 

Null

DLL2 Import Lookup Table

 

Null

DLL3 Import Lookup Table

 

Null

Hint-Name Table

 

?  Import Directory Table

导入表由一系列的IMAGE_IMPORT_DESCRIPTOR结构组成,结构的数量取决于程序要使用的DLL文件的数量,每个结构对应一个DLL文件,例如,如果一个PE文件从10个不同的DLL文件中引入了函数,那么就存在10IMAGE_IMPORT_DESCRIPTOR结构来描述这些DLL文件,在所有这些结构的最后,由一个内容全为0IMAGE_IMPORT_DESCRIPTOR结构作为结束。

IMAGE_IMPORT_DESCRIPTOR结构的定义如下:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {

    union {

        DWORD   Characteristics;

        DWORD   OriginalFirstThunk;

    };

    DWORD   TimeDateStamp;                 

    DWORD   ForwarderChain;

    DWORD   Name;

    DWORD   FirstThunk;

} IMAGE_IMPORT_DESCRIPTOR;

typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

OriginalFirstThunk导入查询表(import lookup table)的RVACharacteristics不使用。

TimeDateStamp在映像被绑定前,这个值是零,在映像被绑定后,这个值是DLL被创建的时间。

ForwarderChain第一个转发引用的索引。

Name这是一个RVA,指向一个以 null 为结束字符的 ASCII 字符串,内含imported DLL 的名称。

FirstThunk导入地址表(import address table)的RVA

?  Import Lookup Table

一个Import Lookup Table实际上就是一个双字,在winnt.h中定于如下:

typedef struct _IMAGE_THUNK_DATA32 {

    union {

        DWORD ForwarderString;

        DWORD Function;

        DWORD Ordinal;

        DWORD AddressOfData;

    } u1;

} IMAGE_THUNK_DATA32;

typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;

当双字(就是指结构!)的最高位为1时,表示函数是以序号的方式导入的,这时双字的低位就是函数的序号。可以用预定义值IMAGE_ORDINAL_FLAG32(或80000000h)来对最高位进行测试,当双字的最高位为0时,表示函数以字符串类型的函数名方式导入,这时双字的值是一个RVA,指向Hint-Name Table

?  Hint/Name Table

winnt.h中,Hint/Name Table被定义为如下格式:

typedef struct _IMAGE_IMPORT_BY_NAME {

    WORD    Hint;

    BYTE    Name[1];

} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

Hint表示函数的序号,不过这个字段是可选的,有些编译器总是将它设置为0

NameName1字段定义了导入函数的名称字符串,这是一个以0为结尾的字符串。

?  表间图示

 

图中示意了可执行文件导入了Kernel32.dll中的ExitProcessReadFileWriteFilelstrcmp函数的情况,其中,前面3个函数按照名称方式导入,最后的lstrcmp函数按照序号导入,这4个函数的序号分别是 02f 6h0111h002bh0010h

 

PE(Portable Executable) File Format(Chinese) - PE(可移植的可执行文件) 文件格式说明(中文)_第1张图片 

PE文件中的导入表

PE文件被装入内存后,内存中的映像就被Windows装载器修正成了下图所示的样子,其中由FirstThunk字段指向的那个数组中的每个双字都被替换成了真正的函数入口地址,之所以在PE文件中使用两份IMAGE_THUNK_DATA数组的拷贝并修改其中的一份,是为了最后还可以留下一份拷贝用来反过来查询地址所对应的导入函数名:

 

PE(Portable Executable) File Format(Chinese) - PE(可移植的可执行文件) 文件格式说明(中文)_第2张图片内存中的导入表

III.          重定位节

当链接器产生一个可执行文件,它假设这个文件会被加载内存的某处,并且把code data的相关假设地址都写入 EXE 文件中。在Optional header中的ImageBase成员,记录了这个文件期望的加载地址,如果windows加载起没有把PE文件加载的它期望的地址上,则需要对code data的相关假设地址都加以修正。这就是重定位的作用。

重定位节可以分为多个重定位块,每个重定位块描述映像中的4k1000h)的重定位信息。每个重定位块都以一个相同的结构开始,在winnt.h中定义如下:

typedef struct _IMAGE_BASE_RELOCATION {

    DWORD   VirtualAddress;

    DWORD   SizeOfBlock;

} IMAGE_BASE_RELOCATION;

typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

VirtualAddress这是一个页面RVA

SizeOfBlock重定位块的总大小。

紧接着这个结构,就是一系列重定位的信息了,一个重定位信息包存在一个WORD值中,这个前4位保存这个重定位信息的性质,后12位则是一个以上面VirtualAddress为基准的偏移。其中前四位的定义如下:

 

 

描述

IMAGE_REL_BASED_ABSOLUTE

0

可以跳过这个重定位块,仅仅是用来对齐。

IMAGE_REL_BASED_HIGH

1

32位的高16位需要修正。

IMAGE_REL_BASED_LOW

2

32位的低16位需要修正。

IMAGE_REL_BASED_HIGHLOW

3

整个32位需要被修正。

IMAGE_REL_BASED_HIGHADJ

4

16位的区域是一个32WORD值的高位。这个32WORD值的低16位跟在这个重定位的后面。

IMAGE_REL_BASED_MIPS_JMPADDR

5

重定位用于MIPS跳转指令。

 

6

保留的,必须是零。

 

7

保留的,必须是零。

IMAGE_REL_BASED_MIPS_JMPADDR16

9

重定位用于MIPS16跳转指令。

下面的例子举出了一个重定位表的实际情况,假设模块被装入00400000h处:

重定位表偏移  数据          说明

0000h        00001000h     第一个块:页面起始地址是00401000h

0004h        00000010h     重定位块长度是10h

0008h        3012h         16位重定位项,重定位位置:00401012h

000ah        3040h         16位重定位项,重定位位置:00401040h

000ch        306fh         16位重定位项,重定位位置:0040106fh

000eh        0000h         用于对齐的空白数据

0010h        00002000h     第二个块:页面起始地址是00402000h

0014h        0000000Ch     重定位块长度是0Ch

0018h        3080h         16位重定位项,重定位位置:00402080h

001ah        30f 0h         16位重定位项,重定位位置: 004020f 0h

001ch        00000000h     重定位

你可能感兴趣的:(C,Visual,C++,6.0,C++,PE(Portable,Executable))