• PE格式第九讲,资源表解析


            PE格式第九讲,资源表解析

    一丶熟悉Windows管理文件的方法

    首先,为什么标题是这个,主要是为了下边讲解资源方便,因为资源结构体很乱.如果直接拿出来讲解,那么就会很晕.

    1.windows管理文件方法

    树形结构

    可以看出结构

    根目录

      子目录

        文件.xxx

      子目录

        子目录 (子目录里面还可以有文件夹)

      .....    

    那么我们的资源也是这样存储的.

    二丶资源结构体解析

    首先,资源结构体分为很多个,但是有用的就3个.一般也分为三个

    IMAGE_RESOURCE_DIRECTORY            根目录(资源目录头)
    
    IMAGE_RESOURCE_DIRECTORY_ENTRY         子目录(资源目录项)其中根目录下可以有很多子目录(也就是说根目录下会有子目录的)
    
    IMAGE_RESOURCE_DATA_ENTRY            文件(资源数据)
    结构体解析:

    1.资源目录头(也可以看做管理文件的根目录)

    typedef struct _IMAGE_RESOURCE_DIRECTORY {
        DWORD   Characteristics;          资源属性
        DWORD   TimeDateStamp;           时间戳
        WORD    MajorVersion;            资源大版本号
        WORD    MinorVersion;            资源小版本号
        WORD    NumberOfNamedEntries;       按照名称命名的数量
        WORD    NumberOfIdEntries;         按照ID命名的数量
    //  IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
    } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

    首先我们看到资源目录头的结构体了,这里大家要知道,有用的就最后两个成员,还有一段注释.

    1.按照名称命名的数量

    意思就是我们的资源是字符串命名加载的有多少个

    2.按照ID命名的数量

    意思就是我们的资源如果按照ID有多少个.

    一般都是用ID的.

    最后两个字段主要是资源的标识,是以ID的有多少个,以字符串标识的有多少个.

    2.资源目录项(子目录)

    typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
        union {
            struct {
                DWORD NameOffset:31;          位段: 低31位飘逝偏移 定义了目录项的名称或者ID
                DWORD NameIsString:1;          位段: 高位, 如果这位为1,则表示31位的偏移指向的是一个Unicode字符串的指针偏移
            };                       这里列出结构体,自己去看,IMAGE_RESOURCE_DIR_STRING_U 里面是字符串长度还有字符串,不是结尾         
            DWORD   Name;                 
            WORD    Id;
        };
        union {
            DWORD   OffsetToData;            偏移RVA因为是联合体,所以有不同的解释
            struct {
                DWORD   OffsetToDirectory:31;    看高位,如果高位是1,那么RVA偏移指向的是新的(根目录)
                DWORD   DataIsDirectory:1;      
            };
        };
    } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

    前边我们说了

    根目录(资源目录头)下面存放的是这个结构体,这个结构体是一个联合体,所以会有不同的解释

    1.首先,联合体是8个字节大小.

    2.其中第一个DWORD大小,看高位,如果高位是1,那么低31位是指向新的目录项名称的结构体IMAGE_RESOURCE_DIR_STRING_U 

    3.如果高位为0,则是ID号,这个ID号说的是 资源ID类型,比如3类型指的就是ICON

    具体,可以随便写个RT_XXX开头的宏去查看.

    这里我写下,跟一下看看.

    4.第二个DWORD量,也是RVA偏移,如果高位为1,那么代表它还是一个目录,也就是指向了一个新的根目录了,这是个不断递归的过程.

    如果不是,则指向文件偏移结构体了.

    文件偏移结构体:(应该是资源数据结构体)

    typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
        DWORD   OffsetToData;          资源数据的偏移RVA
        DWORD   Size;               大小
        DWORD   CodePage;             代码页缓冲(CMD设置窗口的时候就是这个,没用)
        DWORD   Reserved;             保留
    } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

    这个就很简单了,直接前边4个字节指向就是ICON资源的位置.

    三丶实战演练,定位ICON资源.

    看了上面结构体,可能会晕,因为联合体很多,不同的方式有不同的解释方法,那么一步一步的跟随

    1.首先通过数据目录定位资源根目录(也就是根目录,占16个字节,第一个结构体)

    由此得出 RVA = 1B000 

    然后查看属于哪个节

    由此得出,节的虚拟地址也是从1b000开始的,那么直接看文件偏移即可.

    因为此时FA = RVA了,为了方便,一次截图就指明了,在文件的7800h位置

    然后我们定位到7800h的位置

    2.找到位置,查看结构体

    找到位置后,我们对比结构体成员,看看是什么一次,因为这个是资源根目录,所以查看资源根目录结构体

    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;

    我们发现,意思就是按照ID分类的资源有多少个,我们得出是7个,字符串标识的资源有0个,所以不用看了.

    3.定位资源目录项(子目录)

    我们知道,资源根目录下面是子目录,现在有7个按照ID分类的资源,那么就有7个资源目录项(子目录)

    我们看下结构体.

    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;

    首先,我们不要被这个结构体弄晕.我们首先要知道结构体的大小

    结构体是2个union(联合体,共用体),而里面的最大类型是DWORD,所以这个结构体大小是8个字节.

    那么我们就知道了,在资源根目录下有7各这样的数组大小,也就是 7 * 8 = 56字节,整个数组占56个字节

    那么我们看下

    第二个红色箭头没有弄完,截图就完了,不好意思,第二个箭头的意思就是,整个56个字节,是资源目录项,其中黄色区域,属于第一个资源目录项

    那么根据上面的结构体,我们先看黄色区域的第一的4个字节,看看高位是否是1

    这里有两种解释方式

    1.如果高位为1,那么表示一个字符串,那么低31位指向了一个字符串结构体

    2.如果高位为0,那么表示是一个双字节的ID (资源类型)

    现在得出  00000003  很显然,高位为0,那么表示一个资源类型,而资源类型上面看过了,3表示是一个ICON

    那么在看黄色区域的第二的4个字节

    1.高位为1,那么低31位表示指向了一个新的"根目录" (结构体大小还是16个字节,还是最后4个字节有用,也就是上面第一个结构体)

    2.如果高位为0,那么低31位表示指向了一个资源数据结构体(可以表示为文件)

    现在得出, 80000048  很显然高位为1,因为高1位是个8,那么低31位则表示指向一个新的"根目录"

    得出RVA偏移得48

    那么根据刚才的FA = RVA  FA = 7800 那么现在新的目录的FA = 7800 + 48 = 7848

    那么在7848h表示新的根目录,跟过去看下.

    4.定位新的根目录

    可以看出,有是4个新的数据目录项,那么我们接着看下4个数组是什么.

     

    我们还是继续,看资源类型为3的,通过上图,我们得出,资源数据类型为三的(ICON)的高4个字节的高1位还是8

    也就会80000140,那么意思就是又指向了一个新的"根目录"

    5.继续寻找新的根目录

    上图得出 偏移是140  FA = 7800 + 140  = 7940

    那么文件位置7940是新的根目录,接着数16个字节.

    我们看到7940位置是一个新的根目录,那么我们看出,它按照ID分类,就一项了,那么下面8个字节就是数据目录项了.(子目录)

    那么我们由此得出,它的高位不是1,

    现在的 00000238 高位不是1了,那么根据 "子目录"结构体的定义,高位不是1那么这个RVA偏移则是指向了一个文件结构体的偏移

    我们继续计算FA ,一致FA = 7800 ,得出的RVA = 238  则FA = 7800+238 = 7A38h

    6.定位资源数据(文件)

    那么我们定义为7A38的位置,看下资源数据结构是什么样子

    为了防止大家结构体忘记,重新拷贝到这里观看.

    typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
        DWORD   OffsetToData;
        DWORD   Size;
        DWORD   CodePage;
        DWORD   Reserved;
    } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

    就第一个个成员有用,4个字节,表示ICON的RVA偏移.

    那么定位到7A38

    得出第一个成员的RVA偏移是 0001c018

    RVA = 1C018

    按照FA = RVA  ,的知刚才的RVA = 1B000

    求FA = ?

    FA = 1C018 - 1B000 + 7800 =  8818

    那么文件偏移8818的位置,则是ICON的数据了.

    我们看下.

    可以看出,很像图标资源了,那么此时,我们去看下我们的图标二进制,是不是这个.

    对比文件

    我们可以看出,位置确实是这个地方了.那么此时就已经成功的找到了ICON类型的资源了

    作者:IBinary
    出处:http://www.cnblogs.com/iBinary/
    版权所有,欢迎保留原文链接进行转载:)


  • 相关阅读:
    HTML5简易在线画图工具
    HTML Canvas 鼠标画图
    [转]javascript中style.left和offsetLeft的使用
    android中如何获取指定目录下的图片
    Android开发——Android中常见的4种线程池(保证你能看懂并理解)
    Android 文件的读取和写入
    MediaPlayer: Couldn't open /storage/emulated/0/kgmusic/download/独家记忆.mp3: java.io.FileNotFoundExcept
    Android开发-各种各样好看漂亮的进度条,指示器,加载提示汇总
    FileUriExposedException_Android7.0适配
    根据Uri获取文件的绝对路径
  • 原文地址:https://www.cnblogs.com/iBinary/p/7712932.html
Copyright © 2020-2023  润新知