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文件结构分析

实验二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文件格式

WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
么正确的开始地址是0x401560。如果可执行程序调入0x100000处,则开始地址为0x101560。
因为PE文件的每一个段不必按同样的边界对齐方式调入,因此RVA地址的计算变得比较复
杂。例如,在文件中每一个段往往按512个字节的方式对齐,而在内存中可能以4096字节的方
式对齐。这方面的介绍可见下面的“SectionAlignment”、“FileAlignment”。举个例子,
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
三、文件头(File Header)
通过DOS头,你可以找到一个叫做IMAGE_FILE_HEADER的结构,如下;下面我分别介绍一
下。
typedef struct _IMAGE_FILE_HEADER {
中只有大约100个字节的代码,只输出一个诸如“this program needs windows NT ”之类的
信息。
你可以通过一个叫做IMAGE_DOS_HEADER的结构来识别一个合法的DOS头。这个结构的头两
个字节一定是“MZ”(#define IMAGE_DOS_SIGNATURE "MZ")。怎么才能找到PE开始的标志呢
PE文件头简析及输入表、输出表的分析

PE文件头简析及输入表、输出表的分析2008年01月13日星期日 22:50PE文件头简析及输入表、输出表的分析前两天由于做个免杀,需要对输入表做些改变,所以又重新看了pe文件的结构尤其是输入表及输出表的一些细节方面,做个笔记,方便自己以后翻看,也给大家提个方便,呵呵!1、PE文件格式文件尾___________________________________________________________________Code View调试信息 |COFF 符号表 | 调试信息COFF 行号 |------------------------------------------------------------------.reloc |.edata | 块(Section) .data |.text |---------------------------------------------------------------------------------------------------IMAGE_SECTION_HEADER |IMAGE_SECTION_HEADER | 块表(Section Table)IMAGE_SECTION_HEADER |IMAGE_SECTION_HEADER | //对应.text块---------------------------------------------------------------------------------------------------------数据目录表 | //包含在可选映像头中,包含输出\入表信息 IMAGE_OPTIONAL_HEADER32 | 可选映像头IMAGE_FILE_HEADER | 文件映像头"PE",0,0 | pe文件标识(pe文件头包含三个部分)---------------------------------------------------------------------------------------------------------DOS stub |DOS 'MZ' HEADER | 该字段中的e_lfanew字段指向pe头 ---------------------------------------------------------------------------------------------------------文件头说明:01、输入表、输出表的位置:在pe头中可选映像头字段中数据目录表字段中,相对于pe文件标识处的偏移分别为:+80h、+78h;(其中pe文件标识的位置在DOS 'MZ' HEADER字段中的e_lfanew指出,该字段相对于文件开始的偏移为+3Ch,4个字节);02、在用例子说明时用c32asm打开,其中的偏移均为文件在磁盘上存储的物理偏移,而查看的值均为给出的各个地址的RVA,转化方法入下:查到的RVA值-VOffset(可由lordpe查看)+ROffset 得到的就是可以c32asm中的偏移2、上面对pe文件格式做了简要介绍,下面主要分析输入表和输出表:输入表篇:概念不做介绍,位置上面已经给出,呵呵输入表的结构:输入表是以一个IMAGE_IMPORT_DESCRIPTOR(IID)数组开始,一个程序要调用几个dll就会有几个IID项,即每个IID对应于一个dllIID结构:IMAGE_IMPORT_DESCRIPTOR structunion{DWORD Characteristics ; ;00hDWORD OriginalFirstThunk; // 注释1};TimeDateStamp DWORD ;04h // 时间标志,可以忽略;ForwarderChain DWORD ;08h // 正向链接索引,一般为0,当程序引用一个dll中的api,而这个api又引用其它dll中的api时用;Name DWORD ;0Ch //DLL名字的指针,以00结尾的ASCII字符的RVA地址;FirstThunk DWORD ;10h // 注释2IMAGE_IMPORT_DESCRIPTOR ends注释 1:该值为一个 IMAGE_THUNK_DATA数组的RVA,其中的每个指针都指向IMAGE_IMPORT_BY_NAME结构。
深入剖析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文件结构详解1 摘要Windows NT 3.1引入了一种名为PE文件格式的新可执行文件格式。
PE文件格式的规范包含在了MSDN的CD中(Specs and Strategy, Specifications, Windows NT File Format Specifications),但是它非常之晦涩。
然而这一的文档并未提供足够的信息,所以开发者们无法很好地弄懂PE格式。
本文旨在解决这一问题,它会对整个的PE文件格式作一个十分彻底的解释,另外,本文中还带有对所有必需结构的描述以及示范如何使用这些信息的源码示例。
为了获得PE文件中所包含的重要信息,我编写了一个名为PEFILE.DLL的动态链接库,本文中所有出现的源码示例亦均摘自于此。
这个DLL和它的源代码都作为PEFile示例程序的一部分包含在了CD中(译注:示例程序请在MSDN中寻找,本站恕不提供),你可以在你自己的应用程序中使用这个DLL;同样,你亦可以依你所愿地使用并构建它的源码。
在本文末尾,你会找到PEFILE.DLL的函数导出列表和一个如何使用它们的说明。
我觉得你会发现这些函数会让你从容应付PE文件格式的。
2 介绍Windows操作系统家族最近增加的Windows NT为开发环境和应用程序本身带来了很大的改变,这之中一个最为重大的当属PE文件格式了。
新的PE文件格式主要来自于UNIX操作系统所通用的COFF规范,同时为了保证与旧版本MS-DOS及Windows操作系统的兼容,PE文件格式也保留了MS-DOS中那熟悉的MZ头部。
在本文之中,PE文件格式是以自顶而下的顺序解释的。
在你从头开始研究文件内容的过程之中,本文会详细讨论PE文件的每一个组成部分。
很多解决PE文件格式的工作和直接观看数据有关。
例如,要弄懂导入地址名称表是如何构成的,我就得同时查看.idata段头部、导入映像数据目录、可选头部以及当前的.idata段实体,而EXEVIEW.EXE就是查看这些信息的最佳示例。
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文件结构

节表的数据
第一个结构
最后一个结构
对齐填充数据
偏移转换计算 一
入口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文件格式详解(一)

PE文件格式详解(一)0x00 前言PE文件是portable File Format(可移植文件)的简写,我们比较熟悉的DLL和exe文件都是PE文件。
了解PE文件格式有助于加深对操作系统的理解,掌握可执行文件的数据结构机器运行机制,对于逆向破解,加壳等安全方面方面的同学极其重要。
接下来我将通过接下来几篇详细介绍PE文件的格式。
0x01 基本概念PE文件使用的是一个平面地址空间,所有代码和数据都被合并在一起,组成一个很大的组织结构。
文件的内容分割为不同的区块(Setion,又称区段,节等),区段中包含代码数据,各个区块按照页边界来对齐,区块没有限制大小,是一个连续的结构。
每块都有他自己在内存中的属性,比如:这个块是否可读可写,或者只读等等。
认识PE文件不是作为单一内存映射文件被装入内存是很重要的,windows加载器(PE加载器)便利PE文件并决定文件的哪个部分被映射,这种映射方式是将文件较高的偏移位置映射到较高的内存地址中。
当磁盘的数据结构中寻找一些内容,那么几乎能在被装入到内存映射文件中找到相同的信息。
但是数据之间的位置可能改变,其某项的偏移地址可能区别于原始的偏移位置,不管怎么样,所表现出来的信息都允许从磁盘文件到内存偏移的转换,如下图:PS:PE文件头以下的地址无论在内存映射中还是在磁盘映射中都是一样的,当内存分页和磁盘分页一致时无需进行地址转换,只有当磁盘分页和内存分页不一样时才要进行地址转化,这点很重要,拿到PE文件是首先查看分页是否一致。
前两天一直没碰到内存和磁盘分页不一样的,所以这个点一直没发现,今天特来补上。
下面要介绍几个重要概念,分别是基地址(ImageBase),相对虚拟地址(Relative Virtual Address),文件偏移地址(File Offset)。
1)基地址定义:当PE文件通过Windows加载器被装入内存后,内存中的版本被称作模块(Module)。
映射文件的起始地址被称作模块句柄(hMoudule),可以通过模块句柄访问其他的数据结构。
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文件格式详解

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文件格式中的哪些重要信息。
PE文件结构

PE文件结构总体层次分布
· DOS MZ Header
所有 PE文件(甚至32位的DLLs)必须以简单的DOS MZ header开始,它是一个IMAGE_DOS_HEADER结构。有了它,一 旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随MZ Header之后的DOS Stub。
PE文件格式要用到RVA,主要是为了减少PE装载器的负担。因为每个模块都有可能被重载到任何虚拟地址空间,如果让PE 装载器修正每个重定位项,这肯定是个梦魇。相反,如果所有重定位项都使用RVA,那么PE装载器就不必操心那些东西了, 即 它只要将整个模块重定位到新的起始VA。这就像相对路径和绝对路径的概念:RVA类似相对路径,VA就像绝对路径。
2.2.1 PE文件结构布局 找到文件中某一结构信息有两种定位方法。第一种是通过链表方法,对于这种方法,数据在文件的存放位置比较自由。第二种 方法是采用紧凑或固定位置存放,这种方法要求数据结构大小固定,它在文件中的存放位置也相对固定。在PE文件结构中同 时采用以上两种方法。
因为在PE文件头中的每个数据结构大小是固定的,因此能够编写计算程序来确定某一个PE文件中的某个参数值。在编写程序 时,所用到的数据结构定义,包括数据结构中变量类型、变量位置和变量数组大小都必须采用Windows提供的原型。图2.1所 示的PE文件结构的总体层次分布如下:
PE文件结构详解

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文件通过导出表指明自己导 出那些函数,通过导入表指明需要从哪些模块导入哪些函数。导入和导出表的具体结构会在单独的文章中 详细解释。
pe文件格式总体结构

pe文件格式总体结构
PE文件格式(Portable Executable)是Windows操作系统的可执行文件格式,其总体结构包括以下几个部分:
1.DOS头:PE文件的最前面是DOS头,用于兼容DOS系统。
它包
含了文件标识符、魔数(0x5A4D,即MZ)以及DOS头长度等
信息。
2.PE头:紧接着DOS头的是PE头,它包含了PE文件的元数据
信息,如文件标志、机器类型、节区数量、可选头大小等。
3.可选头:可选头包含了PE文件的属性、入口点地址、基址等
信息。
它是一个可选部分,某些PE文件可能没有这个部分。
4.节区:PE文件由多个节区组成,每个节区包含了一部分程序
代码或数据。
每个节区都有自己的头部信息,用于描述节区的属性。
以上是PE文件格式的总体结构,具体细节可能因不同的PE文件而有所差异。
pe文件结构

我们这里将不依赖任何编译器,仅仅使用一个十六进制编辑器逐个字节的手工编写一个可执行程序。
以这种方式讲解PE结构,通过这个过程读者可以学习PE结构中的PE头、节表以及导入表相关方面的知识。
为了简单而又令所有学习程序开发的人感到亲切,我们将完成一个Hello World! 程序。
功能仅仅是运行后弹出一个消息框,消息框的内容是Hello World!。
首先了解一下Win32可执行程序的大体结构,就是通常所说的PE结构。
如图1所示PE结构示意图:图1 标准PE结构图由图中可以看出PE结构分为几个部分:MS-DOS MZ 头部:所有PE文件必须以一个简单的DOS MZ 头开始。
有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随MZ header 之后的DOS程序。
以此达到对Dos系统的兼容。
(通常情况DOS MZ header总共占用64byte)。
MS-DOS 实模式残余程序:实际上是个有效的EXE,在不支持PE文件格式的操作系统中,它将简单显示一个错误提示,大多数情况下它是由汇编编译器自动生成。
通常,它简单调用中断21h,服务9来显示字符串"This program cannot run in DOS mode"。
(在我们写的程序中,他不是必须的,可以不予以实现,但是要保留其大小,大小为112byte,为了简洁,可以使用00来填充。
)PE文件标志:是PE文件结构的起始标志。
(长度4byte, Windows程序此值必须为0x50450000)PE文件头:是PE相关结构 IMAGE_NT_HEADERS 的简称,其中包含了许多PE装载器用到的重要域。
执行体在支持PE文件结构的操作系统中执行时,PE装载器将从DOS MZ header中找到PE header的起始偏移量,跳过了MS-DOS 实模式残余程序,直接定位到真正的文件头PE header,长度20byte。
非托管PE文件资源结构剖析

非托管PE文件资源结构剖析摘要简单介绍了PE文件的结构,介绍了怎样从PE中找到资源块,详细介绍了资源的三层结构,以及三层结构里面的一些细节。
关键词PE文件;资源段;资源结构1 PE文件结构简介PE(Portable Executable)文件是Windows操作系统上的程序文件,常见的EXE、DLL、SYS等都是PE文件。
PE文件有固定的结构,PE文件的结构如图1,所有PE文件都是由MS-DOS文件头,MS-DOS Stub,PE文件头,段表,以及一组段体组成。
段体包括代码段、数据段、输入表段、输出表段,以及资源段等。
MS-DOS文件头MS-DOS Stub PE文件头段表代码段数据段资源段输入表输出表…图1 PE文件结构图资源段是段表下的某个段。
我们可以通过MS-DOS文件头,PE文件头和段表的数据找到资源段的位置。
2找到PE文件资源段可以通过下面的步骤来查找PE资源段。
1)根据MS-DOS文件头结构的成员e_lfanew,得到PE文件头在文件中的位置;2)确定PE件头在文件中的位置之后,就可以确定PEHeader 中的成员FileHeader 和成员OptionalHeader 在文件中的位置。
根据FileHeader中的成员NumberOfSections 的值,就可以确定文件中段的数目,也就是段表数组中元素的个数;3)PE Header 在文件中的位置加上PE Header 结构的大小就可以得到段表在文件中的开始位置;4)取得PE Header 中的Optional Header 中的DataDirectory 数组中的第三项的成员VirtualAddress 的值,这个值就是在内存中资源段的RV A。
然后根据段的数目,遍历段表数组。
找到其中成员VirtualAddress 等于上面求得的RV A的数组项,该数组项就是资源段的段表,其成员PointerToRawData 就是资源段在文件中的位置。
PE文件结构剖析

PE文件结构剖析大家都很清楚,了解可执行文件的结构有多么的重要,DOS下如此,Windows下也同样如此。
如果你想加密程序,编写病毒等,了解PE文件结构必是不可缺少的。
大家也可能见到很多这方面的资料,但都是从理论上解说一下,很少见到拿一个具体文件开刀的。
这里,我就用前面“系列4”中的文件4.EXE为例来剖析一下PE文件格式,因时间关系,不可能一下子就写的很完善,如可行,以后再慢慢补来。
===============================================================对于本文件,红色外框将文件分成4个部分,各部分的内容是:Ⅰ - 文件头;Ⅱ - 代码段;.text sectionⅢ - 引入表;.rdata sectionⅣ - 数据段;.data section可以看出,每部分都有大量的垃圾数据,用绿色的叉号进行标注。
我们先从整体看一下文件的结构:(要结合PE剖析图来看)----------------------------------------------------------1、IMAGE_DOS_HEADER虽然你这是Windows下的程序,但保不准别人会拿它到DOS下执行,当然肯定不是想象的结果啦。
该文件头和DOS下可执行文件的文件头基本上是一样的,所以你也可以认为它是一个标准的DOS下的EXE文件,只不过程序执行的结果是显示一个错误信息:This program ca nnot be run in DOS mode.,意思是这是Windows下的程序,到Windows下用吧!该结构的最后一个元素e_lfanew指示PE文件头的位置,是个重要的数据。
对本例,该元素位于文件偏移量是3C的位置,其值是000000B0。
2、dos下执行时的程序部分3、dos执行时显示的错误信息4、垃圾数据-----------------------------------------------------------就是PE文件头啦,它是一个IMAGE_NT_HEADERS STRUCT结构5、PE文件标记,db 'PE',0,06、是一个IMAGE_FILE_HEADER结构7、是一个IMAGE_OPTIONAL_HEADER结构8、是一个IMAGE_DATA_DIRECTORY结构数组,共16项9、是一个IMAGE_SECTION_HEADER结构数据,项数由结构6中 NumberOfSections 确定。
PE文件格式--------------基本结构信息

附加数据其它节区.reloc节区.rsrc节区.data节区.text节区节表数据目录选项头文件头PE标志DOS stub DOS头PE文件格式--------------基本结构信息一)win32下PE文件格式的文件有:*.exe;*.dll;*.scr;*.fon;*.drv;*.sys二)pe文件基本结构格式说明:1)dos头:0000 0000:4D 5A0000 0010:0000 0020:0000 0030: 3C xx xx xxIMAGE_DOS_HEADER struc+00h e_magic: word ;dos标志MZ,常量表示IMAGE_DOS_SIGNATURE ...+3ch e_lfanew: dword;指向pe文件头IMAGE_DOS_HEADER ends2)dos stub在dos执行的程序代码。
方法是3)pe文件头定位:文件开始地址+IMAGE_DOS_HEADER.e_lfanew数据结构:IMAGE_NT_HEADER struc+00h Signature: dword ;pe标志50 45 00 00,IMAGE_NT_SIGNATURE+04h FileHead: IMAGE_FILE_HEADER+18h OptionalHead: IMAGE_OPTIONAL_HEADER32IMAGE_NT_HEADER ends4)pe标志0000 0D00: 50 45 00 00+00h Signature: dword ;PE标志,常量表示IMAGE_NT_SIGNATURE5)文件头0000 0D00: 50 45 00 00 04 xx 06 xx 08 xx xx xx0000 0D10: 14 xx 16 xx数据结构:IMAGE_FILE_HEADER struc+04h Machine: word ;运行平台+06h NumberOfSections: word ;节区数量+08h TimeDateStamp: dword ;从1969年12月31日下午4点以来的秒数...+14h SizeOfOptionalHeader: word ;选项头大小+16h Characteristics: word ;文件属性,exe为 dll为多少等IMAGE_FILE_HEADER ends6)选项头0000 0D00: 50 45 00 00 04 xx 06 xx 08 xx xx xx0000 0D10: 14 xx 16 xx0000 0D20: 28 xx xx xx0000 0D30: 34 xx xx xx 38 xx xx xx 3C xx xx xx0000 0D40:0000 0D50: 50 xx xx xx 54 xx xx xx 5C xx xx xx0000 0D60:0000 0D70: 78 xx xx xx xx xx xx xx数据结构:IMAGE_OPTIONAL_HEADER32 struc+28h AddressOfEntryPoint: dword ;入口地址+34h ImageBase: dword ;建议装载地址+38h SectionAlignMent: dword ;内存对齐大小+3ch FileAlignMent: dword ;文件对齐大小+50h SizeOfImage dword ;文件装入到内存后的总尺寸,即内存对齐后的总大小+54h SizeOfHeaders dword ;所有头 + 区块表的尺寸大小+5ch SubSystem: wrod ;子系统+78h DataDirectory: IMAGE_DATA_DIRECTORY ;数据目录IMAGE_OPTIONAL_HEADER32 ends界面子系统的取值和含义取值Windows.inc中的预定义值含义0IMAGE_SUBSYSTEM_UNKNOWN未知的子系统1IMAGE_SUBSYSTEM_NATIVE 不需要子系统(如驱动程序)2IMAGE_SUBSYSTEM_WINDOWS_GUI Windows图形界面3IMAGE_SUBSYSTEM_WINDOWS_CUI Windows控制台界面5IMAGE_SUBSYSTEM_OS2_CUI OS2控制台界面7IMAGE_SUBSYSTEM_POSIX_CUI POSIX控制台界面8IMAGE_SUBSYSTEM_NATIVE_WINDOWS不需要子系统9IMAGE_SUBSYSTEM_WINDOWS_CE_GUI Windows CE图形界面7)数据目录IMAGE_DATA_DIRECTORY strucVirtualAddress: dword ;RVA起始地址 VirtualSize: dword ;数据块大小IMAGE_DATA_DIRECTORY ends数据目录列表的含义索引索引值在Windows.inc中的预定义值对应的数据块0IMAGE_DIRECTORY_ENTRY_EXPORT导出表1IMAGE_DIRECTORY_ENTRY_IMPORT导入表2IMAGE_DIRECTORY_ENTRY_RESOURCE资源3IMAGE_DIRECTORY_ENTRY_EXCEPTION 异常(具体资料不详)4IMAGE_DIRECTORY_ENTRY_SECURITY 安全(具体资料不详)5IMAGE_DIRECTORY_ENTRY_BASERELOC重定位表6IMAGE_DIRECTORY_ENTRY_DEBUG调试信息7IMAGE_DIRECTORY_ENTRY_ARCHITECTURE版权信息8IMAGE_DIRECTORY_ENTRY_GLOBALPTR 具体资料不详9IMAGE_DIRECTORY_ENTRY_TLS Thread Local Storage10IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 具体资料不详11IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 具体资料不详12IMAGE_DIRECTORY_ENTRY_IAT 导入函数地址表13IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 具体资料不详14IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 具体资料不详15未使用15未使用8)节表多个IMAGE_SECTION_HEADER组成节表。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
文件偏移和RVA的关系
节数据n 文件 偏移 节数据n …… 节数据1 节表 PE头 DOS块 …… 节数据1 节表 PE头 DOS块 offset 0 相对虚拟地址 Relative Virtual Address RVA
磁盘文件中 映射 内存中
IMAGE_DATA_DIRECTORY
• • • • IMAGE_DATA_DIRECTORY STRUCT VirtualAddress DWORD Size DWORD IMAGE_DATA_DIRECTORY ENDS
找到导入表、导出表
四、PE结构简单应用
• 粗略分辨dll/exe、
– 文件头中的Characteristics字段 – 位于PE头16h偏移处 – 该字段占用2个字节,16个bit位 – 该字段定义是按照bit位来定义的
Characteristics字段
数据位 • • • • • • • • • • • • • • • • 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 代表的含义 ;文件中不存在重定位信息 ;文件是可执行的 ;不存在行信息 ;不存在符号信息 ;被舍弃,值为“0” ;应用程序可以处理大于2GB的地址空间 ;保留,留以后扩展 ;小尾方式 ;只在32位平台上运行 ;不包含调试信息 ;不能从可移动盘(如软盘、光盘)运行 ;不能从网络运行 ;系统文件(如驱动程序),不能直接运行 ;这是一个 DLL 文件 ;文件不能在多处理器上计算机上运行 ;大尾方式
导入表
• • • • • • • • • • IMAGE_IMPORT_DESCRIPTOR STRUCT union Characteristics DWORD OriginalFirstThunk DWORD ends TimeDateStamp DWORD ForwarderChain DWORD Name1 DWORD FirstThunk DWORD IMAGE_IMPORT_DESCRIPTOR ENDS ? ? ;指向被调函数名的指针数组的指针 ? ? ? ? ;时间日期记录,无实际意义,可忽略 ;正向连接索引 ;指向被调用dll的名字指针数组的指针 ;指向被调函数地址的指针数组的指针
;DOS代码的初始化堆栈段 ;DOS代码的初始化堆栈指针
;DOS代码的入口IP ;DOS代码的入口CS
;指向PE文件的头部
DOS头结构图示
DOS头,40h e_lfanew
显示数据
实际数据
00 01 00 00
00 00 01 00
DOS块图示
选中的数据为dos块
PE头组成
• PE头的三个构成部分
;导出表 ;导入表 ;资源 ;重定位表 ;调试信息 ;版权信息 ;导入函数地址表
可选头数据
入口点
导入表
导出表
节表
• • • • • • • • • • • • • • • IMAGE_SECTION_HEADER STRUCT Name1 db IMAGE_SIZEOF_SHORT_NAME union Misc PhysicalAddress dd VirtualSize dd ends VirtualAddress dd SizeOfRawData dd PointerToRawData dd PointerToRelocations dd PointerToLinenumbers dd NumberOfRelocations dw NumberOfLinenumbers dw Characteristics dd IMAGE_SECTION_HEADER ENDS 8dup(?) ? ? ? ? ? ? ? ? ? ? ;8个字节的节表名称,如“.text/code” ; 物理地址 ;节区的真实长度 (内存中) ;节区的RVA地址 ; 物理长度,在文件中对齐后的尺寸 ;节基于文件的偏移量,在文件中的偏移 ;重定位的偏移,在OBJ文件中使用 ;行号表的偏移(供调试用) ;重定位项数目,在OBJ文件中使用 ;行号表中行号的数量 ;节在内存中的属性特征:可读,可写,可执行等等。
示例分析
获取的属性值为818E 转化成二进制数据:1000000110001110 找到有效位:15 、8 、7 、3 、2 、1 分析有效位的含义 1 文件是可执行的 2 不存在行信息 3 不存在符号信息 7 小尾方式 8 只在32位平台上运行 15 大尾方式
文件头数据信息
节数目: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
导出表
• • • • • • • • • • • • • IMAGE_EXPORT_DIRECTORY STRUCT Characteristics DWORD ? ;未使用,总是为0 TimeDateStamp DWORD ? ;文件的产生时刻 MajorVersion WORD ? ;未使用,总是为0 MinorVersion WORD ? ;未使用,总是为0 nName DWORD ? ;指向文件名的RVA nBase DWORD ? ;导出函数的起始序号 NumberOfFunctions DWORD ? ;导出函数的总数 NumberOfNames DWORD ? ;以名称导出的函数总数 AddressOfFunctions DWORD ? ;指向导出函数地址表的RVA AddressOfNames DWORD ? ;指向函数名地址表的RVA AddressOfNameOrdinals DWORD ? ;指向函数名序号表的RVA IMAGE_EXPORT_DIRECTORY ENDS
– DOS头
• 指向DOS可执行程序部分 • 指向PE结构部分
– DOS块
• DOS的可执行程序部分
DOS头结构定义
• • • • • • • • • • • • • • • • • • • • • IMAGE_DOS_HEADER STRUCT e_magic WORD ? e_cblp WORD ? e_cp WORD ? e_crlc WORD ? e_cparhdr WORD ? e_minalloc WORD ? e_maxalloc WORD ? e_ss WORD ? e_sp WORD ? e_csum WORD ? e_ip WORD ? e_cs WORD ? e_lfarlc WORD ? e_ovno WORD ? e_res WORD 4 dup(?) e_oemid WORD ? e_oeminfo WORD ? e_res2 WORD 10 dup(?) e_lfanew DWORD ? IMAGE_DOS_HEADER ENDS ;DOS可执行文件标记,固定为“MZ”
PE结构图示
二、PE结构的学习价值
• • • • 逆向分析需要其支持 是加密、解密的基础 有助于程序的编写 加深对windows系统的认识
三、PE结构分析
• PE结构主要数据块
– DOS部分 – PE头 – 节表 – 节数据
三、PE结构分析
• PE结构总览
DOS部分
• DOS部分由如下两部分构成
节表的数据
第一个结构
最后一个结构
对齐填充数据
偏移转换计算 一
入口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
? ?
;数据的起始RVA ;数据块的长度大小
• • • • • • •
0 1 2 5 6 7 12
IMAGE_DIRECTORY_ENTRY_EXPORT IMAGE_DIRECTORY_ENTRY_IMPORT IMAGE_DIRECTORY_ENTRY_RESOURCE IMAGE_DIRECTORY_ENTRY_BASERELOC IMAGE_DIRECTORY_ENTRY_DEBUG IMAGE_DIRECTORY_ENTRY_ARCHITECTURE IMAGE_DIRECTORY_ENTRY_IAT