一直想做一个PE结构的总结,只是学的时候有很多东西就没搞懂,加上时间一长,很多知识也早忘了,也就一直没完成。这几天从头看了下,好不容易理清楚了,整理一下,以免又忘了

pe文件框架结构,图片贴过来太模糊了就画个表格代替一下

DOS文件头 PE文件头  区块表    各区块    调试信息  

  DOS文件头

DOS文件头包括DOS MZ头和DOS stub

MS-DOS头部是一个IMAGE_DOS_HEADER结构(代码来自windows.inc)

IMAGE_DOS_HEADER STRUCT
+0h e_magic WORD ? ;DOS可执行文件标记"MZ"
+2h e_cblp WORD ?
+4h e_cp WORD ?
+6h e_crlc WORD ?
+8h e_cparhdr WORD ?
+0a e_minalloc WORD ?
+0c e_maxalloc WORD ?
+0e e_ss WORD ?
+ e_sp WORD ?
+ e_csum WORD ?
+ e_ip WORD ?
+ e_cs WORD ?
+ e_lfarlc WORD ?
+1a e_ovno WORD ?
+1c e_res WORD dup(?)
+ e_oemid WORD ?
+ e_oeminfo WORD ?
+ e_res2 WORD dup(?)
+3c e_lfanew DWORD ? ;指向PE文件头
IMAGE_DOS_HEADER ENDS

此结构共64字节

这里面只有第一个和最后一个字段较为重要,e_magic字段被设置为5A4Dh,其ASCII值为"MZ"(4D5Ah)<小端存储>

偏移为3ch的e_lfanew字段指出真正的PE头的文件偏移位置

接下来的DOS stub(DOS块)实际上是一个有效的EXE,在DOS下显示一个错误提示

  PE文件头

PE文件头是一个IMAGE_NT_HEADERS结构

IMAGE_NT_HEADERS STRUCT
+0h Signature DWORD ?   ;PE文件表示
+4h FileHeader IMAGE_FILE_HEADER <>  ;映像文件头,包含了PE文件的一些基本信息
+18h OptionalHeader IMAGE_OPTIONAL_HEADER32 <>  ;可选映像头,补充PE文件属性
IMAGE_NT_HEADERS ENDS

对于32位PE文件,此结构通常为248字节

对于Signature的定义为

IMAGE_NT_SIGNATURE equ 00004550h

其ASCII值为:"PE00"(50450000h)

后面的两个结构最重要的就是偏移78h的数据目录表

IMAGE_FILE_HEADER结构

IMAGE_FILE_HEADER STRUCT
+04h  Machine WORD ? ;可执行文件的目标CPU类型,14Ch为Intel i386
+06h  NumberOfSections WORD ? ;区块的数目
+08h  TimeDateStamp DWORD ?  ;文件创建日期和时间
+0ch  PointerToSymbolTable DWORD ?  ;COFF符号表的文件偏移位置
+10h  NumberOfSymbols DWORD ?  ;符号个数
+14h  SizeOfOptionalHeader WORD ?  ;IMAGE_OPTIONAL_HEADER32结构的大小,32位PE文件通常是E0h,64位PE32+是F0h
+16h  Characteristics WORD ?  ;文件属性
IMAGE_FILE_HEADER ENDS

IMAGE_OPTIONAL_HEADER32结构

IMAGE_OPTIONAL_HEADER32 STRUCT
+18h  Magic WORD ?  ;标志字,ROM映像(0107h)普通可执行映像(010Bh)PE32+(020Bh)
+1Ah  MajorLinkerVersion BYTE ?  ;链接程序的主版本号
+1Bh  MinorLinkerVersion BYTE ?  ;链接程序的次版本号
+1Ch  SizeOfCode DWORD ?  ;所有带有IMAGE_SCN_CNT_CODE属性区块的总大小
+20h  SizeOfInitializedData DWORD ?  ;已初始化数据块的大小
+24h  SizeOfUninitializedData DWORD ?  ;未初始化数据块的大小(通常在.bss块中)
+28h  AddressOfEntryPoint DWORD ?  ;程序执行入口RVA(这个地址并不直接指向Main、WinMain、DllMain,而是指向运行库代码并由它来调用上述函数)
+2Ch  BaseOfCode DWORD ? ;代码段的起始RVA(Microsoft链接器生成的执行文件通常是1000h)<内存中代码段通常在PE文件头之后、数据块之前>
+30h  BaseOfData DWORD ?  ;数据段的起始RVA。这个域的值对于不同版本的微软链接器是不一致的,在64位可执行文件中是不出现的
+34h  ImageBase DWORD ?  ;文件在内存中的首选装入地址
+38h  SectionAlignment DWORD ?  ;内存中的区块对齐值
+3Ch  FileAlignment DWORD ?  ;磁盘上区块的对齐值
+40h  MajorOperatingSystemVersion WORD ?  ;操作系统最低主版本号
+42h  MinorOperatingSystemVersion WORD ?  ;操作系统最低次版本号
+44h  MajorImageVersion WORD ?  ;用户自定义主版本号
+46h  MinorImageVersion WORD ?  ;用户自定义次版本号
+48h  MajorSubsystemVersion WORD ?  ;要求最低子系统版本主版本号
+4Ah  MinorSubsystemVersion WORD ?  ;要求最低子系统版本次版本号
+4Ch  Win32VersionValue DWORD ?  ;不用字段,常设为0
+50h  SizeOfImage DWORD ?  ;映像装入内存后的总尺寸
+54h  SizeOfHeaders DWORD ?  ;MS-DOS头部、PE头部、区块表的组合尺寸。域值四舍五入至文件对齐的倍数
+58h  CheckSum DWORD ?  ;映像校验和,链接器的/RELEASE开关被使用时,校验和被置于文件中
+5Ch  Subsystem WORD ?  ;标明可执行文件所期望的子系统(用户界面类型)的枚举值
+5Eh  DllCharacteristics WORD ?  ;DLL特性旗标,DllMain()函数何时被调用,默认为0
+60h  SizeOfStackReserve DWORD ?  ;为线程保留的堆栈大小,它一开始只提交其中一部分,只有在必要时,才提交剩下的部分
+64h  SizeOfStackCommit DWORD ?  ;一开始即被委派给堆栈的内存数量。默认值是4KB
+68h  SizeOfHeapReserve DWORD ?  ;为进程的默认堆保留的内存。默认值是1MB,在当前Windows里,堆值在用户不干涉的情况下就能增长超过这个值
+6Ch  SizeOfHeapCommit DWORD ?  ;EXE文件里,委派给堆的内存大小。默认值是4KB
+70h  LoaderFlags DWORD ?  ;与调试有关,默认为0
+74h  NumberOfRvaAndSizes DWORD ?  ;数据目录的项数,从最早的Windows NT发布以来一直是16
+78h  DataDirectory IMAGE_DATA_DIRECTORY IMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)
IMAGE_OPTIONAL_HEADER32 ENDS

这两个结构中有很多常用到的信息,如IMAGE_FILE_HEADER结构中的区块数目, IMAGE_OPTIONAL_HEADER中的ImageBase、SectionAlignment和FileAlignment等字段

  区块表

对于数据目录表,最后再来总结

区块表是一个IMAGE_SECTION_HEADER结构数组,区块的个数由IMAGE_NT_HEADERS.FileHeader.NumberOfSections指出

区块表的后面与区块之间一般是大量的填充位

IMAGE_SECTION_HEADER结构:40字节

IMAGE_SECTION_HEADER STRUCT
Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?)  ;区块名
union Misc
PhysicalAddress dd ?
VirtualSize dd ?  ;区块实际大小
ends
VirtualAddress dd ?  ;区块的RVA地址
SizeOfRawData dd ?  ;在文件中对齐后的尺寸
PointerToRawData dd ?  ;在文件中的偏移
PointerToRelocations dd ?  ;在OBJ文件中使用,重定位的偏移,指向一个IMAGE_RELOCATION结构数组
PointerToLinenumbers dd ?  ;行号表在文件中的偏移值,这是文件调试信息
NumberOfRelocations dw ?  ;重定位项数目,在EXE文件中无意义
NumberOfLinenumbers dw ?  ;该块在行号表中的行号数目
Characteristics dd ?  ;块属性
IMAGE_SECTION_HEADER ENDS

此结构常用VirtualAddress和PointerToRawData字段来定位区块,并实现文件偏移与虚拟地址的转换

  数据目录表

数据目录表位于IMAGE_NT_HEADER的78h偏移处,是一个IMAGE_DATA_DIRECTORY结构数组,从最早的Windows NT发布以来项数一直是16

IMAGE_DATA_DIRECTORY结构为:

IMAGE_DATA_DIRECTORY STRUCT
VirtualAddress DWORD ?  ;数据块的起始RVA
isize DWORD ?  ;数据块的大小
IMAGE_DATA_DIRECTORY ENDS

一、数组的第一项指向输出表

输出表是一个IMAGE_EXPORT_DIRECTORY结构

IMAGE_EXPORT_DIRECTORY STRUCT
Characteristics DWORD ?  ;输出属性,目前未定义,总是为0
TimeDateStamp DWORD ?  ;输出表创建时间(GMT时间)
MajorVersion WORD ?  ;输出表主版本号,未使用
MinorVersion WORD ?  ;次版本号,未使用
nName DWORD ?  ;指向一个ASCII字符串的RVA,这个字符串是与这些输出函数关联的DLL名字
nBase DWORD ?  ;基数,加上序数就是函数地址数组的索引值
NumberOfFunctions DWORD ?  ;EAT中条目数(输出函数地址表)
NumberOfNames DWORD ?  ;ENT中的条目数(输出函数名称表)
AddressOfFunctions DWORD ?  ;EAT的RVA
AddressOfNames DWORD ?  ;ENT的RVA
AddressOfNameOrdinals DWORD ?  ;输出序数表的RVA
IMAGE_EXPORT_DIRECTORY ENDS

输出表结构

AddressOfNameOrdinals指向的输出序数表的作用是把EAT和ENT联系起来,当PE装载器在ENT中找到对应函数的位置,再从输出序数表读取相应位置的值,这个值便是在EAT中的偏移,这个值作为进入EAT的索引(这里有一点不明白,看雪加密解密第三版书上说此值作为输出函数的输出序数并且要考虑Base阈值,但是实例中输出序数表中的值是函数在EAT中的偏移)。当通过序数来查询一个输出函数是,减去nBase阈值得到进入EAT的索引

二、数据目录表第二项输入表

输入表以一个IMAGE_IMPORT_DESCRIPTOR(IID)结构数组开始,数组以一个全为0的IID结构结束

IMAGE_IMPORT_DESCRIPTOR STRUCT
union
Characteristics dd ?
OriginalFirstThunk dd ?  ;指向输入名称表(INT)的RVA
ends
TimeDateStamp dd ?  ;时间标志
ForwarderChain dd ?  ;第一个被转向的API的索引,一般为0
Name1 dd ?  ;指向DLL的名字
FirstThunk dd ?  ;指向输入地址表(IAT)的RVA
IMAGE_IMPORT_DESCRIPTOR ENDS

INT和IAT都是一个IMAGE_THUNK_DATA结构数组,同样以一个全为0的IMAGE_THUNK_DATA结构作为结束

IMAGE_THUNK_DATA32 STRUCT
union u1
ForwarderString dd ?  ;指向一个转向者字符串的RVA
Function dd ?  ;被输入的函数的内存地址
Ordinal dd ?  ;被输入的API的序数值
AddressOfData dd ?  ;指向IMAGE_IMPORT_BY_NAME
ends
IMAGE_THUNK_DATA32 ENDS

INT中当IMAGE_THUNK_DATA值得最高位为1是,表示函数以序号方式输入;最高位为0是以函数名的方式输入,此时指向一个IMAGE_IMPORT_BY_NAME结构

IMAGE_IMPORT_BY_NAME结构为:

IMAGE_IMPORT_BY_NAME STRUCT
Hint dw ?  ;指出此函数在所驻留的DLL的输出表中的序号,有些连接器将此值设为0
Name1 db ?  ;输入函数的函数名,这是一个可变尺寸域
IMAGE_IMPORT_BY_NAME ENDS

PE加载器先同过INT找到相应的函数,再将对应函数的地址重写入IAT,此时程序仅依靠IAT提供的函数地址就可以正常运行了

因为一开始IAT跟INT是一样的,有些链接器就只用一个IAT结构就完成了输入(不知道在哪儿看到过这句话,大概意思就这个)

三、数据目录表第三项资源表

数据目录表中的IMAGE_DIRECTORY_ENTRY_RESOURCE条目包含资源的RVA和大小,资源目录每一节点包含一个IMAGE_RESOURCE_DIRECTORY结构和数个IMAGE_RESOURCE_DIRECTORY_ENTRY结构,IMAGE_RESOURCE_DIRECTORY指出紧跟在后面的IMAGE_RESOURCE_DIRECTORY_ENTRY结构的个数

从网上找了张图,这张图对资源目录结构的描述很清晰

IMAGE_RESOURCE_DIRECTORY STRUCT
Characteristics dd ?  ;理论上是资源的属性标志,但通常为0
TimeDateStamp dd ?  ;资源建立的时间
MajorVersion dw ?  ;理论上放置资源的版本,但通常为0
MinorVersion dw ?  ;
NumberOfNamedEntries dw ?  ;使用名字的资源条目的个数
NumberOfIdEntries dw ?  ;使用ID数字资源条目的个数
IMAGE_RESOURCE_DIRECTORY ENDS

NumberOfNamedEntries和NumberOfIdEntries加起来的和等于本目录IMAGE_RESOURCE_DIRECTORY_ENTRY的个数

IMAGE_RESOURCE_DIRECTORY_ENTRY STRUCT
union
rName RECORD NameIsString:,NameOffset:
Name1 dd ?
Id dw ?
ends
union
OffsetToData dd ?
rDirectory RECORD DataIsDirectory:,OffsetToDirectory:
ends
IMAGE_RESOURCE_DIRECTORY_ENTRY ENDS

  就先总结到这儿吧2015-07-02/17:11:08

PE文件结构整理的更多相关文章

  1. 再探.NET的PE文件结构(安全篇)

    一.开篇 首先写在前面,这篇文章源于个人的研究和探索,由于.NET有自己的反射机制,可以清楚的将源码反射出来,这样你的软件就很容易被破解,当然这篇文章不会说怎么样保护你的软件不被破解,相反是借用一个软 ...

  2. PE文件结构详解(六)重定位

    前面两篇 PE文件结构详解(四)PE导入表 和 PE文件结构详解(五)延迟导入表 介绍了PE文件中比较常用的两种导入方式,不知道大家有没有注意到,在调用导入函数时系统生成的代码是像下面这样的: 在这里 ...

  3. PE文件结构详解(五)延迟导入表

    PE文件结构详解(四)PE导入表讲 了一般的PE导入表,这次我们来看一下另外一种导入表:延迟导入(Delay Import).看名字就知道,这种导入机制导入其他DLL的时机比较“迟”,为什么要迟呢?因 ...

  4. PE文件结构详解(四)PE导入表

    PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPO ...

  5. PE文件结构详解(三)PE导出表

    上篇文章 PE文件结构详解(二)可执行文件头 的结尾出现了一个大数组,这个数组中的每一项都是一个特定的结构,通过函数获取数组中的项可以用RtlImageDirectoryEntryToData函数,D ...

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

    在PE文件结构详解(一)基本概念里,解释了一些PE文件的一些基本概念,从这篇开始,将详细讲解PE文件中的重要结构. 了解一个文件的格式,最应该首先了解的就是这个文件的文件头的含义,因为几乎所有的文件格 ...

  7. PE文件结构详解(一)基本概念

    PE(Portable Execute) 文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任 何扩展名.那 ...

  8. PE文件结构(四) 输出表

    PE文件结构(四) 參考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 输出表 一般来说输出表存在于dll中.输出表提供了 文件里函数的名字跟这些函数的地址, PE装载器通过输出表来改 ...

  9. PE文件结构(五岁以下儿童)基地搬迁

    PE文件结构(五岁以下儿童) 參考 书:<加密与解密> 视频:小甲鱼 解密系列 视频 基址重定位 链接器生成一个PE文件时,它会如果程序被装入时使用的默认ImageBase基地址(VC默认 ...

随机推荐

  1. POJ1573 Robot Motion(模拟)

    题目链接. 分析: 很简单的一道题, #include <iostream> #include <cstring> #include <cstdio> #inclu ...

  2. FFT多项式乘法加速

    FFT基本操作...讲解请自己看大学信号转置系列... 15-5-30更新:改成结构体的,跪烂王学长啊啊啊啊机智的static... #include<iostream> #include ...

  3. Letter Combinations of a Phone Number——LeetCode

    Given a digit string, return all possible letter combinations that the number could represent. A map ...

  4. 线段树解Insertion Sort Advanced Analysis

    题目出处 题意描述: 这个题目提问的是,在插入排序的序列给定的情况下,求最少需要移动的次数. 序列的长度n <=10^5 序列中的元素a[i] <=10^6 一组数据中case数t < ...

  5. A - Fire Net - hdu 1045(二分图匹配)

    题意:一个阵地可以向四周扫射,求出来最多能修多少个阵地,墙不可以被扫射透,阵地不能同行或者或者列(有墙隔着例外) 分析:很久以前就做过这道题..当时是练习深搜来着,不过时间复杂度比较高,现在再看突然发 ...

  6. hyperv虚拟机网络速度慢问题的解决办法

    服务器安装了windows2012R2进行虚拟化,虚拟机也是用的是windows2012R2的操作系统,这样可以一次激活对应的虚拟机. 在使用虚拟机的过程中发现问题,虚拟机主机的网速正常,无论是ftp ...

  7. Ensures there will be no 'console is undefined' errors

    很早之前项目中遇到过这种bug, 当时没有多留意,只是暂时把笔记留了下来,今天整理笔记的时候,看到了,故先整理在此,具体用法下次遇到再好好理解理解.如果有筒子遇到过,麻烦留言说一下,先谢谢啦. //E ...

  8. javascript动态改变当前页面中元素的状态行为

    function Datea() { var timed = document.getElementById('timed'); var t = setInterval(function TDate( ...

  9. 再谈javascript原型继承

    Javascript原型继承是一个被说烂掉了的话题,但是自己对于这个问题一直没有彻底理解,今天花了点时间又看了一遍<Javascript模式>中关于原型实现继承的几种方法,下面来一一说明下 ...

  10. ios将一个项目完全导为另一个项目(tool)

    --前言:有时开始一个新项目,但新项目跟已做完的一个项目很类似,基本可以在原有项目上更改.这个时候,可以new一个新project,在将相应的代码文件copy到新的project,配置工程各参数,库等 ...