一、资源表简介
资源表是PE所有表里边最复杂的表,造成资源表复杂是有历史原因的,简单说就是微软设计PE的时候错误的以为只要定义16中资源类型就够了,后来发现远远不够,但是PE结构已经定下来了,只能在原有基础上修改,因此就造成了资源表这块比较不好理解。
所谓的不好理解,就是它里边用到的结构,其中的属性会出现位段/位域的用法,同一个4字节,要根据高位判断它到底是一个整数还是一个偏移;然后偏移并不是RVA,而是相对于资源表的偏移。
但是这些并不能难倒我,我花了一天,把解析程序写出来了。
推荐一本书叫《WINDOWS+PE权威指南》,里面详细说明了资源表的结构,我是看着这本书把程序写出来的。
二、资源表结构的分析
资源表的结构有点像树,长这样:
解析资源表,会涉及到4个结构体,上图包含其中两个,它们分别是:
资源目录 IMAGE_RESOURCE_DIRECTORY
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries;
WORD NumberOfIdEntries;
// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
该结构的 NumberOfNamedEntries 和 NumberOfIdEntries 求和就是紧挨着的资源目录项的数量,其他属性不用管。
资源目录项 IMAGE_RESOURCE_DIRECTORY_ENTRY
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
union {
struct {
DWORD NameOffset:31;
DWORD NameIsString:1;
};
DWORD Name;
WORD Id;
};
union {
DWORD OffsetToData;
struct {
DWORD OffsetToDirectory:31;
DWORD DataIsDirectory:1;
};
};
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
该结构有两个4字节属性,第一个4字节,当高位为1时,低31位存储的是一个偏移,加上资源表的基址,就指向了一个 IMAGE_RESOURCE_DIR_STRING_U 结构,该结构存储了一个Unicode字符串,在第一层,字符串表示资源的名称;在第二层表示资源的非标准命名;在第三层表示非标准代码页。当高位为0时,在第一层低16位表示是16种标准资源类型之一,如ICON;在第二层低16位表示标准命名(预定义的类型);在第三层低16位表示标准代码页,如2052表示简体中文。
第二个4字节属性,在前两层,高位一定是1,在第三层,高位一定是0.
在第一层,低31位表示一个偏移,加上资源表基址就指向了第二层的资源目录 IMAGE_RESOURCE_DIRECTORY;
在第二层,和第一层同理,低31位加上资源表基址指向了第三层的资源目录 IMAGE_RESOURCE_DIRECTORY;
在第三层,低31位是一个偏移,加上资源表基址就指向了一个资源数据项结构 IMAGE_RESOURCE_DATA_ENTRY,该结构存储的是资源的RVA和大小。
Unicode字符串结构体 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;
该结构体存储的是一个Unicode字符串的起始地址,和这个字符串的长度,该结构定义的字符串不以0结尾。
资源数据项 IMAGE_RESOURCE_DATA_ENTRY
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
DWORD OffsetToData;
DWORD Size;
DWORD CodePage;
DWORD Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
存储了资源的RVA和大小。
三、代码
上面的文字说明写得太烂了,还是用代码说明吧?代码写得也烂,但是至少用LordPE验证过解析结果是对的。
// 打印资源表
VOID PrintResourceTable