PE 资源表
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PE 资源表相关的知识,希望对你有一定的参考价值。
前言
我们在window
开发中需要很多资源比如ico
和accelerator
,dialog
这些资源都被存放在PE文件的.rsrc
节中。
首先我们需要明白PE存储方式才好解析:
首先是三个三级目录最后才是真正的资源,其中第三个目录使用LCID进行区分地区.具体参阅
谈谈Windows程序中的字符编码
//winnt.h
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
我们举例某个工程
你可以看到这个工程有两个dialog资源,对应的id如下
//Resouce.h
#define IDD_ABOUTBOX 103
#define IDD_DIALOG1 129
首先一级目录地址存放在PE结构中数据目录数组的第三项,索引为2
通过虚拟地址转化1E000h
得到文件偏移9400h
其中对应的数据结构是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
,他们分别表示资源以名称定义和id定义的数量。后面接上IMAGE_RESOURCE_DIRECTORY_ENTRY
数组,大小为NumberOfNamedEntries
和NumberOfIdEntries
的合。
看看我们本例的结果:
以名称定义的资源数量为0,id定义的数量为7.
每个资源的结构如下
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;
这个结构比较晦涩难懂,首先我们来理解DUMMYUNIONNAME
,这个共用体占DWORD
大小,如果最高位为1那么表示这个资源是以名称命名,低31位就是名称节内偏移。如果最高位是0表示id定义的资源,低位word表示资源的id号。
DUMMYUNIONNAME2
比较简单如果是目录最高为1否则为0表示资源,低31位为下一个资源或者目录节内偏移。
本例中的7个资源如下图所示:
第一个资源 就是 03 00 00 00 48 00 00 80
DUMMYUNIONNAME
为 03 00 00 00
因为最高为0,所以表示为以id定义的资源,低word是3所以资源的id是3.
其实3表示的是icon资源,这个定义在WinUser.h文件中如下所示:
//WinUser.h
/*
* Predefined Resource Types
*/
#define RT_CURSOR MAKEINTRESOURCE(1)
#define RT_BITMAP MAKEINTRESOURCE(2)
#define RT_ICON MAKEINTRESOURCE(3)
#define RT_MENU MAKEINTRESOURCE(4)
#define RT_DIALOG MAKEINTRESOURCE(5)
#define RT_STRING MAKEINTRESOURCE(6)
#define RT_FONTDIR MAKEINTRESOURCE(7)
#define RT_FONT MAKEINTRESOURCE(8)
#define RT_ACCELERATOR MAKEINTRESOURCE(9)
#define RT_RCDATA MAKEINTRESOURCE(10)
#define RT_MESSAGETABLE MAKEINTRESOURCE(11)
#define DIFFERENCE 11
#define RT_GROUP_CURSOR MAKEINTRESOURCE((ULONG_PTR)(RT_CURSOR) + DIFFERENCE)
#define RT_GROUP_ICON MAKEINTRESOURCE((ULONG_PTR)(RT_ICON) + DIFFERENCE)
#define RT_VERSION MAKEINTRESOURCE(16)
#define RT_DLGINCLUDE MAKEINTRESOURCE(17)
#if(WINVER >= 0x0400)
#define RT_PLUGPLAY MAKEINTRESOURCE(19)
#define RT_VXD MAKEINTRESOURCE(20)
#define RT_ANICURSOR MAKEINTRESOURCE(21)
#define RT_ANIICON MAKEINTRESOURCE(22)
#endif /* WINVER >= 0x0400 */
#define RT_html MAKEINTRESOURCE(23)
#ifdef RC_INVOKED
#define RT_MANIFEST 24
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2
#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3
#define ISOLATIONPOLICY_MANIFEST_RESOURCE_ID 4
#define ISOLATIONPOLICY_BROWSER_MANIFEST_RESOURCE_ID 5
#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1 /* inclusive */
#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16 /* inclusive */
#else /* RC_INVOKED */
#define RT_MANIFEST MAKEINTRESOURCE(24)
DUMMYUNIONNAME2
的数值为48 00 00 80
因为最高80
对应的二进制最高为1,所以表示下一级为目录,并且偏移量为48
,因为节首地址为940所以下一级地址为:9400h+48h=9448h
我们同过上面头文件知道dialog资源类型为5,所以我们观察本例中dialog的二进制05 00 00 00 00 01 00 80
DUMMYUNIONNAME
为 05 00 00 00
因为最高为0,所以表示为以id定义的资源,低word是5所以资源的id是5.
DUMMYUNIONNAME2
的数值为00 01 00 80
因为最高80
对应的二进制最高为1,所以表示下一级为目录,并且偏移量为100h
,因为节首地址为940所以下一级地址为:9400h+100h=9500h
因为这是个目录所以继续按照_IMAGE_RESOURCE_DIRECTORY
解析
我们本例中其实有两个dialog,所以你会看到 NumberOfIdEntries
为2.
我们首先打开IMAGE_RESOURCE_DIRECTORY
这个目录的两个字目录信息
你会发现他们id分别为103
和129
,也就是我们头文件Resouce.h中定义的
我们只看103
这个
这个条目按照IMAGE_RESOURCE_DIRECTORY_ENTRY解析,67 00 00 00 50 03 00 80
.
50 03 00 80
是这个文件的偏移,80
表示下一级依旧是目录继续按照IMAGE_RESOURCE_DIRECTORY解析,偏移节内地址为350
,所以
地址为9400+350=9750h
继续向下分析:
你可以看到最后一个目录 id为 804
这是他的LCID
也就是表示简体中文,具体参阅谈谈Windows程序中的字符编码
需要注意28 05 00 00
这里最高位为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;
我们最后到IMAGE_RESOURCE_DATA_ENTRY结构中OffsetToData看看他的数据长什么样。
上图高亮区域就是本例中dialog数据的二进制表示,看不懂?没关系看看visual studio中的dialog的二进制你会发现两个文件是一样的
以上是关于PE 资源表的主要内容,如果未能解决你的问题,请参考以下文章