PE文件解析-资源(Resource)

一、位置

    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;

1.第一层

    第一层起始于一个IMAGE_RESOURCE_DIRECTORY头,后面紧接着是IMAGE_RESOURCE_DIRECTORY_ENTRY数组。数组个数=NumberOfNamedEntries+NumberOfIdEntries。

    IMAGE_RESOURCE_DIRECTORY_ENTRY使用的是Name与OffsetToDirectory,分别代表了资源类型与第二层的数据偏移地址。Name与资源类型的匹配如下:

    OffsetToDirectory数据偏移地址是相对整个资源结构来说的,也就是说首个第一层的起始偏移地址加上OffsetToDirectory就是第二层的偏移地址。

2.第二层

    与第一层一样,第二层起始于一个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;

3.第三层

    与前两层一样,第二层起始于一个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;

猜你喜欢

转载自blog.csdn.net/zhyulo/article/details/85930045