PE之资源文件结构详解
由DOS头 结构0X3C 地值指向PE头地址
由图知PE头地址为0X200
由PE头地址 + 0x88 定位到数据目录表的第三项 资源项 IMAGE_DIRECTORY_ENTRY_RESOURCE 该结构包含8个字节
前四个字节 存储资源的RVA 0x282000 后四个字节存储 资源的SIZE 0x34c00
查看文件节表 知道资源位于.rsrc块中
由此计算出 文件偏移 = 0x212600 + (0x282000 – 0x282000)= 0x212600 跳转带资源块中
资源目录结构中的每一个节点都是由 IMAGE_RESOURCE_DIRECTORY结构和紧随其后的数个IMAGE_RESOURCE_DIRECTORT_ENTRY结构组成 这两种结构组成一个目录块
一般为三层 :第一层资源类型,第二层是资源名,第三层是资源代码页
1
资源目录结构(16个字节,4个字段)
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics; // 理论上是资源的属性标志,但是通常为0 DWORD TimeDateStamp; //资源建立的时间 WORD MajorVersion; //主版本 WORD MinorVersion; //次版本
WORD NumberOfNamedEntries; //使用名字的资源条目的个数 WORD NumberOfIdEntries; //使用ID数字资源条目的个数 // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
NumberOfNamedEntries(以字符串命名的资源数量) 和NumberOfIdEntries(以整型数字来命名的资源数量)两个字段 说明了本目录中目录项的数量,两者加起来即为后面紧跟的IMAGE_RESOURCE_DIRECTORY_ENTRY的数目
资源目录入口结构(8个字节,2个字段)
紧跟着资源目录结构后的就是资源目录入口结构,此结构长度为8个字节 typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { union {
struct {
DWORD NameOffset:31; DWORD NameIsString:1; };
DWORD Name; //目录项的名字字符串指针或ID
2
WORD Id; };
union {
DWORD OffsetToData; //资源数据偏移地址或子目录偏移地址 struct {
DWORD OffsetToDirectory:31; DWORD DataIsDirectory:1; }; };
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
(1).Name字段 :定义目录项的名字或者ID
作为指针时:该指针是从资源区块开始地方算起的偏移量
当结构用于第一层目录时,定义的是资源类型 当结构用于第二层目录时,定义的是资源的名称 当结构用于第三层目录时,定义的是代码页编号
当最高位位0,作为ID使用,范围0-16之间,表示系统预定义的类型
0x01 : 光标 0x05 : 对话框 0x09 : 加速键 0x0E : 图标组 0x02 : 位图 0x06 : 字符串 0x0A : 未格式资源 0x10 : 版本信息 0x03 : 图标 0x07 : 字体目录 0x0B : 消息表 0x04 : 菜单 0x08 : 字头 0x0C : 光标组
当最高位为1时,字段的低位作为指针使用,资源名称字符串是使用的UNICODE编码,这个指针并不指向字符串,而是指向一个IMAGE_RESOURCE_DIR_STRING_U结构 typedef struct _IMAGE_RESOURCE_DIR_STRING_U { WORD Length; //字符串的长度
WCHAR NameString[ 1 ]; //UNICODE字符串,字对其的,长度可变 } IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
(2).OffsetToData字段
该字段是一个指针,当最高位为1,低位数据指向下一目录块的起始地址 为0时,指针指向IMAGE_RESOURCE_DATA_ENTRY结构
作为指针时:该指针是从资源区块开始地方算起的偏移量 typedef struct _IMAGE_RESOURCE_DATA_ENTRY { DWORD OffsetToData; //资源数据的RVA DWORD Size; //资源数据的长度 DWORD CodePage; //代码页一般为0 DWORD Reserved; //保留
3
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
资源数据入口(16个字节)
IMAGE_RESOURCE_DATA_ENTRY(一般是第三层) 该结构描述了资源数据的位置和大小
例子解析
第一层:资源类型
打开资源块
资源目录结构(1个)
struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics; // 0x00000000 DWORD TimeDateStamp; //0x3C272350 WORD MajorVersion; //0x00 WORD MinorVersion; //0x00
WORD NumberOfNamedEntries; //0x00 WORD NumberOfIdEntries; //0x0A }
由此可见有10中资源类型
资源目录入口结构(10个) 0+0X0A = 10 8*10一共占80个字节
当最高位为0,作为ID使用
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
DWORD Name; //ID = 0x01 光标
DWORD OffsetToData; //子目录偏移地址= 0x80000060
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
DWORD Name; //ID = 0x02 位图
DWORD OffsetToData; //子目录偏移地址= 0x800000A8
};
4
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
DWORD Name; //ID = 0x03 图标
DWORD OffsetToData; //子目录偏移地址= 0x80000168
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
DWORD Name; //ID = 0x05 对话框
DWORD OffsetToData; //子目录偏移地址= 0x80000180
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { DWORD Name; //ID = 0x06 字符串
DWORD OffsetToData; //子目录偏移地址= 0x80000A1A0
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { DWORD Name; //ID = 0x0A 未格式资源
DWORD OffsetToData; //子目录偏移地址= 0x80000248
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { DWORD Name; //ID = 0x0C 光标组
DWORD OffsetToData; //子目录偏移地址= 0x800002E0
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { DWORD Name; //ID = 0x0E 图标组
DWORD OffsetToData; //子目录偏移地址= 0x80000328
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { DWORD Name; //ID= 0X10 版本信息
DWORD OffsetToData; //子目录偏移地址= 0x80000340
};
struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
DWORD Name; //ID= 0X18 24
DWORD OffsetToData; //子目录偏移地址= 0x80000358
};
与PEeditor查看到一致
5