一、前言
二、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结构体
上一篇:导入表
下一篇: