PE文件头可选映像头中数据目录表的第3成员IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]指向映像调试信息,它保存在PE文件中,通常在".rsrc"区段。
程序内部和外部的界面等元素的二进制数据统称为资源,程序把它们放在一个特定的表中,符合数据和程序分离的设计原则。资源包括加速键(Accelerator)、位图(Bitmap)、光标(Cursor)、对话框(Dialog Box)、图标(Icon)、菜单(Menu)、串表(String Table)、工具栏(Toolbar)和版本信息(Version Information)等。
资源有很多种类型,每种类型的资源中可能存在多个资源项,这些资源项用不同的ID 或者名称来区分。但是要将这么多种类型的不同ID 的资源有序地组织起来是一件非常痛苦的事情,因此,我们采取类似于磁盘目录结构的方式保存。
PE 文件中的资源是按照 资源类型 -> 资源ID -> 资源代码页 的3层树型目录结构来组织资源的,通过层层索引才能够进入相应的子目录找到正确的资源。
每一层都是以IMAGE_RESOURCE_DIRECTORY结构为头部的,并且后面跟着一个IMAGE_RESOURCE_DIRECTORY_ENTRY结构数组。其中IMAGE_RESOURCE_DIRECTORY负责指出后面数组中的成员个数,IMAGE_RESOURCE_DIRECTORY_ENTRY数组成员分别指向下一层目录结构。
资源目录结构:
IMAGE_RESOURCE_DIRECTORY与IMAGE_RESOURCE_DIRECTORY_ENTRY结构体定义如下:
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics; //属性,一般为0
DWORD TimeDateStamp; //资源的产生时刻,一般为0
WORD MajorVersion; //主版本号,一般为0
WORD MinorVersion; //次版本号,一般为0
WORD NumberOfNamedEntries; //以名称(字符串)命名的资源数量
WORD NumberOfIdEntries; //以ID(整型数字)命名的资源数量
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
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;
第一层起始于一个IMAGE_RESOURCE_DIRECTORY头,后面紧接着是IMAGE_RESOURCE_DIRECTORY_ENTRY数组。数组个数=NumberOfNamedEntries+NumberOfIdEntries。
IMAGE_RESOURCE_DIRECTORY_ENTRY使用的是Name与OffsetToDirectory,分别代表了资源类型与第二层的数据偏移地址。Name与资源类型的匹配如下:
OffsetToDirectory数据偏移地址是相对整个资源结构来说的,也就是说首个第一层的起始偏移地址加上OffsetToDirectory就是第二层的偏移地址。
与第一层一样,第二层起始于一个IMAGE_RESOURCE_DIRECTORY头,后面紧接着是IMAGE_RESOURCE_DIRECTORY_ENTRY数组。数组个数=NumberOfNamedEntries+NumberOfIdEntries。
IMAGE_RESOURCE_DIRECTORY_ENTRY使用的是NameIsString、NameOffset、Id与OffsetToDirectory。其中OffsetToDirectory与第一层一样,代表了第三层的数据偏移地址,同样是相对整个资源结构来说的。
如果NameIsString=1,说明该资源以名称(UNICODE编码的字符串)定义的,NameOffset是名称的相对整个资源结构的偏移地址。相反,如果NameIsString=0,说明该资源以ID(整型数字)定义的,ID号为Id。
NameOffset相对地址指向的是IMAGE_RESOURCE_DIR_STRING_U结构体,该结构体定义如下:
typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
WORD Length; //字符串的长度
WCHAR NameString[ 1 ]; //UNICODE字符串,由于字符串是不定长的。由Length 制定长度
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
与前两层一样,第二层起始于一个IMAGE_RESOURCE_DIRECTORY头,后面紧接着是IMAGE_RESOURCE_DIRECTORY_ENTRY数组,但不同的是数组个数=1。
IMAGE_RESOURCE_DIRECTORY_ENTRY使用的是Name与OffsetToData,分别代表了资源语言类型与资源数据相对地址。Name是指语言内码,比如936代表简体中文。
OffsetToData是相对整个资源结构的偏移地址,指向一个IMAGE_RESOURCE_DATA_ENTRY结构体,该结构体定义如下:
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
DWORD OffsetToData; //资源数据的RVA
DWORD Size; //资源数据的长度
DWORD CodePage; //代码页, 一般为0
DWORD Reserved; //保留字段
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;