Window PE – 资源
资源
Windows程序的各种界面称为资源,包括加速键(Accelerator)、位图(Bitmap)、光标(Cursor)、对话框(DialogBox)、图标(Icon)、菜单(Menu)、串表(StringTable)、工具栏(Toolbar)和版本信息(VersionInformation)等。在PE文件的所有结构中,资源部分是最复杂的。
资源结构
资源用类似于磁盘目录结构的方式保存,目录通常包含3层。第l层目录类似于一个文件系统的根目录,每个根目录下的条目总是在它自己权限下的一个目录。第2层目录中的每一个都对应于一个资源类型(字符串表、菜单、对话框、菜单等)。每个第2层资源类型目录下是第3层目录。
资源目录结构
数据目录表中的IMAGEDIRECTORY_ENTRY_RESOURCE条目包含资源的RVA和大小。资源目录结构中的每一个节点都是由IMAGE_RESOURCE_DIRECTORY结构和紧随其后的数个IMAGE_RESOURCE_DIRECTORY_ENTRY结构组成的,这两种结构组成了一个目录块。
IMAGE_RESOURCE_DIRECTORY结构长度为16字节,共有6个字段,其定义如下。
1 | typedef struct _IMAGE_RESOURCE_DIRECTORY { |
这个结构中让人感兴趣的字段是NumberOfNamedEntries和NumberOfldEntries,它们说明了本目录中目录项的数量。umberOfNamedEntries字段是以字符串命名的资源数量,NumberOfldEntries字段是以整型数字命名的资源数量,两者加起来是本目录中的目录项总和,即紧随其后的IMAGE_RESOURCE_DIRECTORY_ENTRY结构的数量。
资源目录入口结构
紧跟资源目录结构的就是资源目录入口(ResourceDirEntries)结构,此结构长度为8字节,包含2个字段。IMAGE_RESOURCE_DIRECTORY_ENTRY结构定义如下。
1 | typedef struct IMAGE_RESOURCE_DIRECTORY_ENTRY |
根据不同的情况,这2个字段的含义有所不同。
Name字段:定义目录项的名称或ID。当结构用于第1层目录时,定义的是资源类型;当结构用于第2层目录时,定义的是资源的名称;当结用于第3层目录时,定义的是代码页编号。当最高位为0时,表示字段的值作为ID使用;当最高位为1时,表示字段的低位作为指针使用,资源名称字符串使用Unicode编码,这个指针不直接指向字符串,而指向一个IMAGE_RESOURCE_DIR_STRING_U结构。Name字段定义如下。
1
2
3
4
5
6IMAGE RESOURCE DIR STRING U STRUCT
Length
NameStr in g
WORD ?
WCHAR ?
IMAGE RESOURCE DIR STRING U ENDS
- OffsetToData字段:一个指针当最高位(位31)为1时,低位数据指向下一层目录块的起始地址;当最高位为0时,指针指向IMAGE_RESOURCE_DATA_ENTRY结构。在将Name和OffsetToData作为指针时需要注意,该指针从资源区块开始处计算偏移量,并非从RVA(根目录的起始位置)开始处计算偏移量。
有一点要说明的是,当IMAGE_RESOURCE_DIRECTORY_ENTRY在第1层目录中,它的Name字段作为资源类型使用。当资源类型以ID定义且数值在1到16之间时,表示是系统预定义的类型,具体如下表所示。
资源数据入口
经过3层IMAGE_RESOURCE_DIRECTORY_ENTRY(一般是3层,也有可能更少,第1层是资源类型,第2层是资源名,第3层是资源的Language),第3层录结构中的OffsetToData将指向IMAGE_RESOURCE_DATA_ENTRY结构。该结构描述了资、源数据的位置和大小,其定义如下。
1 | IMAGE RESOURCE DATA ENTRY STRUCT |
经过多层结构,此处的IMAGE_RESOURCE_DATA_ENTRY结构就是真正的资源数据了。结构中的OffsetToData指向资源数据的指针(其为RVA值)。