PE 资源表

Posted 不会写代码的丝丽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PE 资源表相关的知识,希望对你有一定的参考价值。

前言

我们在window开发中需要很多资源比如icoaccelerator,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;

其中我们只需要关注NumberOfNamedEntriesNumberOfIdEntries,他们分别表示资源以名称定义和id定义的数量。后面接上IMAGE_RESOURCE_DIRECTORY_ENTRY 数组,大小为NumberOfNamedEntriesNumberOfIdEntries的合。

看看我们本例的结果:

以名称定义的资源数量为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

DUMMYUNIONNAME03 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

DUMMYUNIONNAME05 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分别为103129,也就是我们头文件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 资源表的主要内容,如果未能解决你的问题,请参考以下文章

解析PE资源表与重定位表

ResourceEntries资源表的RVA在复制到不同的映像/ PE时需要重定位吗?

解析PE文件

PE知识复习之PE的导出表

PE知识复习之PE的重定位表

PE文件格式中导入表和ITA表总结20180508