Reverse Core 第二部分 - 13章 - PE文件格式
@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
查找RVA所在节区
使用公式计算文件偏移(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概念:
- 不要把库包含到程序中,单独组成DLL文件,需要时调用即可
- 内存映射技术使加载后的DLL代码,资源在多个进程中实现共享
- 更新库时只要替换相关DLL文件即可,简便易行
加载DLL的方式有两种:
- 显示链接(Explicit Linking),程序使用DLL时加载,使用完毕后释放内存
- 隐式链接(Implicit Linking),程序开始时即一同加载DLL,程序终止时再释放占用内存
IAT提供的机制与隐式链接有关。
notepad.exe调用CreateFileW()时使用call dword ptr ds:[01001104]而非call 7c8107f0:
- kernel32.dll版本不同,CreateFileW()函数的位置也不同
- 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文件格式的更多相关文章
- Reverse Core 第二部分 - 16&17章 - 基址重定位表&.reloc节区
第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x00 前言 这几天忙着挖邮箱漏洞,吃火锅,马上要被关禁闭,看书进度比较 ...
- Reverse Core 第二部分 - 14&15章 - 运行时压缩&调试UPX压缩的notepad
@date: 2016/11/29 @author: dlive 0x00 前言 周六周日两天在打HCTF2016线上赛,没时间看书,打完比赛接着看~~ 0x01 运行时压缩 对比upx压缩前后的no ...
- PE文件格式详解,第二讲,NT头文件格式,以及文件头格式
PE文件格式详解,第二讲,NT头文件格式,以及文件头格式 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) PS:本篇博客 ...
- 【JavaScript权威指南(第五版)】笔记之第二部分 客户端JavaScript 第13章~第23章
第十三章 Web浏览器中的javascript ① eg:下面两行代码实际上执行的是相同的功能 var answer = 42; window.answer = 42; ③每个window对象 ...
- 深入理解 Win32 PE 文件格式
深入理解 Win32 PE 文件格式 Matt Pietrek 这篇文章假定你熟悉C++和Win32. 概述 理解可移植可执行文件格式(PE)可以更好地了解操作系统.如果你知道DLL和EXE中都有些什 ...
- ASM:《X86汇编语言-从实模式到保护模式》第13章:保护模式下内核的加载,程序的动态加载和执行
★PART1:32位保护模式下内核简易模型 1. 内核的结构,功能和加载 每个内核的主引导程序都会有所不同,因为内核都会有不同的结构.有时候主引导程序的一些段和内核段是可以共用的(事实上加载完内核以后 ...
- Linux就这个范儿 第13章 打通任督二脉
Linux就这个范儿 第13章 打通任督二脉 0111010110……你有没有想过,数据从看得见或看不见的线缆上飞来飞去,是怎么实现的呢?数据传输业务的未来又在哪里?在前面两章中我们学习了Linux网 ...
- PE文件格式详解,第三讲,可选头文件格式,以及节表
PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...
- PE文件格式分析
PE文件格式分析 PE 的意思是 Portable Executable(可移植的执行体).它是 Win32环境自身所带的执行文件格式.它的一些特性继承自Unix的Coff(common object ...
随机推荐
- Python学习--Python简介
Python 简介 Python是一种解释型.编译性.面向对象.动态数据类型的高级程序设计语言.Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年. P ...
- cmd常用命令
2016.12.18 0:07 (持续更新) cd 目录名:打开文件目录, cd .. 返回上一目录 cd ... 返回上上级目录 cd \ 返回根目录 cls 清除当前cmd页面所有的记录 md 名 ...
- 使用App.config管理数据库连接
程序的数据库连接字符串可以保持在程序的配置文件App.config中,便于管理. 将配置文件添加至解决方案: 添加连接信息: <?xml version="1.0"?> ...
- 理解Compressed Sparse Column Format (CSC)
最近在看<Spark for Data Science>这本书,阅读到<Machine Learning>这一节的时候被稀疏矩阵的存储格式CSC给弄的晕头转向的.所以专门写一篇 ...
- python模块(shelve,xml,configparser,hashlib,logging)
1.1shelve模块 shelve 模块比pickle模块简单,只有一个open函数,返回类似字典对象,可读可写:key必须为字符串, 而值可以是python所支持的数据类型. shelve模块主要 ...
- MSSQLServer 纵向表转横向表 横向表转纵向表 行转列 列转行
MSSQLServer 纵向表转横向表 横向表转纵向表 建表语句及插入数据语句: CREATE TABLE Test_y( ) NULL, ) NULL, [Grade] [int] NULL ) ...
- Table 表单样式
<style> table th { white-space: nowrap; background-color: #f5f5f5; height:30px; font-size:14px ...
- unity游戏开发新手-----2017年展望
0.希望三月份中旬之前找一份游戏开发的工作,必须转正; 1.希望存款3-4万; 2.今年年底结婚; 3.锻炼身体,体重保持在115斤左右,有胸肌和腹肌;(结婚之前实现) 4.技术方面: 熟练掌握C#语 ...
- Java基础:三目运算符
三目运算符 (表达式1)?(表达式2):(表达式3),计算方法是这样的:表达式1是一个逻辑表达式,如果其值为true,则整个表达式的值为表达式2的值,否则为表达式3的值.
- Yii2 基于RESTful架构的 advanced版API接口开发 配置、实现、测试 (转)
环境配置: 开启服务器伪静态 本处以apache为例,查看apache的conf目录下httpd.conf,找到下面的代码 LoadModule rewrite_module modules/mod_ ...