【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结构体

上一篇:导入表
下一篇:

猜你喜欢

转载自blog.csdn.net/chy_chenyang/article/details/80823775