PE文件结构——NT Headers

目录

一、NT Headers的结构

1.Signature(DWORD)

2. FileHeader(IMAGE_FILE_HEADER)

3.OptionalHeader(IMAGE_OPTIONAL_HEADER32)


一、NT Headers的结构

NT Headers的结构被定义在"winnt.h"中,结构名为"_IMAGE_NT_HEADERS"。它内部有三个成员,具体请看下图:

 接下来我们将具体分析这三个成员:

1.Signature(DWORD)

它占据了四个字节,是一个固定的十六进制值为"0x50450000",按照ASCII码编码,值为"PE\0\0",这是一个标签,它的作用是告诉OS loader这是个PE文件。

2. FileHeader(IMAGE_FILE_HEADER)

这个我暂且叫他文件头,里面有一些和这个PE文件有关的信息。

 接下来我们来分析一下它的结构:

首先,我们先用PE-Bear来解析一下这个exe文件的File Header:

1.Machine

它占两个字节,镜像文件只能运行于指定处理器或者能够模拟该处理器的系统上。我们来看看微软的专用文档对这一部分的描述:

下面是相关的值与其对应的机器型号:

 详细内容请看这儿

 接下来我们用一个解析软件"PE-Bear"来解析一下eclipse.exe,来看看它这个Machine值是多少

 

 这个Meaning是AMD64(K8),这是一个由AMD公司研发的64位处理器。

2.NumberofSections

它是一个count,它占两个字节,代表在之后的区域表中有几个区域段。

3.TimeDataStamp

存的是这个文件创建的时间。

4.PointerToSymbolTable 和 NumberOfSymbols

 这个我目前也知道一个概念,不过它是已经被抛弃了,官方文档里面狠心地说了一句"...is deprecated",所以说这两个的value都是0。

5.SizeOfOptionalHeader

它存有可选择头的大小,它的大小是不同的。对于32位文件来说大小是224,对于64位文件来说大小是240。

6.Characteristics

用来标识说明这个PE文件的一些属性与特征,比如说这个文件是不是可执行的等等。这里每一个value都有一些特定的信息,具体想看的话可以看上面那个传送门。

3.OptionalHeader(IMAGE_OPTIONAL_HEADER32)

 前言:可选头有两个版本分别为32位版本(IMAGE_OPTIONAL_HEADER32)和64位版本(IMAGE_OPTIONAL_HEADER64)这两个结构分别在_IMAGE_NT_HEADERS和_IMAGE_NT-HEADER64结构中。可选择头是这个结构中最重要的一部分,当文件被执行时这里的属性会被加载到内存中并且执行。

可选择头有两个版本,这两个版本之间有一些区别:

1.32位的可选择头,它一共有31个成员而64位的可选择头有30个成员。多了一个DWORD BaseOfData,它存的是镜像被加载到内存中的数据节的RVA。

2.有五个成员,在32位的可选择头和64位的可选择头结构中的数据类型是不同的,这个就不一一列举了。

下面是可选择头的具体结构: 

//
// Optional header format.
//

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
    WORD        Magic;
    BYTE        MajorLinkerVersion;
    BYTE        MinorLinkerVersion;
    DWORD       SizeOfCode;
    DWORD       SizeOfInitializedData;
    DWORD       SizeOfUninitializedData;
    DWORD       AddressOfEntryPoint;
    DWORD       BaseOfCode;
    ULONGLONG   ImageBase;
    DWORD       SectionAlignment;
    DWORD       FileAlignment;
    WORD        MajorOperatingSystemVersion;
    WORD        MinorOperatingSystemVersion;
    WORD        MajorImageVersion;
    WORD        MinorImageVersion;
    WORD        MajorSubsystemVersion;
    WORD        MinorSubsystemVersion;
    DWORD       Win32VersionValue;
    DWORD       SizeOfImage;
    DWORD       SizeOfHeaders;
    DWORD       CheckSum;
    WORD        Subsystem;
    WORD        DllCharacteristics;
    ULONGLONG   SizeOfStackReserve;
    ULONGLONG   SizeOfStackCommit;
    ULONGLONG   SizeOfHeapReserve;
    ULONGLONG   SizeOfHeapCommit;
    DWORD       LoaderFlags;
    DWORD       NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

八个标准成员:

1.Magic:表示这是一个32-bit或者64-bit的可执行文件。对于Windows的PE Loader,它会忽视文件头中的Machine。

2.MajorLinkerVersion:链接器的主版本号。

3.MinorLinkerVersion:链接器的次版本号。

4.SizeOfCode:代码块的大小,代码是放在.text文件里的。

5.SizeOfInitializedData:初始化的数据的数据块大小。这些初始化的数据放在.data的文件中。

6.SizeOfUninitializedData:未初始化的数据的数据块的大小。这些未初始化的数据放在后缀为.dss的区块下。

7.AdressOfEntryPoint:镜像文件被加载到内存中时,它代表了一个入口点的RVA(Relative Virtual Address)。

8.BaseOfCode:代码基址,表示的是镜像文件被加载到内存中的代码节的RVA。

9.BaseOfData(32-bit):数据基址,表示镜像文件被加载到内存中的数据节的RVA。(偷偷加一个应该没人看见【滑稽】)

 

下面就是一些sections。说实话,看英文比中文更好理解。但是有一点我今天才弄懂,在英文文章中我们总能看见一个词"image",比如"image file",这个是个镜像文件。那么什么是镜像文件呢?当一个可执行文件run之前,它会由OS loader加载进内存中,分配虚拟内存空间 。这种行为类似于复制该文见到机器给它分配到的空间中去,所以用"image"来修饰这个文件,这就显得很形象了。

 

 拓展内容:

1.ImageBase:镜像文件被加载进入内存时的第一个字节的首选地址,它必须是64k的倍数。它实际上是用来定为的,因为镜像文件存储的内存空间实际上是和实际空间不一样的,需要通过这个基址来给“头”和“节”进行重定位。

2.SectionAlignment:字节对齐,这里面存的值是用来使字节对齐的值(以字节计)。

3.FileAlignment:文件对齐,用来对齐文件的节中的原始数据因子(以字节计)。

注:这两个对齐我没怎么理解。

4.MajorOperatingSystemVersion,

 MinorOperatingSystemVersion, 

MajorImageVersion, MinorImageVersion, 

MajorSubsystemVersion, 

MinorSubsystemVersion:我来按照顺序翻译一下。主操作系统版本号,次操作系统版本号,镜像文件主版本号,镜像文件次版本号,子系统主版本号,主系统次版本号。

5.Win32VersionValue:这是一个保留值,必须为0.

6.SizeOfImage:镜像的大小(以字节计),它的大小是为SectionAlignment整数倍。因为可执行文件要被加载到内存中,而机器分配给它空间方式是连续的整块。实际上这样会使文件加载后所占内存空间比实际空间更大。

7.SizeOfHaeders:所有头的总大小(以字节计算),它的大小为FileAlignment的整数倍,向上取整(显然,上面那个也是)。

8.CheckSum:翻译过来是叫验效和。在加载时检测这个文件是否合法。

9.SubSystem:运行镜像所需要的子系统,对应的值可以去microslft的官网里面去看,传送门在上边。

10.DLLcharacteristic:定义一些属性,普通文件都有这个。比如说,0x0040代表着DLL能够被重定位,0x0100代表着这个PE文件被提供了一种内存保护机制——NX(Non-Executable)位是一种硬件支持的内存保护技术,可以防止缓冲区溢出等攻击。

11.SizeOfStackReserve,SizeOfStackCommit: 栈保留大小和初始的栈提交大小。这里的栈是CPU的栈。

12.SizeOfHeapReserve,SizeOfHeapCommit:堆保留大小和初始的堆提交大小。

13.LoaderFlags:保留区域,set为0。

14.NumberOfRvaAndSizes:是数据目录表的数组大小。

15.DataDirectory:数据目录表,一个结构体数组。

 看一下最后一个数据目录表,它的结构里面存的是表大小和表的虚拟地址。

这些是本次的学习笔记,等完全学完后再完整地整理一下优化一下这些笔记(先立一个flag)其实还想写一下解析文件地C程序(已经写了一部分了),等有之后全写了(再立一个flag)。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值