【PE结构】资源表

一、前言
二、PE整体结构
三、DOS头
四、NT头
五、区段头
六、导出表
七、导入表

八、资源表

九、重定位表

1.概念

程序中通常包含图片、菜单、控件、不同样式的文本等多种多样的内容。
这些内容或界面元素,都以二进制的形式保存在PE文件中。
这些数据保存的位置,就是PE文件的资源段(.rsrc)
这些数据的组织格式,我们成为资源表

2.资源表定位

前面提到的 NT头->扩展头->数据目录表->第三个元素->相对虚拟地址(RVA)
还用010Editor打开百度云盘看一下
这里写图片描述
从扩展头里的数据,我们就可以得到资源表的定位信息RVA
资源表所在区段是.rsrc段
这里写图片描述
资源表FOA = 资源表RVA - 区段RVA + 区段FOA = 0x7B7000 - 0x7B7000 + 0x79EA00 = 0x79EA00
这里写图片描述

3.资源表结构

资源表的结构比较复杂,一共有三层,三层从上到下是树状扩展的
第一层数据代表资源种类的数量及名称
第二层数据代表每种资源中资源的数量及名称
第三层数据代表资源文件的位置

每层由一个 IMAGE_RESOURCE_DIRECTORY 结构体和N个 IMAGE_RESOURCE_DIRECTORY_ENTRY 结构体组成。

3.1.IMAGE_RESOURCE_DIRECTORY结构体

typedef struct _IMAGE_RESOURCE_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    WORD    NumberOfNamedEntries;   // 用字符串作为资源标识的条目个数
    WORD    NumberOfIdEntries;      // 用数字ID作为资源标识的条目个数
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

十六个字节

3.2.IMAGE_RESOURCE_DIRECTORY_ENTRY结构体

IMAGE_RESOURCE_DIRECTORY_ENTRY 的个数 = IMAGE_RESOURCE_DIRECTORY.NumberOfNamedEntries + IMAGE_RESOURCE_DIRECTORY.NumberOfIdEntries

这个结构体在每一层中都是以结构体数组的方式存在
第一层,每个元素代表一种资源
第二层,每个元素代表一个资源
第三层,每个元素代表一个资源的位置

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
    union {
        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;

该结构体一共8字节,里面包含两个联合体,每个联合体4字节
第一个联合体,表示资源的名称
第二个联合体,表示资源的位置

3.2.1.第一个联合体
  • 如果最高位为0,也就是NameIsString为0
    此时4字节代表资源类型,也就是ID起作用
资源类型资源类型
0x01鼠标指针0x08字体
0x02位图0x09快捷键
0x03图标0x0A非格式化资源
0x04菜单0x0B消息列表
0x05对话框0x0C鼠标指针组
0x06字符串列表0x0E图标组
0x07字体目录0x10版本信息
  • 如果最高位为1,也就是NameIsString为1
    这是NameOffset指向保存字符串的结构体
typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
    WORD    Length;
    WCHAR   NameString[ 1 ];
}IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U;

第二个元素NameString为字符串起始,长度为Length,这个串不是以0结尾哦。

3.2.2.第二个联合体
  • 如果最高位为1,也就是DataIsDirectory为1
    代表OffsetToDirectory指向的地方是一个目录
    通常,第一层和第二层,这个值都是1
  • 如果最高位为0,也就是DataIsDirectory为0
    代表OffsetToDirectory指向的地方是一个数据
    通常,第三层,这个值为0

3.3.IMAGE_RESOURCE_DATA_ENTRY结构体

这个结构体是第三层指向的,最终资源的结构体

typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
    DWORD   OffsetToData;   // 资源偏移,RVA
    DWORD   Size;           // 资源大小
    DWORD   CodePage;       // 资源页属性
    DWORD   Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

4.资源表查找

4.1.第一层

  • 通过数据目录表第三个元素找到资源表起始位置
  • 在Directory结构体中,可知道紧挨在结构体后面,有N种资源存在
  • 接下来是N的元素的Directory_Entry结构体数组
  • Directory_Entry中第一个4字节,如果最高位为0,即NameIsString为0,标识是已知资源类型,ID起作用
  • Directory_Entry中第一个4字节,如果最高位为1,即NameIsString为1,NameOffset指向资源名结构体
  • Directory_Entry中第二个4字节,如果最高位为1,表示指向的是一个目录,目标是第二层的Directory

4.2.第二层

  • 这里会是以下结构[D*1][DE*N][D*1][DE*N]……
  • 在Directory结构体中,可知道紧挨在结构体后面,有N个当前种类的资源存在
  • Directory_Entry中,第一个4字节和第二个4字节的判断规则和第一层一样

4.3.第三层

  • 在Directory结构体中,第一个4字节(联合体)代表资源是什么语言
  • 在Directory结构体中,第二个4字节(联合体)的DataIsDirectory为0,代表指向的地方是一个具体内容,也就是资源位置。
  • OffsetToData会指向IMAGE_RESOURCE_DATA_ENTRY结构体

上一篇:【PE结构】导入表
下一篇:【PE结构】重定位表


版权声明:本文为chy_chenyang原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。