@date: 2016/11/24

@author: dlive

​ PE (portable executable) ,它是微软在Unix平台的COFF(Common Object File Format 通用对象文集格式)的基础上制成的。

​ PE文件是指32位的可执行文件,也称PE32,64位的可执行文件称为PE+或者PE32+

​ PE文件的种类

种类 主扩展名
可执行系列 exe ,scr
驱动程序系列 sys, vxd
库系列 dll, dcx, cpl, drv
对象文件系列 obj

​ VA 虚拟地址 RVA 相对虚拟地址

​ 32位的Windows OS中,各进程分配有4GB的虚拟内存,因此进程中VA值的范围是00000000-FFFFFFFF

此处还有一个重要的图:p92 图13-2

​ 以下格式推荐使用notepad.exe为例,结合010editor中的EXE Template模板解析结果学习。

0x01 PE头

1.DOS头

​ 微软考虑PE对DOS文件的兼容性,在PE头最前面添加了IMAGE_DOS_HEADER结构体,用来扩展已有的DOS头。

# IMAGE_DOC_HEADER
WORD e_magic; // DOS签名 MZ
...
...
LONG e_lfanew; // NT Header offset

2.DOS存根(Stub)

​ 没有DOS存根,文件也能正常运行,DOS存根由代码和数据混合而成,大小不固定,其中的代码和数据是为了兼容MS-DOS,可以在MS-DOS下运行,输出“This program cannot be run in DOS mode”

3.NT头

# IMAGE_NT_HEADERS
DWORD Signature; //PE签名 50450000 =》 'PE'NULLNULL
IMAGE_FILE_HEADER FileHeader; // 文件头
IMAGE_OPTIONAL_HEADER32 OptionalHeader; //可选头,PE为IMAGE_OPTIONAL_HEADER32,PE32+ //为IMAGE_OPTIONAL_HEADER64

3.1 IMAGE_FILE_HEADER

# IMAGE_FILE_HEADER
WORD Machine; //CPU架构,Intel x86芯片的Machine码为14C
WORD NumberOfSections; //节区数量
DWORD TimeDataStamp; //记录编译器创建文件的时间,有些开发工具可设置该值,有些不可设置
...
WORD SizeOfOptionalHeader;//optional header大小,PE和PE32+的optional header大小不同
WORD Characteristics; //标识文件是否是可执行,是否为dll等信息

3.2 IMAGE_OPTIONAL_HEADER32

PE32+ 为IMAGE_OPTIONAL_HEADER64

# IMAGE_OPTIONAL_HEADER32
WORD Magic; //IMAGE_OPTIONAL_HEADER32为10B,IMAGE_OPTIONAL_HEADER64为20B
...
DWORD AddressOfEntryPoint; //EP的RVA值
...
DWORD ImageBase; //指示文件装入虚拟内存时的优先装入地址(VA)
//执行PE文件时,PE装载器先创建进程,再将文件载入内存,然后把EIP寄存器的值设置为ImageBase+AddressOfEntryPoint
DWORD SectionAlignment; //节区在内存中的最小单位, alignment(n.准线)
DWORD FileAlignment; //节区在磁盘文件中的最小单位
//磁盘文件或内存的节区大小必定为FileAlignment或SectionAlignment的整数倍
...
DWORD SizeOfImage; //PE Image在虚拟内存中所占空间的大小,一般而言文件大小和加载到内存中的大小是不同的
DWORD SizeOfHeader; //整个PE头的大小,该值必须是FileAlignment的整数倍
WORD Subsystem; //区分系统驱动文件(*.sys)与普通可执行文件(*.exe,*.dll)
DWORD NumbersOfRvaAndSizes; //用来指定DataDirectory数组的个数
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//后面几章会单独讲解其中重要的几项: ------------------------ DataDirectory[] ------------------------
DataDirectory[0] = EXPORT Directory
DataDirectory[1] = IMPORT Directory
DataDirectory[2] = RESOURCE Directory
...
...
DataDirectory[9] = TLS Directory
...
...

4.节区头

节区头中定义了各节区属性。

PE文件中的code, data, resource等按照属性分类存储在不同节区。

PE文件格式的设计者把具有相似属性的数据统一保存砸一个称为节区的地方,然后需要把各节区属性记录在节区头中(节区属性中有文件/内存的起始位置,大小,访问权限等)

类别 访问权限
code r-x
data rw-
resource r--
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//节区名,如.text,.code,但是PE规范未明确规定节区Name,可以                                    //向其中放入任何值,所以Name的值仅供参考
union {
DWORD PhysicalAddress;
DWORD VirtualSize; //内存中节区所占大小
} Misc;
DOWRD VirtualAddress;//内存中节区起始地址(RVA)
DOWRD SizeOfRawData; //磁盘文件中节区所占大小,和VirtualSize一般具有不同的值,即磁盘中和内存中节区 //大小不同
DOWRD PointerToRawData; //磁盘文件中节区起始位置
...
DWORD Charateristics; //节区属性,是否包含代码,是否包含初始化/未初始化数据,可读/可写/可执行

0x02 RVA to RAW

通过RVA计算RAW

  1. 查找RVA所在节区

  2. 使用公式计算文件偏移(RAW)

    RAW - PointerToRawData = RVA - VirtualAddress

    RAW = RVA - VirtualAddress + PointerToRawData

由于VirtualSize和SizeOfRawData值不同,所以会引起奇怪的事。。。

0x03 IAT(Import Address Table)

IAT(导入地址表)是一种表格,用来记录程序正在使用哪些库中的哪些函数。IAT存储在PE文件的.text段节区

1.DLL(Dynamic Linked Library)

16位DOS时代不存在DLL的概念,当程序用到库函数时编译器会先从C库中读取函数的二进制代码,然后插入到应用程序中。

但是在之后的Windows OS设计中,为了节约内存/磁盘空间,OS的设计者引入DLL概念:

  1. 不要把库包含到程序中,单独组成DLL文件,需要时调用即可
  2. 内存映射技术使加载后的DLL代码,资源在多个进程中实现共享
  3. 更新库时只要替换相关DLL文件即可,简便易行

加载DLL的方式有两种:

  1. 显示链接(Explicit Linking),程序使用DLL时加载,使用完毕后释放内存
  2. 隐式链接(Implicit Linking),程序开始时即一同加载DLL,程序终止时再释放占用内存

IAT提供的机制与隐式链接有关。

notepad.exe调用CreateFileW()时使用call dword ptr ds:[01001104]而非call 7c8107f0:

  1. kernel32.dll版本不同,CreateFileW()函数的位置也不同
  2. DLL重定位

2.IMAGE_IMPORT_DESCRIPTOR

IMAGE_IMPORT_DESCRIPTOR结构体中记录着PE文件要导入哪些库文件

执行一个普通程序时往往需要导入多个库,导入多少库就存在多少IMAGE_IMPORT_DESCRIPTOR结构体,这些结构体组成了数组,且结构体数组最后以NULL结构体结束。

#struct IMAGE_IMPORT_DESCRIPTOR
union {
DWORD Charateristics;
DWORD OriginalFirstThunk; //INT(Import Name Table)的地址(RVA),INT与IAT是DWORD数组,以NULL结束,INT中各元
//素的值为IMAGE_IMPORT_BY_NAME结构体指针
}
...
DWORD Name; //库名称字符串的地址(RVA)
...
DWORD FirstThunk; //IAT的地址(RVA)
#struct IMAGE_IMPORT_BY_NAME
WORD Hint; //序号
BYTE Name[1]; //函数名称字符串

IMAGE_IMPORT_DESCRIPTOR不在PE头,而在PE体中,IMAGE_OPTIONAL_HEADER32.DataDirectory[1].VirtualAddress的值即是IMAGE_IMPORT_DESCRIPTOR结构体数组的起始地址(RVA),如果要在文件中找到对应的地址需要将RVA转换为RAW。

PE装载器把导入函数输入至IAT的顺序: 见书p108

0x04 EAT(Export Address Table)

与IAT一样,PE文件内的特定结构体(IMAGE_EXPORT_DIRECTORY)保存着导出信息,且PE文件中仅有一个用来说明EAT的结构体(IMAGE_EXPORT_DIRECTORY)

IAT的IMAGE_EXPORT_DIRECTORY结构体以数组的形式存在,且拥有多个成员,这是因为PE文件可以同时导入多个库文件

在PE文件头中IMAGE_OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress的值即是IMAGE_EXPORT_DIRECTORY的起始位置(RVA)

#IMAGE_EXPORT_DIRECTORY
...
DWORD Base; //ordinal base
DWORD NumberOfFunctions; //实际Export函数的个数
DWORD NumberOfNames; //Export函数中具名的函数个数
DWORD AddressOfFunctions; //address of functions start address array
DWORD AddressOfNames; // address of funcion name string array
DWORD AddressOfNameOrdinals; //address of ordinal(序号) array

从库中获得函数的地址的API为GetProcAddress()。该API引用EAT来获取指定API的地址。

GetProcAddress()的操作原理:见书p114

0x05 高级PE

IAT/EAT的内容是运行时压缩器(Runtime Packer),反调试,DLL注入,API钩取等多种中高级逆向主题的基础知识。

PE规范只是一个建议性质的书面标准,查看结构体内部会发现,其实有很多成员并未被使用。只要文件符合PE规范就是PE文件,利用这一点可以制作出一些脱离常识的PE文件。

Patched PE指的就是这样的PE文件,这些PE文件仍然符合PE规范,但附带的PE头非常具有创意。

Reverse Core 第二部分 - 13章 - PE文件格式的更多相关文章

  1. Reverse Core 第二部分 - 16&17章 - 基址重定位表&.reloc节区

    第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x00 前言 这几天忙着挖邮箱漏洞,吃火锅,马上要被关禁闭,看书进度比较 ...

  2. Reverse Core 第二部分 - 14&15章 - 运行时压缩&调试UPX压缩的notepad

    @date: 2016/11/29 @author: dlive 0x00 前言 周六周日两天在打HCTF2016线上赛,没时间看书,打完比赛接着看~~ 0x01 运行时压缩 对比upx压缩前后的no ...

  3. PE文件格式详解,第二讲,NT头文件格式,以及文件头格式

    PE文件格式详解,第二讲,NT头文件格式,以及文件头格式 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) PS:本篇博客 ...

  4. 【JavaScript权威指南(第五版)】笔记之第二部分 客户端JavaScript 第13章~第23章

    第十三章 Web浏览器中的javascript ①   eg:下面两行代码实际上执行的是相同的功能 var answer = 42; window.answer = 42;   ③每个window对象 ...

  5. 深入理解 Win32 PE 文件格式

    深入理解 Win32 PE 文件格式 Matt Pietrek 这篇文章假定你熟悉C++和Win32. 概述 理解可移植可执行文件格式(PE)可以更好地了解操作系统.如果你知道DLL和EXE中都有些什 ...

  6. ASM:《X86汇编语言-从实模式到保护模式》第13章:保护模式下内核的加载,程序的动态加载和执行

    ★PART1:32位保护模式下内核简易模型 1. 内核的结构,功能和加载 每个内核的主引导程序都会有所不同,因为内核都会有不同的结构.有时候主引导程序的一些段和内核段是可以共用的(事实上加载完内核以后 ...

  7. Linux就这个范儿 第13章 打通任督二脉

    Linux就这个范儿 第13章 打通任督二脉 0111010110……你有没有想过,数据从看得见或看不见的线缆上飞来飞去,是怎么实现的呢?数据传输业务的未来又在哪里?在前面两章中我们学习了Linux网 ...

  8. PE文件格式详解,第三讲,可选头文件格式,以及节表

    PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...

  9. PE文件格式分析

    PE文件格式分析 PE 的意思是 Portable Executable(可移植的执行体).它是 Win32环境自身所带的执行文件格式.它的一些特性继承自Unix的Coff(common object ...

随机推荐

  1. jquery的.html(),.text()和.val()方法

    新人一段时间没写前端代码就有点忘记了,现在来复习一下..html()方法 获取集合中第一个匹配元素的HTML内容 或 设置每一个匹配元素的html内容,具体有3种用法: .html() 不传入值,就是 ...

  2. bzoj1078【SCOI2008】斜堆

    题意: 斜堆(skew heap)是一种常用的数据结构.它也是二叉树,且满足与二叉堆相同的堆性质:每个非根结点的值都比它父亲大.因此在整棵斜堆中,根的值最小.但斜堆不必是平衡的,每个结点的左右儿子的大 ...

  3. jQuery 运行机制

    1.Selector,查找元素.这个查找不但包含基于CSS1~CSS3的CSS Selector功能,还包含其对直接查找或间接查找而扩展的一些功能. 2.Dom元素的属性操作.Dom元素可以看作htm ...

  4. 自己写的服务出现"服务没有及时响应启动或控制请求 1053" 错误

    自己写了一个服务,安装到电脑上后 启动时发现报"服务没有及时响应启动或控制请求 1053" 这个错误 在网上找了一些方法,都没有解决 后来,看了下,原来有个写文件的方法读取文件没有 ...

  5. 深入浅出 Redis client/server交互流程

    综述 最近笔者阅读并研究redis源码,在redis客户端与服务器端交互这个内容点上,需要参考网上一些文章,但是遗憾的是发现大部分文章都断断续续的非系统性的,不能给读者此交互流程的整体把握.所以这里我 ...

  6. ionic 获取手机所在位置

    之前项目中需要使用到定位功能,前边的文章提到的坐标位置是有问题的,是国际坐标,国内的环境使用google地图会出现问题,所以需要使用国内的地图进行坐标解析,因为国内和国外的坐标体系不一致,需要通过转换 ...

  7. 判断iframe加载完成

    一.js判断 var parFrame = document.getElementById("oIframe"); if(parFrame.attachEvent){ parFra ...

  8. Nike Zoom Winflo 2 Kvinder Sko Når jeg set elementet

    De fleste af os elskede denne Nike Pegasus 34 foruden var ved at blive begejstret for at få dine ben ...

  9. 利用vim查看日志,快速定位问题

    起因 在一般的情况下,如果开发过程中测试报告了一个问题,我一般会这么做: 1.在自己的开发环境下重试一下测试的操作,看看能不能重现问题.不行转2 2.数据库连接池改成测试库的地址,在自己的开发环境下重 ...

  10. ThinkPHP 隐藏URL中的 index.php

    去掉 URL 中的 index.php 通常的URL里面含有index.php,为了达到更好的SEO效果可能需要去掉URL里面的index.php ,通过URL重写的方式可以达到这种效果,通常需要服务 ...