PE文件-FILE HEADER与OPTIONAL HEADER

来源:互联网 发布:scala编程思想 pdf 编辑:程序博客网 时间:2024/06/13 23:32
 

本课我们将要研究 PE header file header(文件头)部分

至此,我们已经学到了哪些东东,先简要回顾一下:

  • DOS MZ header 又命名为 IMAGE_DOS_HEADER.。其中只有两个域比较重要: e_magic 包含字符串"MZ"e_lfanew 包含PE header在文件中的偏移量。
  • 比较e_magic 是否为IMAGE_DOS_SIGNATURE以验证是否是有效的DOS header。比对符合则认为文件拥有一个有效的DOS header
  • 为了定位PE header,移动文件指针到e_lfanew所指向的偏移。
  • PE header的第一个双字包含字符串"PE\0\0"。该双字与IMAGE_NT_SIGNATURE比对,符合则认为PE header有效。

本课我们继续探讨关于 PE header 的知识。 PE header 的正式命名是 IMAGE_NT_HEADERS。再来回忆一下这个结构。

IMAGE_NT_HEADERS STRUCT
    Signature dd ?
    FileHeader IMAGE_FILE_HEADER <>
    OptionalHeader IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS ENDS

Signature PE标记,值为50h, 45h, 00h, 00hPE\0\0)。
FileHeader 该结构域包含了关于PE文件物理分布的一般信息。
OptionalHeader 该结构域包含了关于PE文件逻辑分布的信息。

最有趣的东东在 OptionalHeader 里。不过,FileHeader 里的一些域也很重要。本课我们将学习FileHeader下一课研究OptionalHeader

IMAGE_FILE_HEADER STRUCT
    Machine WORD ?
    NumberOfSections WORD ?
    TimeDateStamp dd ?
    PointerToSymbolTable dd ?
    NumberOfSymbols dd ?
    SizeOfOptionalHeader WORD ?
    Characteristics WORD ?
IMAGE_FILE_HEADER ENDS

Field nameMeaningsMachine该文件运行所要求的CPU。对于Intel平台,该值是IMAGE_FILE_MACHINE_I386 (14Ch)。我们尝试了LUEVELSMEYERpe.txt声明的14Dh14Eh,但Windows不能正确执行。看起来,除了禁止程序执行之外,本域对我们来说用处不大。NumberOfSections 文件的节数目。如果我们要在文件中增加或删除一个节,就需要修改这个值。TimeDateStamp文件创建日期和时间。我们不感兴趣。PointerToSymbolTable用于调试。NumberOfSymbols用于调试。SizeOfOptionalHeader指示紧随本结构之后的 OptionalHeader 结构大小,必须为有效值。Characteristics关于文件信息的标记,比如文件是exe还是dll

简言之,只有三个域对我们有一些用: Machine, NumberOfSections Characteristics。通常不会改变 Machine Characteristics 的值,但如果要遍历节表就得使用 NumberOfSections
为了更好阐述 NumberOfSections 的用处,这里简要介绍一下节表。

节表是一个结构数组,每个结构包含一个节的信息。因此若有3个节,数组就有3个成员。我们需要NumberOfSections值来了解该数组中到底有几个成员。 也许您会想检测结构中的全0成员起到同样效果。Windows确实采用了这种方法。为了证明这一点,可以增加NumberOfSections的值,Windows仍然可以正常执行文件。据我们的观察,Windows读取NumberOfSections的值然后检查节表里的每个结构,如果找到一个全0结构就结束搜索,否则一直处理完NumberOfSections指定数目的结构。 为什么我们不能忽略NumberOfSections的值? 有几个原因。PE说明中没有指定节表必须以全0结构结束。Thus there may be a situation where the last array member is contiguous to the first section, without empty space at all. Another reason has to do with bound imports. The new-style binding puts the information immediately following the section table's last structure array member. 因此您仍然需要NumberOfSections

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

我们已经学习了关于 DOS header PE header 中部分成员的知识。这里是 PE header 中最后、最大或许也是最重要的成员,optional header

回顾一下,optional header 结构是 IMAGE_NT_HEADERS 中的最后成员。包含了PE文件的逻辑分布信息。该结构共有31个域,一些是很关键,另一些不太常用。这里只介绍那些真正有用的域。

这儿有个关于PE文件格式的常用术语: RVA
RVA
代表相对虚拟地址。 知道什么是虚拟地址吗?相对那些简单的概念而言,RVA有些晦涩。简言之,RVA是虚拟空间中到参考点的一段距离。我打赌您肯定熟悉文件偏移量: RVA就是类似文件偏移量的东西。当然它是相对虚拟空间里的一个地址,而不是文件头部。举例说明,如果PE文件装入虚拟地址(VA)空间的400000h处,且进程从虚址401000h开始执行,我们可以说进程执行起始地址在RVA 1000h。每个RVA都是相对于模块的起始VA的。
为什么PE文件格式要用到RVA呢? 这是为了减少PE装载器的负担。因为每个模块多有可能被重载到任何虚拟地址空间,如果让PE装载器修正每个重定位项,这肯定是个梦魇。相反,如果所有重定位项都使用RVA,那么PE装载器就不必操心那些东西了: 它只要将整个模块重定位到新的起始VA。这就象相对路径和绝对路径的概念: RVA类似相对路径,VA就象绝对路径。

FieldMeaningsAddressOfEntryPointPE装载器准备运行的PE文件的第一个指令的RVA。若您要改变整个执行的流程,可以将该值指定到新的RVA,这样新RVA处的指令首先被执行。ImageBasePE文件的优先装载地址。比如,如果该值是400000h,PE装载器将尝试把文件装到虚拟地址空间的400000h处。字眼"优先"表示若该地址区域已被其他模块占用,那PE装载器会选用其他空闲地址。SectionAlignment内存中节对齐的粒度。例如,如果该值是4096 (1000h),那么每节的起始地址必须是4096的倍数。若第一节从401000h开始且大小是10个字节,则下一节必定从402000h开始,即使401000h和402000h之间还有很多空间没被使用。FileAlignment

文件中节对齐的粒度。例如,如果该值是(200h),,那么每节的起始地址必须是512的倍数。若第一节从文件偏移量200h开始且大小是10个字节,则下一节必定位于偏移量400h: 即使偏移量512和1024之间还有很多空间没被使用/定义。

MajorSubsystemVersion
MinorSubsystemVersion
win32子系统版本。若PE文件是专门为Win32设计的,该子系统版本必定是4.0否则对话框不会有3维立体感。SizeOfImage内存中整个PE映像体的尺寸。它是所有头和节经过节对齐处理后的大小。 SizeOfHeaders所有头+节表的大小,也就等于文件尺寸减去文件中所有节的尺寸。可以以此值作为PE文件第一节的文件偏移量。SubsystemNT用来识别PE文件属于哪个子系统。 对于大多数Win32程序,只有两类值: Windows GUI 和 Windows CUI (控制台)。DataDirectoryIMAGE_DATA_DIRECTORY 结构数组。每个结构给出一个重要数据结构的RVA,比如引入地址表等。