PE文件结构(0x04)

这次来继续刨析一下IMAGE_OPTIONAL_HEADER32的结构定义,正如名字所定义,这是一个可选的映像头,是一个可选的结构,但是事实上,IMAGE_FILE_HEADER结构远远不足以来定义PE文件属性,所以,这些属性的附加在IMAGE_OPTIONAL_HEADER32的结构中进行定义。

 

这两个结构合起来才是一个完整的pe文件结构

 

接下来我们来具体的看看IMAGE_OPTIONAL_HEADER32的结构定义

typedef struct _IMAGE_OPTIONAL_HEADER 
{
    //
    // Standard fields.  
    //
+18h    WORD    Magic;        // 标志字, ROM 映像(0107h),普通可执行文件(010Bh)
+1Ah    BYTE    MajorLinkerVersion;     // 链接程序的主版本号
+1Bh    BYTE    MinorLinkerVersion;     // 链接程序的次版本号
+1Ch    DWORD   SizeOfCode;     // 所有含代码的节的总大小
+20h    DWORD   SizeOfInitializedData;    // 所有含已初始化数据的节的总大小
+24h    DWORD   SizeOfUninitializedData; // 所有含未初始化数据的节的大小
+28h    DWORD   AddressOfEntryPoint;    // 程序执行入口RVA
+2Ch    DWORD   BaseOfCode;      // 代码的区块的起始RVA
+30h    DWORD   BaseOfData;      // 数据的区块的起始RVA
    //
    // NT additional fields.    以下是属于NT结构增加的领域。
    //
+34h    DWORD   ImageBase;      // 程序的首选装载地址
+38h    DWORD   SectionAlignment;      // 内存中的区块的对齐大小
+3Ch    DWORD   FileAlignment;      // 文件中的区块的对齐大小
+40h    WORD    MajorOperatingSystemVersion;  // 要求操作系统最低版本号的主版本号
+42h    WORD    MinorOperatingSystemVersion;  // 要求操作系统最低版本号的副版本号
+44h    WORD    MajorImageVersion;       // 可运行于操作系统的主版本号
+46h    WORD    MinorImageVersion;       // 可运行于操作系统的次版本号
+48h    WORD    MajorSubsystemVersion;  // 要求最低子系统版本的主版本号
+4Ah    WORD    MinorSubsystemVersion;  // 要求最低子系统版本的次版本号
+4Ch    DWORD   Win32VersionValue;       // 莫须有字段,不被病毒利用的话一般为0
+50h    DWORD   SizeOfImage;       // 映像装入内存后的总尺寸
+54h    DWORD   SizeOfHeaders;       // 所有头 + 区块表的尺寸大小
+58h    DWORD   CheckSum;       // 映像的校检和
+5Ch    WORD    Subsystem;       // 可执行文件期望的子系统
+5Eh    WORD    DllCharacteristics;       // DllMain()函数何时被调用,默认为 0
+60h    DWORD   SizeOfStackReserve;       // 初始化时的栈大小
+64h    DWORD   SizeOfStackCommit;       // 初始化时实际提交的栈大小
+68h    DWORD   SizeOfHeapReserve;        // 初始化时保留的堆大小
+6Ch    DWORD   SizeOfHeapCommit;        // 初始化时实际提交的堆大小
+70h    DWORD   LoaderFlags;        // 与调试有关,默认为 0 
+74h    DWORD   NumberOfRvaAndSizes;  // 下边数据目录的项数,这个字段自Windows NT 
                                      // 发布以来一直是16
+78h    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
           // 数据目录表
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

大部分文件都不重要,比较重要的是下面的几个字段:

  • AddressOfEntryPoint

        这是程序被执行的入口地址,是一个RVA地址,他指向了程序开始时第一个被执行的位置,如果在一个可执行文件上附加了一段代码并想让这段代码首先被执行,那么只需要将这个入口地址指向附加的代码就可以了。

  • ImageBase

       指出文件的优先装入地址。也就是说当文件被执行时,如果可能的话,Windows优先将文件装入到由ImageBase字段指定的地址中,只有指定的地址已经被其他模块使用时,文件才被装入到其他地址中。链接器产生可执行文件的时候对应这个地址来生成机器码,所以当文件被装入这个地址时不需要进行重定位操作,装入的速度最快,如果文件被装载到其他地址的话,将不得不进行重定位操作,这样就要慢一点。

       对于EXE文件来说,由于每个文件总是使用独立的虚拟地址空间,优先装入地址不可能被其他模块占据,所以EXE总是能够按照这个地址装入,这也意味着EXE文件不再需要重定位信息。对于DLL文件来说,由于多个DLL文件全部使用宿主EXE文件的地址空间,不能保证优先装入地址没有被其他的DLL使用,所以DLL文件中必须包含重定位信息以防万一。因此,在前面介绍的 IMAGE_FILE_HEADER 结构的 Characteristics 字段中,DLL 文件对应的 IMAGE_FILE_RELOCS_STRIPPED 位总是为0,而EXE文件的这个标志位总是为1

在链接的时候,可以通过对link.exe指定/base:address选项来自定义优先装入地址,如果不指定这个选项的话,一般EXE文件的默认优先装入地址被定为00400000h,而DLL文件的默认优先装入地址被定为10000000h

  • SectionAlignment 字段和 FileAlignment字段

      SectionAlignment字段指定了节被装入内存后的对齐单位。也就是说,每个节被装入的地址必定是本字段指定数值的整数倍。而FileAlignment字段指定了节存储在磁盘文件中时的对齐单位。X86中一般是4KB对齐;

1000h个字节,就是4096个字节,4kb。

  • Subsystem

        指定使用界面的子系统,它的取值如表所示。这个字段决定了系统如何为程序建立初始的界面,链接时的/subsystem:其他选项指定的就是这个字段的值,在前面章节的编程中我们早已知道:如果将子系统指定为Windows C UI,那么系统会自动为程序建立一个控制台窗口,而指定为Windows GUI的话,窗口必须由程序自己建立。

      界面子系统的取值和含义

取   值

Windows.inc中的预定义值

含   义

0

IMAGE_SUBSYSTEM_UNKNOWN

未知的子系统

1

IMAGE_SUBSYSTEM_NATIVE

不需要子系统(如驱动程序)

2

IMAGE_SUBSYSTEM_WINDOWS_GUI

Windows图形界面

3

IMAGE_SUBSYSTEM_WINDOWS_CUI

Windows控制台界面

5

IMAGE_SUBSYSTEM_OS2_CUI

OS2控制台界面

7

IMAGE_SUBSYSTEM_POSIX_CUI

POSIX控制台界面

8

IMAGE_SUBSYSTEM_NATIVE_WINDOWS

不需要子系统

9

IMAGE_SUBSYSTEM_WINDOWS_CE_GUI

Windows CE图形界面

 

  • DataDirectory[]字段

        这个字段可以说是最重要的字段之一,它由16个相同的IMAGE_DATA_DIRECTORY结构组成,虽然PE文件中的数据是按照装入内存后的页属性归类而被放在不同的节中的,但是这些处于各个节中的数据按照用途可以被分为导出表、导入表、资源、重定位表等数据块,这16个IMAGE_DATA_DIRECTORY结构就是用来定义多种不同用途的数据块的(如表17.4所示)。IMAGE_DATA_DIRECTORY结构的定义很简单,它仅仅指出了某种数据块的位置和长度

typedef struct _IMAGE_DATA_DIRECTORY {
  DWORD     VirtualAddress;     //块的RVA
  DWORD     Size;               //块的长度
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

 下面是数组的的参数

索   引

索引值在Windows.inc中的预定义值

对应的数据块

0

IMAGE_DIRECTORY_ENTRY_EXPORT

导出表

1

IMAGE_DIRECTORY_ENTRY_IMPORT

导入表

2

IMAGE_DIRECTORY_ENTRY_RESOURCE

资源

3

IMAGE_DIRECTORY_ENTRY_EXCEPTION

异常(具体资料不详)

4

IMAGE_DIRECTORY_ENTRY_SECURITY

安全(具体资料不详)

5

IMAGE_DIRECTORY_ENTRY_BASERELOC

重定位表

6

IMAGE_DIRECTORY_ENTRY_DEBUG

调试信息

7

IMAGE_DIRECTORY_ENTRY_ARCHITECTURE

版权信息

8

IMAGE_DIRECTORY_ENTRY_GLOBALPTR

具体资料不详

9

IMAGE_DIRECTORY_ENTRY_TLS

Thread Local Storage

10

IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG

具体资料不详

11

IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT

具体资料不详

12

IMAGE_DIRECTORY_ENTRY_IAT

导入函数地址表

13

IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT

具体资料不详

14

IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR

具体资料不详

15

未使用

 

在PE文件中寻找特定的数据时就是从这些IMAGE_DATA_DIRECTORY结构开始的,比如要存取资源,那么必须从第3个IMAGE_DATA_DIRECTORY结构(索引为2)中得到资源数据块的大小和位置;同理,如果要查看PE文件导入了哪些DLL文件的哪些API函数,那就必须首先从第2个IMAGE_DATA_DIRECTORY结构得到导入表的位置和大小。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值