您现在的位置是:首页» windows系统» pe文件格式详解,pe文件的总体结构

pe文件格式详解,pe文件的总体结构

2024-07-13 14:35:30
本内容由系统网小编为大家分享,Windows系统安装教程、办公系统、软件怎么使用、软件使用教程、办公软件攻略等信息。1、PE文件的结构1.什么是可执行文件?可执行文件(英语:Executable file)是一个可以由操作系统载入和执行的文

本内容由系统网小编为大家分享,Windows系统安装教程、办公系统、软件怎么使用、软件使用教程、办公软件攻略等信息。

1、PE文件的结构

1.什么是可执行文件?

可执行文件(英语:Executable file)是一个可以由操作系统载入和执行的文件。

可执行文件的格式:

PE和ELF非常相似,它们都来自相同的可执行文件格式COFF

事实上,在Windows平台,由Visual C++编译器生成的目标文件仍然是COFF格式,可执行的文件则是PE格式

微软的64位Windows平台的PE文件结构叫做PE32+,它将原来的32位字段转换成64位字段。

2、PE文件的特征

确定文件是否是PE文件不仅应该看到文件的副名,而且应该通过PE指纹

使用UE打开一个exe文件,发现该文件的第一个两个字母是MZ,0x3C位置存储一个地址,并且发现“PE”存储在该位置,因此基本上可以确定修改的文件是PE文件

这些重要信息(“MZ”和“PE”)验证文件是否是一个PE文件,这些信息叫做PE指纹。

3. PE文件的整体结构

这将 PE 文件的主要部分列为四个部分,其中可以首先介绍模糊的概念,然后详细解释

节点或块或块都是意义,后者将相互交换使用

下面是从二进制级别的PE文件结构的概览

PE文件映射到内存

存储在磁盘上的PE文件的结构与载入内存的文件不同。

当PE文件通过Windows加载器载入内存后,内存中的版本称为模块(Module)。

映射文件的初始地址称为模块处理(hModule),也称为基本地址(ImageBase)。

模块手柄与其他手柄不同 吗?

文件数据通常为512字节(1节)整齐(目前超过4k),32位内存通常为4k(1页),512D=200H,4096D=100H

文件中的块的大小是200H的整数,内存中的块的大小是100H的整数,映射后实际数据的大小是不变的,其余部分可以用0填充

PE文件头部(DOS头部+PE头部)与块表之间没有空隙,但两者之间存在空隙,大小取决于匹配参数

当VC编译器默认编译时,exe文件基础地址为0x400,DLL文件基础地址为0x100

VA:虚拟内存地址

RVA:相对的虚拟地址是与基地址相对的迁移地址

FOA:文件传输地址

5、DOS部分

DOS MZ文件头实际上是一个结构(IMAGE_DOS_HEADER),占有64字节

DOS字符串在16位元系统中被使用,其中DOS字符串在32位元系统中成为冗余数据,但还有两个重要的成员:e_magic字段(偏差0x0)和e_lfanew字段(偏差0x3C)。

e_magic保存了“MZ”字符,e_lfanew保存了PE字节地址,通过这个地址找到PE字节并获取PE文件标识符“PE”。

e_magic和e_lfanew是验证 PE指纹的重要字段,而其他字段大多不使用(可以填充任意的数据)

DOS Stub区域的数据由链接器填充(它可以填充数据本身的意图)并且是一个小代码,可以在DOS下运行。

这段代码的唯一作用是向终端输出一行字:“This program cannot be run in DOS”(“e_cs”和“e_ip”指向)

然后退出程序,表明该程序不能在DOS下运行。

6、PE文件头(PE Header)

PE头是一个结构(IMAGE_NT_HEADERS32),包含另外两个结构,占有4B + 20B + 224B

Signature字段设置为0x00004550,ANCII码字符是“PE00”,标识PE文件头的开始,PE标识不能破坏。

1.IMAGE_FILE_HEADER结构

IMAGE_FILE_HEADER(映像文件头或标准PE头)结构包含PE文件的一些基本信息,该结构在微软的官方文档中被称为标准通用对象文件格式(Common Object File Format,COFF)头

重要字段: NumberOfSections,SizeOfOptionalHeader

相应的结构是下图的紫色部分

0x014C表示x86CPU上运行; 0x007表示当前ex有7节点;

0x00E0描述IMAGE_OPTIONAL_HEADER32为224字节;

0x030F(00 0011 00 11)表示文件属性,结合下列相应位置和1

2.IMAGE_OPTIONAL_HEADER结构

IMAGE_OPTIONAL_HEADER(可选视频标题或扩展PE标题)是可选结构, IMAGE_FILE_HEADER结构的扩展

IMAGE_FILE_HEADER结构记录的OptionalHeader字段(可能不准确)

重要字段:

AddressOfEntryPoint: 以下显示的程序输入地址是32C40H

ImageBase:内存镜基地址,400H以下

FileAlignment:文件对齐,下图为200H

SectionAlignment:内存对齐,下图为1000H

数据目录[16]:由若干相同的IMAGE_DATA_DIRECTORY结构组成的数据目录表,

指向输出表、输入表、资源块,重定位表等(后面详解这里先跳过)

ImageBase + AddressOfEntryPoint = 程序实际上运行输入地址(实际的装载地址相当于ImageBase)。

0x400 + 0x32C40 = 0x432C40 (使用OD程序发现它从这个地址开始)

应用程序:在PE文件空白区域中添加代码,让程序先执行添加代码,然后跳进程序输入

思路:

① 在PE的空白区构造一段代码(call -> E8)

2修改新的代码输入地址( IMAGE_OPTIONAL_HEADER ).AddressOfEntryPoint)

③ 新增代码执行后,跳回入口地址(jmp -> E9)

7、块表

块表是 IMAGE_SECTION_HEADER结构的集合,每个包含40个 IMAGE_SECTION_HEADER结构的字符。

每个 IMAGE_SECTION_HEADER结构包含与它关联的块的信息,如位置、长度和属性。

重要字段: Name[8], VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData, Characteristics

IMAGE_FILE_HEADER中的NumberOfSections字段是否记录当前文件中的节点数目?

31C80H代表了装载的内存代码块的排列;100H代表了装载到内存RVA100H的代码块;

31E00H表示文件同步后代码块的大小;400H表示文件中的代码块的移动

60020H代表代码块属性(‭0110 00 00 00 00 00 00 0010 00‬) 请参阅下面的表,查看具有可读和可执行属性的代码

更多属性参考: https://docs.Microsoft.com/zh-cn/windows/win32/api/winnt/ns-winnt-image_section_header

8.将RVA转换为FOA

RVA: 相对虚拟地址, FOA: 文件转移地址.

计算步骤:

1 计算 RVA = 虚拟存储地址 - ImageBase

2如果RVA位于PE头部:FOA==RVA

3 确定 RVA 的 哪个 部分 位置 :

RVA >= 节.VirtualAddress (节在内存对齐后RVA )

RVA <= 节.VirtualAddress + 当前节内存对齐后的大小

偏移 = RVA - node.Virtual Address;

4 FOA = Section.PointerToRawData +偏移量;

应用举例:

具有初始值的全球变量的初始值存储在PE文件中,这是您修改的文件中的全球变量的数据值

你需要找到在文件中存储全球变量的位置,然后修改它

2、输出表和输入表

可选PE头的最后一个字段(扩展PE头)DataDirectory[16]表示一个由16个相同的IMAGE_DATA_DIRECTORY结构组成的数据目录表,每个结构都指向输出表、输入表、资源块等

1,输出表(抽出表)当创建一个DLL时,您实际上创建了一个允许EXE或其他DLL被调用的功能集

DLL文件通过输出表向系统提供信息,例如输出函数的名称、序列号和输入地址。

数据目录表的第一个成员是指输出表。

在文件中找到输出表(使用DllDemo.Take dll作为例子。请参见图)。

成功地在文件极化0C00H上找到输出表,如下:

注:如果文件匹配和内存匹配为4k,则不需要地址转换。2输出表大小指输出表大小及其子表大小,以及

输出表实际上是一个40字节结构(IMAGE_EXPORT_DIRECTORY)。输出表的结构如下:

重要字段: Name,Base,NumberOfNames,AddressOfFunctions,AddressOfNames,AddressOfNameOrdinals

过程分析:

//功能:将动态链接库载入内存HMODULE WINAPI LoadLibrary(LPCTSTR lpFileName // 模块的文件名);

/*函数:检索指定动态链接库(DLL)中的输出库函数地址*/FARPROC GetProcAddress(HMODULE hModule, // DLL模块处理器(模块基础地址)LPCSTR lpProcName // 指定函数的函数名称或序列值);

PE负载器调用GetProcAddress来在DLL中找到DlIDemo.API函数MsgBox,

系统定位DlI Demo.DLL的输出表(IMAGE_EXPORT_DIRECTORY)结构,获取输出函数名称表(ENT)的初始地址,

对名字进行二进制查找,直到发现字符串“MsgBox”为止,PE装载器发现MsgBox是数组的第1个条目后,加载器从输出序数表

中读取相应的第1个值,这个值是MsgBox的在函数地址表(EAT)的索引。使用索引在EAT取值得到MsgBox的RVA1008h。

添加DllDemo到1008h。DLL的装载地址获取MsgBox的实际地址。

注: 如果lpProcName是一个序列,则必须通过Base字段确定初始序列,并且序列-Base的差值作为参考得到函数RVA地址(注意序列和参考在这里)

注:输出序列表存储索引值而不是序列,而实际序列是Base+索引值

例如,写一个简单的添加函数(int add(int a, int b))并创建A.dll

分析A.进口DLL表

当用序列(12)获取函数地址时,它将12Base=0作为输出函数地址表的索引值

使用A.dll

2.输入表(输入表)

在PE文件映射到内存后,Windows将相应的DLL文件加载,EXE文件通过输入表在相应的DLL中找到进口函数,从而完成程序的正常操作

数据目录表的第二个成员是输入表,当前的文件依赖于多个模块,有多个输入表,并且不断丢弃。

如何找到输入表?

上面的图显示,当前的文件只依赖一个模块,只依赖一个进口表,如果多个模块持续存储到20 0 语句持续出现为止。

输入表实际上是一个20字节结构 IMAGE_IMPORT_DESCRIPTOR

重要字段:

Name:DLL(依赖模块)名字的指针。是一个以“00”结尾的ASCII字符的RVA地址。

OriginalFirstThunk: RVA包含一个面向输入的名称表(INT)。

FirstThunk:包含输入地址表(IAT)的RVA。IAT是一个image_THUNK_DATA结构的集合。

IMAGE_THUNK_DATA结构实际上只占4字节

如果IMAGE_THUNK_DATA32的最大位数为1,则下位31位元代表函数的输出序列,

否则,四个字符是RVA,指向IMAGE_IMPORT_BY_NAME结构

IMAGE_IMPORT_BY_NAME结构字段仅包含四个字节,这些字节存储输入函数的相关信息

从上面看,我们可以通过导入表获取当前文件依赖模块的名称和函数名称吗?

INT和IAT的内容在这里相同,为什么? 稍后解释

INT和IAT的内容在PE文件未加载时相同。

PE运载器将文件插入内存,并将实际函数地址(GetProcAddress)填入IAT

例如:

3、重定位表

如果PE文件未被载入优先地址(ImageBase),则该文件中的每个绝对地址需要修改。

需要修正的地址有很多,可以在文件中使用重定位表记录这些绝对地址的位置,在载入内存后若载入基地址与ImageBase不同再进行修正,若相同就不需要修正这些地址。

数据目录项的第6个结构,指向重定位表(Relocation Table)

重置表由单独的重置单元组成,每个单元记录需要重置的地址在4KB(一页)内存中。

每个移位数据块的大小必须与 DWORD (4 字节)的大小相符,它们以 IMAGE_BASE_RELOCATION 结构开始,格式如下

这些领域可能很难直接理解,但你可以在后面看到一个完全清晰的例子

虽然有许多类型的迁移,x86可执行的文件中,所有基本地址迁移类型是 IMAGE_REL_BASED_HIGHLOW。

在移位组的末尾,出现 typeIMAGE_REL_BASED_ABSOLUTE 的移位。这些移位除了填充即可使下一个 MAGE_BASE_RELOCATION 以 4- 字节边界线排列。

对于IA-64可执行的文件,重置类型总是显示为IMAGE_REL_BASED_DIR64。

有趣的是,虽然IA-64的EXE页面大小是8KB,但基础地址的迁移仍然是4KB的块

所有移位块都以MAGE_BASE_RELOCATION结构结束,VisualAddress字段为0。

示例分析:

继续使用DllDemo.Example: dll

使用该工具以下列方式定位文件的定位表

查看下文的重置表信息

下面实际分析

在CODE节中以下列方式确定当前RVA

所以

100Fh(RVA) → 60Fh(FOA)

1023h(RVA) → 623h(FOA)

60Fh及623h点至0040200h及00403030h点,分别为需要迁移的数据

在执行PE文件之前,当重置时,负载器使用PE文件的实际视频地址在内存中减少PE文件所需的视频地址,并根据不同类型的重置而增加相应的地址数据的差值。

您可以看到重置表的作用:一旦文件被载入内存,重置表记录的RVA会找到需要重置的数据

通过页基地址获得完整的RVA+页间极化地址,将重置表大大缩小。

4、资源

Windows程序的各个接口称为资源,包括加速键(Accelerator)、位图(Bitmap)、光标(Cursor)、对话框(Dialog Box)、图标(Icon)、菜单(Menu)、串表(String Table)、工具栏(Toolbar)和版本信息(Version Information)等。

在定义资源时,你可以用字符串作为名称来识别资源,或者用ID来识别资源

资源分类

- 标准资源类型

- 非标准资源类型

如果资源类型的高级别为1,则表示相应的资源类型是非标准的新类型

数据目录项目第三个结构是指资源表,而不是直接指资源数据,而是以磁盘目录的形式定位资源数据

资源表是一个四层二进制序列树结构。

每个节点由一个资源目录结构和以下几个资源目录项目组成。

这两个结构构成资源目录结构单元(目录块)

资源目录结构(IMAGE_RESOURCE_DIRECTORY)为16字节,定义如下

资源目录项目结构(IMAGE_RESOURCE_DIRECTORY_ENTRY)为8字节,包含2个字段,定义如下。

重要字段:

名称字段: 定义目录项的名称或ID.

OffsetToData字段:是一个指针。

在第三层目录结构中的OffsetToData将指向image_RESOURCE_DATA_ENTRY结构。

结构描述了资源数据的位置和大小,并定义如下。

重要字段:

OffsetToData:指向资源数据(RVA)

大小:资源数据的长度

实例分析:

在文件中定位资源

由于当前的exe文件匹配和内存匹配为4k,RVA不需要传输FOA

所以:

该图标的实际资源数据为4100h,而尺寸为2E8h。

RVA菜单的实际资源数据为4400h,尺寸为5Ah。

图标群的实际资源数据RVA为43E8h,尺寸为14h。

使用工具验证

可以清楚地看到根目录有三个资源目录项目(图标、菜单、图标组)

第二层是资源ID或资源名称

第三层为2052表的代码页ID简化中文,1033表的英文

实际资源数据的右下图标

XTw.com.Cn系统网专业应用软件下载教程,免费windows10系统,win11,办公软件,OA办公系统,OA软件,办公自动化软件,开源系统,移动办公软件等信息,解决一体化的办公方案。

免责声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。内容仅供参考使用,不准确地方联系删除处理!

联系邮箱:773537036@qq.com

标签: 详解 结构 文件