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),可以通过模块句柄访问其他的数据结构。这个初始内存弟子就是基地址。

内存中的模块代表着进程从这个可执行文件中所需要的代码,数据,资源,输入表,输出表以及其他有用的数据结构所使用的内存都放在一个连续的内存块中,编程人员只要知道装载程序文件映像到内存的基地址即可。在32位系统中可以直接调用GetModuleHandle以取得指向DLL的指针,通过指针访问DLL module的内容,例如:

HMODULE GetmoduleHandle(LPCTSRT lpModuleName);

当调用该函数时,传递一个可执行文件或者DLL文件名字字符串。如果系统找到该文件,则返回该可执行文件的或者DLL文件映像加载到的基地址。也可以调用GetModuleHandle,传递NULL参数,则返回调用的可执行文件的基地址。

2)相对虚拟地址

在可执行文件中,有相当多的地方需要指定内存的地址。例如:引用全局变量时,需要指定它的地址。PE文件尽管有一个首选的载入地址(基地址),但是他们可以载入到进程空间的任意地方,所以不能依赖与PE的载入点。由于这个原因,必须有一个方法来指定一个地址而不是依赖于PE载入点。

为了在PE文件中避免有确定的内存地址,出现了相对虚拟地址(Relative Virtual Addres,简称RVA)的概念。RVA只是内存中的一个简单的相对于PE文件装入地址的偏移地址,它是一个“相对”地址,或者称位“偏移量”地址。例如:假设一个EXE文件从地址40000h处载入,并且它的代码区块开始于4010000h,代码区的RVA将是:

目标地址401000h ——转入地址400000h则RVA=1000h。

将RVA地址转换成真实地址,只需简单的翻转这个过程:将实际装入地址加上RVA即可得到实际的内存地址。顺便一提,在PE用语里,实际的内存地址被称作虚拟地址(Vritual Address,简称VA),另外也可以把虚拟地址想象为加上首选装入地址的RVA。不要忘了前面提到的装入地址等同于模块句柄,它们之间的关系如下:

虚拟地址(VA)=基地址(ImageBase)+相对虚拟地址(RVA)

3)文件偏移地址

当PE文件存储在磁盘上时,某个数据的位置相对于文件头的偏移量也称文件偏移地址(FileOffset)或者物理地址(RAW Offset)。文件偏移地址从PE文件的第一个字节开始计数,起始为零。用十六进制工具比如:winhex,hexworkshop都可以查看。注意这个物理地址和虚拟地址的区别,物理地址是文件在磁盘上相对于文件头的地址,而虚拟地址是PE可执行程序加载在内存中的地址。

0x02 几个重要头部信息介绍

接下来介绍MS-DOS头部信息,PE文件头信息及几个重要字段。

1)MS-DOS头部

每个PE文件是以一个DOS程序开始的,有了它,一旦程序在DOS下执行,DOS就能辨别出这是个有效的执行体,然后运行紧随MZ header(后面会介绍)之后的DOS stub(DOS块)。DOS stub实际上是一个有效的EXE,在不支持PE文件格式的操作系统中,它将简单显示一个错误提示,类似于字符串“This Program cannot be run in MS-DOS”。用户通常对DOS stub 不感兴趣,因为大多数情况下他们由汇编器自动生成。平常把DOS stub和DOS MZ头部合称为DOS文件头。

PE文件的第一个字节起始于一个传统的MS-DOS头部,被称作IMAGE_DOS_HEADER。其IMAGE_DOS_HEADER的结构如下(左边的数字是到文件头的偏移量):

IMAGE_DOS_HEADER STRUCT

{

+0h WORD e_magic   // Magic DOS signature MZ(4Dh 5Ah)     DOS可执行文件标记

+2h   WORD  e_cblp  // Bytes on last page of file

+4h WORD  e_cp   // Pages in file

+6h WORD  e_crlc   // Relocations

+8h WORD  e_cparhdr   // Size of header in paragraphs

+0ah WORD  e_minalloc  // Minimun extra paragraphs needs

+0ch WORD  e_maxalloc  // Maximun extra paragraphs needs

+0eh WORD  e_ss    // intial(relative)SS value      DOS代码的初始化堆栈SS

+10h WORD  e_sp    // intial SP value                 DOS代码的初始化堆栈指针SP

+12h WORD  e_csum    // Checksum

+14h WORD  e_ip    //    intial IP value                     DOS代码的初始化指令入口[指针IP]

+16h WORD  e_cs    // intial(relative)CS value                    DOS代码的初始堆栈入口

+18h WORD  e_lfarlc    // File Address of relocation table

+1ah WORD  e_ovno        //    Overlay number

+1ch WORD  e_res[4]    // Reserved words

+24h WORD  e_oemid    //    OEM identifier(for e_oeminfo)

+26h WORD      e_oeminfo   //    OEM information;e_oemid specific

+29h WORD  e_res2[10]   //    Reserved words

+3ch DWORD   e_lfanew     // Offset to start of PE header             指向PE文件头

} IMAGE_DOS_HEADER ENDS

这个结构中有两字段很重要,一个是e_magic,一个是e_lfanew。e_magic(一个字大小)字段需要被设置为5A4Dh这个也是PE程序载入的重要标志,这个值非常有意思,他们对应的字符分别位Z和M,是为了纪念MS-DOS的最初创建者Mark Zbikowski而专门设置的,由于在hex编辑器中显示是由低位到高位故显示为4D5Ah,刚好是创建者的名字缩写。另一个字段是e_lfanew。这个字段表示的是真正的PE文件头部相对偏移地址(RVA),它指出了真正PE头部文件偏移位置。它占用四个字节,位于文件开始偏移的3ch字节中。

下面我将用hexworkshop打开一个pe文件向大家展示一下上面这段话的含义。

第一张图说明的就是IMAGE_DOS_HEADER的第一个字段e_magic的值与地址。第二张图就是上面所讲的第二个关键字段e_fannew字段的值(注意:不同的PE程序这个值可能不一样,但原理一样),这个值就是PE头文件的起始偏移量。

2)PE文件头文件

相对于MS-DOS头文件,PE头文件PEheader要复杂的多,下面将详细讲解其中的几个字段。

紧跟着DOS头文件下面的就是peheader。PEheader是PE相关结构NT映像头(IMAGE_NT_HEADER)的简称,其中包含许多PE装载器用到的重要字段。执行体在支持PE文件结构的操作系统执行时,PE装载器将IMAGE_DOS_HEADER结构中的e_fanew字段找到PEheader的起始偏移量,加上基址得到PE文件头的指针:

PNTHeader=IMAGBase+dosHeader->e_lfanewr(其实就是去字段e_lfanew的值)。

下面来讨论IMAGE_NT_HEADER的结构,它是由三个字段组成(左边的数字是PE文件头的偏移量):IMAGE_NT_HEADER STRUCT

{

+0h Signature  DWORD              //PE文件标志

+4h FileHeader IMAGE_FILE_HEADER  //文件头初始偏移地址

+18 optionalHeader IMAGE_OPTION_HEADER //另一个重要头部初始偏移地址

} IMAGE_NT_HEADER ENDS

下面对这三个字段逐个详细分析:

  1. Signature字段

这个字段是PE文件的标志字段,通常设置成00004550h,其ASCII码为PE00,这个字段是PE文件头的开始,前面的DOS_HEADER结构中的字段e_lfanew字段就是指向这里。

2.IMAGE_FILE_HEADER字段

这个字段也是包含几个字段结构,它包含了PE文件的一些基本信息,最重要的是其中一个域指出了IMAGE_OPTIONAL_HEADER的大小。

typedef struct _IMAGE_FILE_HEADER {

WORD Machine;//运行平台

WORD NumberOfSections;//文件的区块数目

DWORD TimeDateStamp;//文件创建的用时间戳标识的日期

DWORD PointerToSymbolTable;//指向符号表(用于调试)

DWORD NumberOfSymbols;//符号表中符号的个数

WORD SizeOfOptionalHeader;//IMAGE_OPTIONAL_HEADER32结构大小

WORD Characteristics;//文件属性

} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

上图标出七个字段的位置及各自的值。

1)Machine字段,表示目标CPU 的类型。

几个常见的及其标识如下:

机器              标识

Intel I386          14ch

MIPS R3000        162h

Alpha AXP          184h

Power PC           1F0h

MIPS R4000         184h

根据以上信息我们知道这个PE文件要运行在Intel I386机器上。

2)NumberOfSection,标识区块的数目,关于区块后面会详细讲。

3)TimeDateStamp

这个字段没啥好说的,指的就是PE文件创建的事件,这个时间是指从1970年1月1日到创建该文件的所有的秒数。

4)PointerToSymbolTable。这个字段用的比较少,略

5)NumberOfSymbol。这个字段也用得很少,略

6)SizeOfOptionalHeader:紧跟着IMAGE_FILE_HEADER后面的数据大小,这也是一个数据结构,它叫做IMAGE_OPTIONAL_HEADER,其大小依赖于是64位还是32位文件。32位文件值通常是00EOh,对于64位值通常为00F0h。

7)Characteristics:文件属性,普通EXE文件这个字段值为010fh,DLL文件这个字段一般是0210h。

下一篇将从字段IMAGE_OPTIONAL_HEADER讲起。

转载于:https://www.cnblogs.com/2f28/p/9800992.html

PE文件格式详解(一)相关推荐

  1. 【破解教程】PE文件格式详解(上)

    PE文件格式详解(上) 摘要 Windows NT 3.1引入了一种名为PE文件格式的新可执行文件格式.PE文件格式的规范包含在了MSDN的CD中(Specs and Strategy, Specif ...

  2. PE 文件格式 详解 一

    内容引用自:看雪<逆向工程原理>,http://www.blogfshare.com/pe-header-one.html . 如有错误,欢迎留言. 1.  PE文件是windows操作系 ...

  3. PE文件格式详解(7)

    调试信息段,.debug 调试信息位于.debug段之中,同时PE文件格式也支持单独的调试文件(通常由.DBG扩展名标识)作为一种将调试信息集中的方法.调试段包含了调试信息,但是调试目录却位于早先提到 ...

  4. PE文件格式详解(3)

    PE可选头部 PE可执行文件中接下来的224个字节组成了PE可选头部.虽然它的名字是"可选头部",但是请确信:这个头部并非"可选",而是"必需&quo ...

  5. [系统安全] PE文件格式详解1

    文章目录 PE文件概述 PE文件相关各类地址 MS-DOS头① DOS Stub② PE头③ Signature字段 IMAGE_FILE_HEADER结构体 IMAGE_OPTIONAL_HEADE ...

  6. PE文件格式详解(手工实现一个可执行文件)

    [转载文章-看雪学院]非常经典 http://www.pediy.com/kssd/index.html 其实还是很多细节的地方没弄懂,保存下来,认真分析分析. [文章标题]: 手写可执行程序 [文章 ...

  7. PE文件格式详解(二)

    0x00 前言 上一篇讲到了PE文件头的中IMAGE_FILE_HEADER结构的第二个结构,今天从IMAGE_FILE_HEADER中第三个结构sizeOfOptionalHeader讲起.这个字段 ...

  8. PE文件格式详解(八)

    0x00 前言 前面了解了PE文件的输入和输出,今天来看看另一个重要的结构--资源.资源结构是很典型的树形结构,层层查找,最终找到资源位置. 0x01 资源结构介绍 Windows程序的各种界面成为资 ...

  9. PE文件详解(教程1-7)

    PE文件详解(教程1-7) ========================================= PE教程1: PE文件格式一览 PE 的意思就是 Portable Executable ...

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

    by evil.eagle 转载请注明出处. http://blog.csdn.net/evileagle/article/details/11903197 在PE文件结构详解(一)基本概念里,解释了 ...

最新文章

  1. Py之Data Base:Python和数据库的那些嘻嘻哈哈事详细攻略
  2. 搜狗2012.9.23校园招聘会笔试题
  3. 【网络通信与信息安全】之深入解析TCP的“拥塞控制”原理
  4. Delphi格式化函数Format、FormatDateTime和FormatFloat详解
  5. Jmeter 压测基础笔记
  6. Java BigDecimal 转换,除法陷阱(转)
  7. URAL 1664 Pipeline Transportation
  8. NMath应用教程:如何通过代码访问底层数据和应用函数
  9. Java期末重点复习 | 文本版
  10. PCA、最小平方差等中用拉格朗日求极值时对常见的一个f(x)=X'A'AX求导的证明
  11. C++ 优先队列 priority_queue 使用篇
  12. 计算机音乐雅俗共赏,“雅俗共赏”与音乐教育
  13. 守望先锋ptr服务器位置,守望先锋测试服怎么进 守望先锋ptr怎么进
  14. 使用Arduino和蓝牙实现语音控制LED指示灯
  15. 计算机导论题目2020,计算机网络论文题目_
  16. 郊区春游(NC16122)状压dp
  17. 视频加封面制作步骤,全部视频添加不同图片封面图
  18. dede织梦CMS安装页面出现dir的通用安装教程
  19. python做生日快乐_python如何实现生日快乐代码
  20. cmatrix黑客帝国屏保

热门文章

  1. mysql记录的增删改查、单表查询
  2. python接受前端传递的参数
  3. VB 2010中Excel文件处理的一个奇怪问题
  4. 排序(2)二分排序、快速排序、归并排序
  5. 蓝牙天线的介绍与选用
  6. 搭建高性能计算环境(九)、应用软件的安装之gaussian 09
  7. 一键安装配置Redis详解
  8. 简明 jieba 中文分词教程
  9. 【目标检测】基于帧差法+Vibe算法实现车辆行人检测matlab源码
  10. 【预测模型-ELAMN预测】基于哈里斯鹰算法优化ELMAN神经网络实现数据回归预测matlab代码