PE文件结构详解

合集下载

PE文件格式详解

PE文件格式详解

PE文件格式详解(一)基础知识什么是PE文件格式:我们知道所有文件都是一些连续(当然实际存储在磁盘上的时候不一定是连续的)的数据组织起来的,不同类型的文件肯定组织形式也各不相同;PE文件格式便是一种文件组织形式,它是32位Window系统中的可执行文件EXE以及动态连接库文件DLL的组织形式。

为什么我们双击一个EXE文件之后它就会被Window运行,而我们双击一个DOC文件就会被Word打开并显示其中的内容;这说明文件中肯定除了存在那些文件的主体内容(比如EXE文件中的代码,数据等,DOC 文件中的文件内容等)之外还存在其他一些重要的信息。

这些信息是给文件的使用者看的,比如说EXE文件的使用者就是Window,而DOC文件的使用者就是Word。

Window可以根据这些信息知道把文件加载到地址空间的那个位置,知道从哪个地址开始执行;加载到内存后如何修正一些指令中的地址等等。

那么PE文件中的这些重要信息都是由谁加入的呢?是由编译器和连接器完成的,针对不同的编译器和连接器通常会提供不同的选项让我们在编译和联结生成PE文件的时候对其中的那些Window需要的信息进行设定;当然也可以按照默认的方式编译连接生成Window中默认的信息。

例如:WindowNT默认的程序加载基址是0x40000;你可以在用VC连接生成EXE文件的时候使用选项更改这个地址值。

在不同的操作系统中可执行文件的格式是不同的,比如在Linux上就有一种流行的ELF格式;当然它是由在Linux上的编译器和连接器生成的,所以编译器、连接器是针对不同的CPU架构和不同的操作系统而涉及出来的。

在嵌入式领域中我们经常提到交叉编译器一词,它的作用就是在一种平台下编译出能在另一个平台下运行的程序;例如,我们可以使用交叉编译器在跑Linux的X86机器上编译出能在Arm上运行的程序。

程序是如何运行起来的:一个程序从编写出来到运行一共需要那些工具,他们都对程序作了些什么呢?里面都涉及哪些知识需要学习呢?先说工具:编辑器-》编译器-》连接器-》加载器;首先我们使用编辑器编辑源文件;然后使用编译器编译程目标文件OBJ,这里面涉及到编译原理的知识;连接器把OBJ文件和其他一些库文件和资源文件连接起来生成EXE文件,这里面涉及到不同的连接器的知识,连接器根据OS的需要生成EXE文件保存着磁盘上;当我们运行EXE文件的时候有Window的加载器负责把EXE文件加载到线性地址空间,加载的时候便是根据上一节中说到的PE文件格式中的哪些重要信息。

逆向分析实验2PE文件结构分析

逆向分析实验2PE文件结构分析

实验二PE文件结构分析一. 实验目的1.了解PE文件的输入表结构;2.手工解析PE文件的输入表;3.编程实现PE文件输入表的解析。

二. 实验内容1.第一步:手动解析输入表结构(1)使用工具箱中的工具e verything,寻找当前系统中任意一个e xe文件,文件名称是: actmovie.exe(2)使用LordPE“PE编辑器”打开exe文件,确定输入表的RVA,截图如下(图1):(3)点击PE编辑器右侧的“位置计算器”,得到文件偏移值,截图如下(图2):(4)使用16进制编辑工具,跳转到相应的输入文件偏移地址,输入表是每个IID对应一个DLL,根据IID大小,这里取20字节的数据进行分析,将输入表第一个IID结构的数据与IID结构体的成员一一对应,具体如下所示:IMAGE_IMPORT_DESCRIPTOR {OriginalFirstThunk = 000013C0TimeDateStamp = FFFFFFFFForwarderChain = FFFFFFFFName = 000014C0FirstThunk = 0000100C}(5)关注OriginalFirstThunk和Name两个成员,其中Name是一个RVA,用步骤(3)的方法得到其文件偏移值为 000008C0 ,在16进制编辑工具转到这个偏移地址,可见输入表的第一个D LL名为 msvcrt.dll ,截图如下(图3):(6)分析一下OriginalFirstThunk,它指向一个类型为IMAGE_THUNK_DATA的数组,上面已经分析出了它的值为000013C0 ,这是一个RVA,用步骤(3)的方法得到文件偏移地址 00007C0 。

在16进制编辑工具转到这个偏移地址,其中前面4个字节的数据为 63 5F 00 C8 ,截图如下(图4):(7)可以看出,这是以序号(填“以名字”或“以序号”)的方式输入函数;用与步骤(3)相同的方式在16进制编辑工具中对应IMAGE_IMPORT_BY_NAME结构的数据,可以看到函数的输入序号为 20 ,函数名为 cexit ,截图如下(图5):(8)验证:使用L ordPE单击“目录表”界面中输入表右侧的“…按钮”,打开输入表对话框,可以验证获取的DLL名和函数名是否正确。

深入剖析PE文件

深入剖析PE文件

深入剖析PE文件PE文件是Win32的原生文件格式.每一个Win32可执行文件都遵循PE文件格式.对PE文件格式的了解可以加深你对Win32系统的深入理解.一、基本结构。

上图便是PE文件的基本结构。

(注意:DOS MZ Header和部分PE header的大小是不变的;DOS stub部分的大小是可变的。

)一个PE文件至少需要两个Section,一个是存放代码,一个存放数据。

NT上的PE文件基本上有9个预定义的Section。

分别是:.text, .bss, .rdata, .data, .rsrc, .edata, .idata, .pdata, 和.debug。

一些PE文件中只需要其中的一部分Section.以下是通常的分类:l 执行代码Section , 通常命名为:.text (MS) or CODE (Borland)l 数据Section, 通常命名为:.data, .rdata, 或.bss(MS) 或DATA(Borland).资源Section, 通常命名为:.edatal 输入数据Section, 通常命名为:.idatal 调试信息Section,通常命名为:.debug这些只是命名方式,便于识别。

通常与系统并无直接关系。

通常,一个PE文件在磁盘上的映像跟内存中的基本一致。

但并不是完全的拷贝。

Windows加载器会决定加载哪些部分,哪些部分不需要加载。

而且由于磁盘对齐与内存对齐的不一致,加载到内存的PE文件与磁盘上的PE文件各个部分的分布都会有差异。

当一个PE文件被加载到内存后,便是我们常说的模块(Module),其起始地址就是所谓的HModule.二、DOS头结构。

所有的PE文件都是以一个64字节的DOS头开始。

这个DOS头只是为了兼容早期的DOS操作系统。

这里不做详细讲解。

只需要了解一下其中几个有用的数据。

1. e_magic:DOS头的标识,为4Dh和5Ah。

分别为字母MZ。

PE文件结构详细说明

PE文件结构详细说明

PE文件结构详细说明今天看这个PE文件结构真是好晕,不过还好,勉强看得明白。

就是这里面参数太多了,越看越悬乎了,哎,郁闷哦,这不,干脆来总结一下。

帮助自己理解。

不要急,慢慢来,先去喝杯水,现在整点报时,嘀嘀嘀嘀嘟。

现在是重庆时间2-14号4:21。

啊!冒视是情人节!再郁闷一下。

好了,水喝好了。

不吹废话了,言归正传。

说到PE文件结构,其实两天前我自己只是知道这么个东西,知道里面装了一些我不知道的但是很重要的东西。

这几天看Windows核心编程,看到这一节,看了3遍,晕,第一次看了觉得有那么个印象了,第二次看了就发现有些问题还不大明白,开始模糊了,第3次看了把一些疑虑搞定了,但是还是有些问题仍然模糊中。

哎!都怪自己太菜。

(可能是菜吃的太多的缘故:))。

又跑题了,再次言归正传。

先看看PE文件结构总体层次分布吧,我这里没有网络,本想在网上找个粘贴过来的,哎,只能是梦想,来自己画一个吧,建议你也自己画一下,加深印象。

(甜菜们跳过。

)。

画画中。

终于画完了,嘿嘿,现在时间5:09分。

看看这个图吧,什么感觉,是不是有点晕。

呵呵,反正我刚开始看这玩意儿的时候是这么个感觉,多看几次也就习惯了,嘿嘿。

先看看吧,有个印象。

现在继续深层次的解剖,就从DOS MZ Header 开始吧。

DOS MZ Header是一个IMAGE_DOS_HEADER类型的数据结构。

下面这就是IMAGE_DOS_HEADER数据结构的C语言定义,这个定义可以在winnt.h中找到。

结构大小=30*sizeof(WORD)+sizeof(LONG),sizeof(WORD)为2字节,sizeof(LONG)=4字节,所以整个IMAGE_DOS_HEADER大小为64字节。

typedef struct _IMAGE_DOS_HEADER { // DOS .EXE headerWORD e_magic; // Magic numberWORD e_cblp; // Bytes on last page of fileWORD e_cp; // Pages in fileWORD e_crlc; // RelocationsWORD e_cparhdr; // Size of header in paragraphsWORD e_minalloc; // Minimum extra paragraphs neededWORD e_maxalloc; // Maximum extra paragraphs neededWORD e_ss; // Initial (relative) SS valueWORD e_sp; // Initial SP valueWORD e_csum; // ChecksumWORD e_ip; // Initial IP valueWORD e_cs; // Initial (relative) CS valueWORD e_lfarlc; // File address of relocation tableWORD e_ovno; // Overlay numberWORD e_res[4]; // Reserved words注意这里是8字节WORD e_oemid; // OEM identifier (for e_oeminfo)WORD e_oeminfo; // OEM information; e_oemid specificWORD e_res2[10]; // Reserved words注意这里是20字节LONG e_lfanew; // File address of new exe header} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;其中第一个域e_magic成为魔术数字,它用于表示一个MS-DOS兼容的文件类型,所有MS-DOS兼容的可执行文件都将这个值设置为0x5A4D,表示ASCII字符MZ。

PE文件结构解析

PE文件结构解析

PE⽂件结构解析说明:本⽂件中各种⽂件头格式截图基本都来⾃看雪的《加密与解密》;本⽂相当《加密与解密》的阅读笔记。

1.PE⽂件总体结构PE⽂件框架结构,就是exe⽂件的排版结构。

也就是说我们以⼗六进制打开⼀个.exe⽂件,开头的那些内容就是DOS头内容,下来是PE头内容,依次类推。

如果能认识到这样的内含,那么“exe开头的内容是不是就直接是我们编写的代码”(不是,开头是DOS头内容)以及“我们编写的代码被编排到了exe⽂件的哪⾥”(在.text段,.text具体地址由其相应的IMAGE_SECTION_HRADER指出)此类的问题答案就显⽽易见了。

exe⽂件从磁盘加载到内存,各部份的先后顺序是保持不变的,但由于磁盘(⼀般200H)和内存(⼀般1000H)区块的对齐⼤⼩不⼀样,所以同⼀内容在磁盘和在内存中的地址是不⼀样的。

换⾔之你在磁盘上看到⼀段内容⼀内容要到在内存中找到它--假设它是能映射到内容的部份--那么要做相应的地址转换。

(⽐如你在Ultraedit 中看到某⼏个字节⽽想在OllyDbg中找到这⼏个字节那么需要进⾏地址转换)另外要注意,PE⽂件中存放的地址值都是内存中的地址,这些地址在OllyDbg中不需要转换到其指定的位置就能找到其指向的内容;这要根据这个地址找到内容在Ultraedit的地址,需要将此RVA址转换成⽂件偏移地址。

还要注意DOS头/PE头/块表,映射到内存时属同⼀区块⽽且是第⼀区块,所以此三者上的RVA和⽂件偏移地址是相等的。

2.DOS头部2.1MS-DOS头部(IMAGE_DOS_HEADER)最后的e_lfanew即是PE⽂件的RVA地址我们在前边已经提过,对于DOS头/PE头/区块表三部分RVA和⽂件偏移地址是相等的,所以上边在⼗六进制⽂本编缉器中,直接转向e_lfanew指向的000000B0可以正好找到PE头。

2.2DOS stubDOS stub是当操作系统不⽀持PE⽂件时执⾏的部分,⼀般由编译器⾃⼰⽣成内容是输出“This program cannot be run in MS-DOS mode”等提⽰。

PE文件结构

PE文件结构

节表的数据
第一个结构
最后一个结构
对齐填充数据
偏移转换计算 一
入口RVA:00261001
内存块大小
内存块起始 文件块大小
文件块起始
起始位置 块起始
结束位置 块起始 + 块长度
各个节的范围
• • • • • • • • • • • 节名 Code DATA BSS .idata .tls .rdata .reloc .rsrc .aspack .adata 起始地址 - 终了地址 00001000 - 00140000 00140000 - 00145000 00145000 - 0014B000 0014B000 - 0014E000 0014E000 - 0014F000 0014F000 - 00150000 00150000 - 00165000 00165000 - 00261000 00261000 - 00264000 00264000 - 00265000
文件头数据信息
节数目:0Ah
可选头定义
• • • • • • • • • • • • • • IMAGE_OPTIONAL_HEADER32 STRUCT SizeOfCode DWORD ? ;001ch 所有含代码的节的总大小 SizeOfInitializedData DWORD ? ;0020h 所有含已初始化数据的节的总大小 SizeOfUninitializedData DWORD ? ;0024h 所有含未初始化数据的节的大小 AddressOfEntryPoint DWORD ? ;0028h 程序执行入口RVA BaseOfCode DWORD ? ;002ch 代码的节的起始RVA BaseOfData DWORD ? ;0030h 数据的节的起始RVA ImageBase DWORD ? ;0034h PE文件的装载地址 SectionAlignment DWORD ? ;0038h 内存中的节的对齐粒度 FileAlignment DWORD ? ;003ch 文件中的节的对齐粒度 SizeOfImage DWORD ? ;0050h 内存中整个PE映像尺寸 SizeOfHeaders DWORD ? ;0054h 所有头+节表的大小 DataDirectory IMAGE_DATA_DIRECTORY 16 dup(<>) ;0078h IMAGE_OPTIONAL_HEADER32 ENDS

PE文件结构与ELF文件结构

一、PE文件结构PE文件被称为可移植的执行体是Portable Execute的全称,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL),Portable 是指对于不同的Windows版本和不同的CPU类型上PE文件的格式是一样的,当然CPU不一样了,CPU指令的二进制编码是不一样的。

只是文件中各种东西的布局是一样的。

在下面关于结构的定义中,WORD 表示变量大小为2个字节,DWORD表示变量大小是4个字节。

1.1 PE文件的结构PE文件有着固定的结构,分为五个部分,如下:1:DOS MZ Header(DOS文件头) 一个IMAGE_DOS_HEADER结构,大小为64字节。

2:DOS Stub(DOS加载模块) 没有固定大小。

3:PE Header(PE文件头)一个IMAGE_NT_HEADERS结构,大小为248字节。

4:Section Table(节表)一个IMAGE_SECTION_HEADER结构数组,数组大小依据节而定,如果PE文件有5个节,则数组大小为5。

5:Sections(节或段)没有固定大小,可以有多个节。

1.2 DOS文件头和DOS加载模块PE文件的一二部分完全是为了程序能在DOS运行下时给出一个提示。

IMAGE_DOS_HEADER结构的定义如下:Typedef struct IMAGE_DOS_HEADER{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;DOS文件头和DOS加载模块在 Windows下几乎已经没有什么作用了。

PE结构详解(64位和32位的差别)

1 基本概念下表描述了贯穿于本文中的一些概念:图1 解释了Microsoft PE可执行文件格式:PE文件总体上分为“头”和“节”。

“头”是“节”的描述、简化、说明,“节”是“头”的具体化。

3 文件头PE文件的头分为DOS头、NT头、节头。

注意,这是本人的分法,在此之前并没有这种分法。

这样分法会更加合理,更易理解。

因为这三个部分正好构成SizeOfHeaders所指的范围,所以将它们合为“头”。

这里的3个头与别的文章的头的定义会有所区别。

节头紧跟在NT头后面。

3.1 DOS头(PE文件签名的偏移地址就是大小)用记事本打开任何一个镜像文件,其头2个字节必为字符串“MZ”,这是Mark Zbikowski的姓名缩写,他是最初的MS-DOS设计者之一。

然后是一些在MS-DOS下的一些参数,这些参数是在MS-DOS下运行该程序时要用到的。

在这些参数的末尾也就是文件的偏移0x3C(第60字节)处是是一个4字节的PE文件签名的偏移地址。

该地址有一个专用名称叫做“E_lfanew”。

这个签名是“PE00”(字母“P”和“E”后跟着两个空字节)。

紧跟着E_lfanew 的是一个MS-DOS程序。

那是一个运行于MS-DOS下的合法应用程序。

当可执行文件(一般指exe、com文件)运行于MS-DOS下时,这个程序显示“This program cannot be run in DOS mode(此程序不能在DOS模式下运行)”这条消息。

用户也可以自己更改该程序,有些还原软件就是这么干的。

同时,有些程序既能运行于DOS又能运行于Windows下就是这个原因。

Notepad.exe整个DOS头大小为224个字节,大部分不能在DOS下运行的Win32文件都是这个值。

MS-DOS程序是可有可无的,如果你想使文件大小尽可能的小可以省掉MS-DOS程序,同时把前面的参数都清0。

3.2 NT头(244或260个字节)紧跟着PE文件签名之后,是NT头。

PE文件结构解析PPT教学课件


Subsystem
NT用来识别PE文件属于哪个子系统。
DataDirectory
一个IMAGE_DATA_DIRECTORY 结构数组。 每个结构给出一个重要数据结构的RVA,比 如引入地址表等。
17
几个常用术语
• RVA:Relative Virtual Address,表示相对虚拟地址。它是相对内 存中ImageBase的偏移位置。
在文件中时,每个双字中存放着对应引入函数的函数名字符串的 RVA 在内存中时,每个双字中存放着对应引入函数的地址。
请问:ExitProcess函数的地址可能在不同的操作系统中各不相同,但为什么 我们写的程序可以在不同的系统中正常运行?
40
IAT( IMPORT Address Table)
41
IMPORT Directory Table (核心)
OriginalFirstThunk dd ? //指向引入函数名列表或序号列表
Ends
TimeDateStamp dd ?
ForwarderChain dd ?
Name1 dd
?
//指向dll函数名
FirstThunk dd ?
//指向IAT表
IMAGE_IMPORT_DESCRIPTOR ENDS
IMAGE_DATA_DIRECTORY ENDS
21
22
3.4hello-2.5.exe的IAT与引入表
23
节表
节表其实就是紧挨着 PE header 的一结构数组。
该数组成员的数目由 File header (IMAGE_FILE_HEADER) 结 构中 NumberOfSections 域的域值来决定。
18

PE文件详解

一、前言(Preface)------------------PE(“portable executable”,可移植的可执行文件)文件格式,是微软WindwosNT,Windows95和Win32子集①中的可执行的二进制文件的格式;在WindowsNT中,驱动程序也是这种格式。

它还能被应用于各种目标文件②和库文件中。

这种文件格式是由微软设计的,并于1993年被TIS(tool interface standard,工具接口标准)委员会(由Microsoft,Intel,Borland,Watcom,IBM,等等组成)所批准,它明显的基于COFF文件格式的许多知识。

COFF(“common object file fromat”,通用目标文件格式)是应用于好几种UNIX系统③和VMS④系统中的目标文件和可执行文件的格式。

Win32 SDK⑤中包含一个名叫<winnt.h>的头文件,其中含有很多用于PE格式的#define和typedef定义。

我将逐步地提到其中的很多结构成员名字和#define定义。

你也可能发现DLL文件“imagehelp.dll”很有用途,它是WindowNT的一部分,但其书面文件却很缺乏。

它的一些功用在“Developer Network”(开发者网络)中有所描述。

二、总览(General Layout)-------------------------在一个PE文件的开始处,我们会看到一个MS-DOS可执行体(英语叫“stub”,意为“根,存根”);它使任何PE文件都是一个有效的MS-DOS可执行文件。

在DOS-根之后是一个32位的签名以及魔数0x00004550 (IMAGE_NT_SIGNATURE)(意为“NT签名”,也就是PE签名;十六进制数45和50分别代表ASCII码字母E和P----译者注)。

之后是文件头(按COFF格式),用来说明该二进制文件将运行在何种机器之上、分几个区段、链接的时间、是可执行文件还是DLL、等等。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事 实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任何扩展名。那Windows是怎么区分可执行 文件和非可执行文件的呢?我们调用LoadLibrary传递了一个文件名,系统是如何判断这个文件是一个合法 的动态库呢?这就涉及到PE文件结构了。 PE文件的结构一般来说如下图所示:从起始位置开始依次是DOS头,NT头,节表以及具体的节。
NumberOfSections:该PE文件中有多少个节,也就是节表中的项数。 TimeDateStamp:PE文件的创建时间,一般有连接器填写。 PointerToSymbolTable:COFF文件符号表在文件中的偏移。 NumberOfSymbols:符号表的数量。 SizeOfOptionalHeader:紧随其后的可选头的大小。 Characteristics:可执行文件的属性,可以是下面这些值按位相或。
这里写图片描述
这种表示方式叫做虚拟地址(VA)。也许有人要问,既然有VA这么简单的表示方式为什么还要有前面的 RVA呢?因为虽然PE文件为自己指定加载的基地址,但是windows有茫茫多的DLL,而且每个软件也有自己 的DLL,如果指定的地址已经被别的DLL占了怎么办?如果PE文件无法加载到预期的地址,那么系统会帮 他重新选择一个合适的基地址将他加载到此处,这时原有的VA就全部失效了,NT头保存了PE文件加载所需 的信息,在不知道PE会加载到哪个基地址之前,VA是无效的,所以在PE文件头中大部分是使用RVA来表示 地址的,而在代码中是用VA表示全局变量和函数地址的。那又有人要问了,既然加载基址变了以后VA都失 效了,那存在于代码中的那些VA怎么办呢?答案是:重定位。系统有自己的办法修正这些值,到后续重定 位表的文章中会详细描述。既然有重定位,为什么NT头不能依靠重定位采用VA表示地址呢(十万个为什 么)?因为不是所有的PE都有重定位,早期的EXE就是没有重定位的。我们都知道PE文件可以导出函数让 其他的PE文件使用,也可以从其他PE文件导入函数,这些是如何做到的?PE文件通过导出表指明自己导 出那些函数,通过导入表指明需要从哪些模块导入哪些函数。导入和导出表的具体结构会在单独的文章中 详细解释。
第2页 共13页
WORD e_cs;
// Initial (relative) CS value
WORD e_lfarlc;
// File address of relocation table
WORD e_ovno;
// Overlay number
WORD e_res[4];
// Reserved words
WORD e_oemid;
// OEM identifier (for e_oeminfo)
WORD e_oeminfo;
// OEM information; e_oemid specific
WORD e_res2[10];
// Reserved words
LONG e_lfanew;
// File address of new exe header
// DOS .EXE header // Magic number // Bytes on last page of file // Pages in file // Relocations // Size of header in paragraphs // Minimum extra paragraphs needed // Maximum extra paragraphs needed // Initial (relative) SS value // Initial SP value // Checksum // Initial IP value
0x0168 // MIPS little‐endian 0x0169 // MIPS little‐endian WCE v2 0x0184 // Alpha_AXP 0x01a2 // SH3 little‐endian 0x01a3 0x01a4 // SH3E little‐endian 0x01a6 // SH4 little‐endian 0x01a8 // SH5 0x01c0 // ARM Little‐Endian 0x01c2 0x01d3 0x01F0 // IBM PowerPC Little‐Endian 0x01f1 0x0200 // Intel 64 0x0266 // MIPS 0x0284 // ALPHA64 0x0366 // MIPS 0x0466 // MIPS IMAGE_FILE_MACHINE_ALPHA64 0x0520 // Infineon 0x0CEF 0x0EBC // EFI Byte Code 0x8664 // AMD64 (K8) 0x9041 // M32R little‐endian 0xC0EE
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
我们只需要关注两个域:
e_magic:一个WORD类型,值是一个常数0x4D5A,用文本编辑器查看该值为‘MZ’,可执行文件必须都是 'MZ'开头。
e_lfanew:为32位可执行文件扩展的域,用来表示DOS头之后的NT头相对文件起始地址的偏移。
二、NT头
顺着DOS头中的e_lfanew,我们很容易可以找到NT头,这个才是32位PE文件中最有用的头,定义如下:
typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
第1页 共13页
然而CPU的某些指令是需要使用绝对地址的,比如取全局变量的地址,传递函数的地址编译以后的汇编指 令中肯定需要用到绝对地址而不是相对映象头的偏移,因此PE文件会建议操作系统将其加载到某个内存地 址(这个叫基地址),编译器便根据这个地址求出代码中一些全局变量和函数的地址,并将这些地址用到 对应的指令中。例如在IDA里看上去是这个样子:
一、DOS头
DOS头的作用是兼容MS-DOS操作系统中的可执行文件,对于32位PE文件来说,DOS所起的作用就是显示 一行文字,提示用户:我需要在32位windows上才可以运行。我认为这是个善意的玩笑,因为他并不像显示 的那样不能运行,其实已经运行了,只是在DOS上没有干用户希望看到的工作而已,好吧,我承认这不是 重点。但是,至少我们看一下这个头是如何定义的:
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
每个域的具体含义如下: Machine:该文件的运行平台,是x86、x64还是I64fine IMAGE_FILE_MACHINE_UNKNOWN #define IMAGE_FILE_MACHINE_I386 #define IMAGE_FILE_MACHINE_R3000 #define IMAGE_FILE_MACHINE_R4000
0 0x014c 0x0162 0x0166
// Intel 386. // MIPS little‐endian, 0x160 big‐endian // MIPS little‐endian
第4页 共13页
#define IMAGE_FILE_MACHINE_R10000 #define IMAGE_FILE_MACHINE_WCEMIPSV2 #define IMAGE_FILE_MACHINE_ALPHA #define IMAGE_FILE_MACHINE_SH3 #define IMAGE_FILE_MACHINE_SH3DSP #define IMAGE_FILE_MACHINE_SH3E #define IMAGE_FILE_MACHINE_SH4 #define IMAGE_FILE_MACHINE_SH5 #define IMAGE_FILE_MACHINE_ARM #define IMAGE_FILE_MACHINE_THUMB #define IMAGE_FILE_MACHINE_AM33 #define IMAGE_FILE_MACHINE_POWERPC #define IMAGE_FILE_MACHINE_POWERPCFP #define IMAGE_FILE_MACHINE_IA64 #define IMAGE_FILE_MACHINE_MIPS16 #define IMAGE_FILE_MACHINE_ALPHA64 #define IMAGE_FILE_MACHINE_MIPSFPU #define IMAGE_FILE_MACHINE_MIPSFPU16 #define IMAGE_FILE_MACHINE_AXP64 #define IMAGE_FILE_MACHINE_TRICORE #define IMAGE_FILE_MACHINE_CEF #define IMAGE_FILE_MACHINE_EBC #define IMAGE_FILE_MACHINE_AMD64 #define IMAGE_FILE_MACHINE_M32R #define IMAGE_FILE_MACHINE_CEE
下图是一张真实的PE文件头结构以及其各个域的取值:
第3页 共13页
Signature:类似于DOS头中的e_magic,其高16位是0,低16是0x4550,用字符表示是'PE‘。 IMAGE_FILE_HEADER是PE文件头,c语言的定义是这样的:
typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics;
相关文档
最新文档