《Windows PE》7.2 资源表

PE(可执行文件格式)资源表是 Windows 操作系统中用于存储和管理可执行文件中各种资源的一种结构。它是一个层次化的资源目录,通过索引和标识符来查找和访问资源。

PE 资源表包含了多种类型的资源,例如位图、图标、光标、对话框、字符串、版本信息等。每个资源都有一个唯一的标识符和类型,用于在资源表中定位和识别。本节我们将讲述资源表的数据结构以及如何定位资源表。资源表的RVA地址和大小位于数据目录项第2项。

本节必须掌握的知识点:

        资源表结构解析

        资源表定位

7.2.1 资源表结构解析

PE资源表的结构如下

●资源目录表(Resource Directory Table):资源目录表是资源表的顶层结构,它包含了指向各个资源类型的目录项的指针。

●资源类型目录表(Resource Type Directory Table):资源类型目录表包含了每个资源类型的目录项,例如位图、图标、对话框等。

●资源名称/标识符目录表(Resource Name/Identifier Directory Table):资源名称/标识符目录表包含了每个资源类型下的资源名称或标识符的目录项。

●资源数据目录表(Resource Data Directory Table):资源数据目录表包含了每个资源的实际数据的位置和大小。

通过 PE 资源表,操作系统和应用程序可以轻松地访问和加载可执行文件中的资源。开发人员可以使用资源编辑器或编程工具来创建、编辑和管理 PE 资源表中的资源。

在程序中,可以使用 Win32 API 函数(如 FindResource、LoadResource)来加载和访问 PE 资源表中的资源,以满足程序的需求并提供更丰富的用户界面和功能。

●三级目录结构

PE的资源组织方式类似于操作系统的文件管理方式。从根目录开始,下设一级子目录、 二级子目录和三级子目录;三级子目录下才是文件。其三级目录结构如图7-1所示。

图7-1 三级目录结构

1.一级子目录按照资源类型分类,如”光标” 一级子目录、“位图” 一级子目录、“菜单” 一级子目录、“字符串” 一级子目录、“加速键” 一级子目录等多个资源类型。

2.二级子目录按照资源的ID分类。例如,同样是“菜单” 一级子目录的内容,其下可以有: IDM_OPEN的ID号为2001,IDM_EXIT的ID号为2002,IDM1的ID号为4000等多个菜单项。

3.三级子目录是按照资源的代码页分类,即不同的语言代码页对应不同的数据。其中,根据语言可以分为简体中文、英文、繁体中文等多个代码页。

4.三级目录后即为节点,也就是所说的“文件”。这里的“文件”其实就是包含了资源数据的指针和大小等信息的一个数据结构而已。对所有资源数据块的访问均可从这里开始。

●资源目录结构单元

由于一、二、三级目录的数据结构是相同的,均是由一个资源目录头加上多个线性跟随 着的资源目录项组成,我们可以将主干和枝干的节点称为资源目录结构单元,如图7-2所示。

图7-2 资源目录结构单元

从数据结构角度来看,资源表是一个四层的二叉排序树结构。其中,第一层为主干,第二、三层为枝干,叶子节点为第四层。主干和枝干的节点即为资源目录结构单元,完整示意见图7-3。

图7-3 资源表的二叉树结构

资源表的结构虽然比较复杂,但并不难理解。下一节我们将分析资源表在PE文件中的详细定义和定位。

资源目录头

资源表数据从第一级资源目录开始。资源的每一级目录都会有一个资源目录头,它标识 了该类资源的属性、创建日期和版本等信息,其中也包含了随后的目录项的数量描述信息。 详细结构定义如下:

typedef struct _IMAGE_RESOURCE_DIRECTORY {

    DWORD   Characteristics;    // 资源目录的特性标志,通常为 0

    DWORD   TimeDateStamp;   // 资源目录的时间戳,表示目录的创建或修改时间

    WORD    MajorVersion;            // 资源目录的主版本号

    WORD    MinorVersion;            // 资源目录的次版本号

    WORD    NumberOfNamedEntries;  // 命名目录项的数量

    WORD    NumberOfIdEntries;       // 标识符目录项的数量

    // Array of IMAGE_RESOURCE_DIRECTORY_ENTRY structures

    // followed by resource directory entries (subdirectories or leaf nodes)

} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

IMAGE_RESOURCE_DIRECTORY 结构中的字段的含义如下:

1.Characteristics:资源目录的特性标志,通常为 0。该字段目前保留,未使用。

2.TimeDateStamp:资源目录的时间戳,表示目录的创建或修改时间。该字段用于跟踪资源目录的变化。

3.MajorVersion 和 MinorVersion:资源目录的版本号,用于指示资源目录的版本信息。这些版本号可以用于识别资源目录的格式和兼容性。

4.NumberOfNamedEntries:资源目录中的命名目录项的数量。命名目录项是根据名称进行索引的子目录或叶节点。

5.NumberOfIdEntries:资源目录中的标识符目录项的数量。标识符目录项是根据标识符进行索引的子目录或叶节点。

IMAGE_RESOURCE_DIRECTORY 结构后面紧跟着一个由 IMAGE_RESOURCE_DIRECTORY_ENTRY 结构组成的数组,用于表示资源目录的子目录或叶节点。每个 IMAGE_RESOURCE_DIRECTORY_ENTRY 结构表示一个子目录或叶节点,并包含了子目录或叶节点的偏移地址或资源标识符。

通过 IMAGE_RESOURCE_DIRECTORY 的层次结构,可以遍历和访问 PE 资源表中的不同类型的资源以及它们的子目录。这样,操作系统和应用程序可以根据需要加载和使用所需的资源。

资源目录项

IMAGE_RESOURCE_DIRECTORY_ENTRY 是 PE(可执行文件格式)中资源表中的一个目录项,用于表示资源目录的子目录或叶节点。

以下是 IMAGE_RESOURCE_DIRECTORY_ENTRY 的定义:

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {

    union {                   //目录项的名字、字符串指针或ID号

        struct {

            DWORD NameOffset : 31; // 命名目录项的名称偏移地址

            DWORD NameIsString : 1; // 标志,指示命名目录项是否为字符串

        } DUMMYSTRUCTNAME;

        DWORD   Name;              // 标识符目录项的资源标识符

        WORD    Id;                  // 标识符目录项的整数标识符

    } DUMMYUNIONNAME;

    union {

        DWORD   OffsetToData;        // 子目录或叶节点的偏移地址

        struct {

            DWORD   OffsetToDirectory : 31;  // 子目录的偏移地址

            DWORD   DataIsDirectory : 1;     // 标志,指示目录项是否是子目录

        } DUMMYSTRUCTNAME2;

    } DUMMYUNIONNAME2;

} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

IMAGE_RESOURCE_DIRECTORY_ENTRY 结构包含了以下几个重要的字段:

1.NameOffset:命名目录项的名称偏移地址。如果 NameIsString 标志位为 1,则该字段表示命名目录项的名称在资源表字符串表中的偏移地址;如果 NameIsString 标志位为 0,则该字段表示命名目录项的资源标识符ID的低 31 位。

2.NameIsString:标志位,指示命名目录项是否为字符串。如果该标志位为 1,则 NameOffset 字段表示命名目录项的名称在资源表字符串表中的偏移地址。表示命名目录项使用的是字符串名称,而不是整数标识符。此时,NameOffset 字段指向的是一个 IMAGE_RESOURCE_DIR_STRING_U 结构,其中存储了字符串的长度和内容。

以下是 IMAGE_RESOURCE_DIR_STRING_U 结构的定义:

typedef struct _IMAGE_RESOURCE_DIR_STRING_U {

    WORD   Length;               // 字符串长度(以字节为单位)

    WCHAR  NameString[1];        // 字符串内容

} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;

3.Name:标识符目录项的资源标识符。如果 NameIsString 标志位为 0,则该字段表示标识符目录项的资源标识符。

4.Id:标识符目录项的整数标识符。如果 NameIsString 标志位为 1,则该字段表示标识符目录项的整数标识符。

5.OffsetToData:子目录或叶节点的偏移地址。如果 DataIsDirectory 标志位为 0,则该字段表示叶节点的偏移地址;如果 DataIsDirectory 标志位为 1,则该字段表示子目录的偏移地址。

6.OffsetToDirectory:子目录的偏移地址。如果 DataIsDirectory 标志位为 1,则该字段表示子目录的偏移地址。

7.DataIsDirectory:标志位,指示目录项是否是子目录。如果该标志位为 1,则 OffsetToData 字段表示子目录的偏移地址。

通过 IMAGE_RESOURCE_DIRECTORY_ENTRY 结构的字段,可以确定目录项是指向子目录还是叶节点,并获取相应的偏移地址或资源标识符。这样,可以在资源表中导航和访问不同类型的资源。

图7-4 资源目录及目录项之间的关系

资源数据项

IMAGE_RESOURCE_DATA_ENTRY 是 PE(可执行文件格式)中资源表中的一个数据项,用于表示资源的实际数据。

以下是 IMAGE_RESOURCE_DATA_ENTRY 的定义:

typedef struct _IMAGE_RESOURCE_DATA_ENTRY {

    DWORD   OffsetToData;            // 数据的偏移地址

    DWORD   Size;                   // 数据的大小

    DWORD   CodePage;              // 数据的代码页

    DWORD   Reserved;               // 保留字段,一般为 0

} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

IMAGE_RESOURCE_DATA_ENTRY 结构包含了以下几个字段:

1.OffsetToData:数据的偏移地址。该字段指示了资源数据在 PE 文件中的偏移位置。

2.Size:数据的大小,以字节为单位。该字段表示了资源数据的实际大小。

3.CodePage:数据的代码页。该字段指示了资源数据所使用的字符编码。

4.Reserved:保留字段,一般为 0。

通过解析 IMAGE_RESOURCE_DATA_ENTRY 结构,可以获取资源数据的偏移地址、大小和代码页信息。这些信息可以用于在 PE 文件中定位和提取资源数据。

在资源表中,IMAGE_RESOURCE_DIRECTORY_ENTRY 的 OffsetToData 字段指向一个 IMAGE_RESOURCE_DATA_ENTRY 结构,该结构描述了资源数据的位置和相关属性。通过这个结构,可以按需加载和使用 PE 文件中的资源数据。

图7-5 资源数据块定位中的资源数据项

提示

       32位PE和64位PE文件中的资源表完全相同。

7.2.2 资源表定位

实验四十八:定位资源表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值