PE文件结构(一)

一.     PE文件结构图

二.     DOS 头部

其中最后一个字段DWORD e_lfanew;的值为PE文件头的相对偏移地址(RVA);

三.PE文件头

结构体的定义:IMAGE_NT_HEADERS:左边地址为相对PE文件头地址的偏移量。

DWORD Signature:PE文件头标识,一般其值为:0x00004550;对应字符为PE..;

1.映像文件头(_IMAGE_FILE_HEADER FileHeader):

左边地址为相对映像文件头的地址文件头地址的偏移量。

IMAGE_FILE_HEADER的大小为20字节.

第一个成员为WORD类型的Machine,这个通常为0x014C(intel 386系列CPU);

第二个成员为WORD类型的NumberOfSections,即文件中节的数量,这个对应的文件具体的节区数量。

第三个成员为DWORD类型的TimeDateStamp,是一个时间戳,对应于从1970年1月1日开始的秒数。

第四个和第五个成员分别为DWORD类型的PointerToSymbolTable和NumberOfSymbols,和调试相关,这里忽略。

第六个成员为WORD类型的SizeOfOptionalHeader,即后面可选映像头部分的大小,即为IMAGE_OPTIONAL_HEADER的大小,一般情况下32位的为0x00E0,64位的为0x00F0

第七个成员为WORD类型的Characteristics,反映出这个文件的类型以及运行平台的特征。

2.可选映像头(IMAGE_OPTIONAL_HEADER OptionalHeader)

比较重要的字段:

(1)WORD Magic:标记字,其说明了文件的映像类型:

ROM映像:0x0107

普通可执行的映像:0x010B(一般)

PE(32+)映像:0x020B

(2) 。DWORD AddressOfEntryPoint,这个字段是程序执行的入口RVA地址。

对于DLL文件,这个入口点是在进程初始化和关闭时以及线程创建和毁灭时被调用。大多数的的可执行文件中这个地址并不指向MAIN,WINMAIN或DLLMAIN,而是指向运行时库代码并由其来调用上述函数在DLL中这个域可以被置为0

BaseOfCode:代码段的起始RVA。通常为1000H

BaseOfData:  数据段的起始RVA。在64位的可执行文件中其是不存在的,了解就行

(3) ImageBase为建议的装载地址。对于可执行文件来说一般是

0x00400000。

SectionAlignment为内存中节的对齐大小,即每个区段装入得大小必须是该值得整数倍,一般为0x00001000H(4KB).FileAlignment为PE文件中节的对齐大小

(4) Subsystem: 指定程序的子系统类型.

微软定义如下:


Value


Meaning


IMAGE_SUBSYSTEM_UNKNOWN

0


Unknown subsystem.


IMAGE_SUBSYSTEM_NATIVE

1


No subsystem required (device drivers and native system processes).


IMAGE_SUBSYSTEM_WINDOWS_GUI

2


Windows graphical user interface (GUI) subsystem.


IMAGE_SUBSYSTEM_WINDOWS_CUI

3


Windows character-mode user interface (CUI) subsystem.


IMAGE_SUBSYSTEM_OS2_CUI

5


OS/2 CUI subsystem.


IMAGE_SUBSYSTEM_POSIX_CUI

7


POSIX CUI subsystem.


IMAGE_SUBSYSTEM_WINDOWS_CE_GUI

9


Windows CE system.


IMAGE_SUBSYSTEM_EFI_APPLICATION

10


Extensible Firmware Interface (EFI) application.


IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER

11


EFI driver with boot services.


IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER

12


EFI driver with run-time services.


IMAGE_SUBSYSTEM_EFI_ROM

13


EFI ROM image.


IMAGE_SUBSYSTEM_XBOX

14


Xbox system.


IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION

16


Boot application.

☆数据目录表DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

其指向了输出表,输入表,资源块等数据。其由数个相同的IMAGE_DATA_DIRECTORY结构组成。数据目录成员(16个成员)定义如下:

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

基本结构如右图:


对应的偏移地址(RVA)相对PE文件头地址的偏移量及数据块的大小:


Offset (PE/PE32+)


Description


96/112(78h)


Export table address and size(输出表的地址与大小)


104/120(80h)


Import table address and size(输入表的地址与大小)


112/128(88h)


Resource table address and size


120/136(90h)


Exception table address and size


128/144(98h)


Certificate table address and size


136/152(A0h)


Base relocation table address and size


144/160(A8h)


Debugging information starting address and size


152/168(B0h)


Architecture-specific data address and size


160/176(B8h)


Global pointer register relative virtual address


168/184(C0h)


Thread local storage (TLS) table address and size


176/192(C8h)


Load configuration table address and size


184/200(D0h)


Bound import table address and size


192/208(D8h)


Import address table address and size


200/216(E0h)


Delay import descriptor address and size


208/224(E8h)


The CLR header address and size


216/232


Reserved(保留)

●输出表(IMAGE_DIRECTORY_ENTRY_EXPORT)

输出表的内容即结构体IMAGE_DIRECTORY_ENTRY_EXPORT所指向的地址的内容

1.当PE文件被执行的时候,windows装载器将文件装入内存并将输入表中登记的DLL文件一并装入,再根据DLL文件中的函数输出信息对被执行文件的IAT表进行修正。在这些包含输出函数的DLL文件中,输出信息被保存在输出表中,通过输出表,DLL文件向系统提供输出函数的名称,序号和入口地址等信息。以便windows装载器通过这些信息来完成动态链接的过程。一般来说,exe文件不存在输出表,DLL文件大部分都包含输出表,不过这不是绝对的。

2.Base:导出函数序号的起始值,将AddressOfFunctions 字段指向的入口地址表的索引号加上这个起始值就是对应函数的导出 序号。假如Base 字段的值为x,那么入口地址表指定的第1个导出函数的序号就是x;第2个导出函数的序号就是x+1。总之,一个导出函数的导出序号等 于Base 字段的值加上其在入口地址表中的位置索引值。

3.AddressOfNames 和 AddressOfNameOrdinals:均为RVA 值。前者指向函数名字符串地址表。这个地址表是一个双字数组,数组中的每一项指向一个函数名称字符串的RVA。数组的项数等于NumberOfNames 字段的值,所有有名称的导出函数的名称字符串都定义在这个表中;后者指向另一个word 类型的数组(注意不是双字数组)。数组项目与文件名地址表中的项目一一对应,项目值代表函数入口地址表的索引,这样函 数名称与函数入口地址关联起来。(举个例子说,加入函数名称字符串地址表的第n 项指向一个字符串“MyFunction”,那么可以去查找 AddressOfNameOrdinals 指向的数组的第n 项,假如第n 项中存放的值是x,则表示AddressOfFunctions 字段描述的地址表中的第x 项函数入口地址对应的名称就是“MyFunction”)

  • ●输入表(IMAGE_DIRECTORY_ENTRY_IMPORT  )☆

IID(_IMAGE_IMPORT_DESCRIPTOR)结构如下图所示:

每个被PE文件隐式地连接进来的DLL文件都有一个IID。在这个结构中没有字段指出该结构数组的项数,但它的最后一个单元式NULL,可以由此计算出该数组的项数

如下图所示:

IMAGE_THUNK_DATA为DWORD大小

当 IMAGE_THUNK_DATA 值的最高位为 1时,表示函数以序号方式输入,这时候低 31位被看作一个函数序号。当

IMAGE_THUNK_DATA 值的最高位为 0时,表示函数以字符串类型的函数名方式输入,这时双字的值是一个 RVA,指向一个 IMAGE_IMPORT_BY_NAME 结构。

上图中最后加的14位NULL标记为最后一项。

IMAGE_IMPORT_BY_NAME结构如右图。

结构中的 Hint 字段也表示函数的序号,不过这个字段是可选的,有些编译器总是将它设置为 0,Name 字段定义了导入函数的名称字符串,这是一个以 0 为结尾的字符串。

为什么由两个并行的指针数组同时指向 IMAGE_IMPORT_BY_NAME 结构呢?第一个数组(由 OriginalFirstThunk 所指向)是单独的一项,而且不能被改写,我们前边称为 INT。第二个数组(由 FirstThunk 所指向)事实上是由 PE 装载器重写的。

PE 装载器首先搜索 OriginalFirstThunk ,找到之后加载程序迭代搜索数组中的每个指针,找到每个 IMAGE_IMPORT_BY_NAME 结构所指向的输入函数的地址,然后加载器用函数真正入口地址来替代由 FirstThunk 数组中的一个入口,因此我们称为输入地址表(IAT)。

OriginalFirstThunk指向INT表,存储API函数名称。FirstThunk执行IAT表,存储API函数地址,即是PE文件在影射到内存空间后,所用到的地址表,此时OringinalFirstThunK 就无用啦。

时间: 2024-10-11 03:21:00

PE文件结构(一)的相关文章

PE文件结构与函数导出表——详解与实例

PE文件结构与函数导出表--详解与实例 随着windows系统从Xp升级到Win7.Win8, 从32位升级到64位,PE文件结构在整体未变的情况下发生了一些小的变动,一方面是推荐的程序装载地址未采用,另一方面,导出函数序号不再是简单的升序,而是一定程度上的进行了乱序.本文首先对PE文件结构进行了详尽的解说,接着介绍了如何得出函数导出表,整个过程采用SysWoW64目录下的wininet.dll实例进行说明.在介绍过程中,明确指出了Win7.Win8等新系统相对Xp带来的区别. 文章链接:htt

PE文件结构(五)基址重定位

PE文件结构(五) 参考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 基址重定位 链接器生成一个PE文件时,它会假设程序被装入时使用的默认ImageBase基地址(VC默认exe基地址00400000h,dll基地址10000000h),并且会把代码中所有指令中用到的地址都使用默认的基地址(例如 程序代码中 push 10001000,就是把10000000h当做了基地址,把push 10001000写入到文件中).如果一个exe程序中一个dll装载时的地址与其它dll地址发生冲突(因为

PE文件结构(四) 输出表

PE文件结构(四) 参考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 输出表 一般来说输出表存在于dll中.输出表提供了 文件中函数的名字跟这些函数的地址, PE装载器通过输出表来修改IAT. IMAGE_OPTIONAL_HEADER中的 DataDirectory[0] 提供了输出表的RVA.输出表是以一个IMAGE_EXPORT_DIRECTORY结构 开始的. IMAGE_EXPORT_DIRECTORY结构: typedef struct _IMAGE_EXPORT_DIREC

PE文件结构(一)

参考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 exe,dll都是PE(Portable Execute)文件结构.PE文件使用的是一个平面地址空间,所有代码和数据都被合并在一起,组成一个很大的结构.先看2张图,来大概了解一下PE文件结构. PE文件的框架结构 通过这张图(开始在下面),我们可以知道PE文件的大概结构,PE文件是由 DOS头,PE文件头,块表,块,调试信息 这些部分组成的.这些结构的定义在 winnt.h 中的  "Image Format"  这一

PE文件结构详解

1.定位标准PE头 DOS Stub长度不固定,所以DOS头不是一个固定大小的数据结构.DOS头位于PE的起始位置,通过DOS头去定位后面标准PE头的位置就是通过字段e_lfanew. e_lfanew字段的值是一个相对偏移量,绝对定位时需要加上DOS MZ头的基地址. 也就是PE头的绝对位置是: PE_start = DOS MZ 基地址+IMAGE_DOS_HEADER.e_lfanew 2.PE文件结构 在32位系统下,最重要的部分是PE头和PE数据区. 32位系统下的PE文件被划分为:D

PE文件结构(三) 输入表

PE文件结构(三) 參考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 输入表 输入函数,表示被程序调用可是它的代码不在程序代码中的,而在dll中的函数.对于这些函数.磁盘上的可执行文件仅仅是保留相关的函数信息,如函数名,dll文件名称等. 在程序执行前.程序是没有保存这些函数在内存中的地址.当程序执行起来时.windows载入器会把相关的dll装入内存.而且将输入函数的指令与函数真在内存中正的地址联系起来.输入表(导入表)就是用来保存这些函数的信息的. 在   IMAGE_OPTIONA

PE文件结构详解(四)PE导入表

PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPORT,即导入表. 也许大家注意到过,在IMAGE_DATA_DIRECTORY中,有几项的名字都和导入表有关系,其中包括:IMAGE_DIRECTORY_ENTRY_IMPORT,IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,IMAGE_DIRECTORY_ENTRY_IAT

PE文件结构详解(二)可执行文件头

在PE文件结构详解(一)基本概念里,解释了一些PE文件的一些基本概念,从这篇开始,将详细讲解PE文件中的重要结构. 了解一个文件的格式,最应该首先了解的就是这个文件的文件头的含义,因为几乎所有的文件格式,重要的信息都包含在头部,顺着头部的信息,可以引导系统解析整个文件.所以,我们先来认识一下PE文件的头部格式.还记得上篇里的那个图吗? DOS头和NT头就是PE文件中两个重要的文件头. 一.DOS头 DOS头的作用是兼容MS-DOS 操作系统中的可执行文件,对于32位PE文件来说,DOS所起的作用

PE文件结构详解(三)PE导出表

上篇文章 PE文件结构详解(二)可执行文件头 的结尾出现了一个大数组,这个数组中的每一项都是一个特定的结构,通过函数获取数组中的项可以用RtlImageDirectoryEntryToData函数,DataDirectory中的每一项都可以用这个函数获取,函数原型如下: PVOID NTAPI RtlImageDirectoryEntryToData(PVOID Base, BOOLEAN MappedAsImage, USHORT Directory, PULONG Size); Base:模

PE文件结构详解(一)基本概念

PE(Portable Execute) 文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任 何扩展名.那Windows是怎么区分可执行文件和非可执行文件的呢?我们调用LoadLibrary传递了一个文件名,系统是如何判断这个文件是一个合 法的动态库呢?这就涉及到PE文件结构了. PE文件的结构一般来说如下图所示:从起始位置开始依次是DOS头,NT头,节表以及具体的节. DOS头是用来兼容MS-DOS操