• WindowsPE 第七章 资源表


    资源表

        在程序设计中,总会设计一些数据。这些数据可能是源代码内部需要用到的常量,菜单选项、界面描述等;也可能是源代码外部的,比如程序的图标文件、北京音乐文件、配置文件等,以上这些数据统称为资源。按照程序与数据分离的设计思想,最理想的方案是单独为程序所需要的数据安排一节来存储-PE中的资源就是这么做的。

    7.1资源分类

        资源数据在PE里是最复杂的一种。其难度主要体现在对资源数据的遍历定位上,以及资源块的不易阅读性。因为即使通过信息定位方法找到了资源块,其内部结构还需要进一步解析。首先来看资源分类的历史。

        刚开始资源类型方面,以为16个种类足以了,然而后来发现并不够,这类问题再之前很容易理解。就如千年虫问题...

    程序中常用的六类资源包括:

    位图资源、光标资源、图标资源、菜单资源、对话框资源、自定义资源。

    7.1.1  位图、光标、图标资源

        位图、光标和图标是标识程序用途、修饰程序的最简约的符号,一般对应icocuranibmp文件内容。这三种资源最终都是基于图片文件。在对资源脚本文件进行定义时,通常使用文件名,最后由资源编译器rc.exe将像素数据读入,在转化为二进制格式存储在PE的资源表指向的位置。位图、光标、图标这三类资源在脚本文件中的定义格式如下:


     

    7.1.2  菜单资源

        菜单资源是大部分应用程序都具备的资源。在资源脚本文件中,菜单的定义格式如下所示:

    菜单ID MENU [DISCARDABLE]

    BEGIN

    菜单项定义

    ......

    END

    7.1.3  对话框资源

        对话框也是大部分程序具备的一种资源。弹出式对话框人性化地排列着文本框、说明文字和按钮等可视化控件,使复杂的计算机操作变得容易。语法如下:

    对话框ID DIALOG[DISCARDABLE] x坐标,y坐标,宽度,高度[options]

    BEGIN

    子窗口控件1

    子窗口控件2

    ......

    END

    对话框的可可选属性及描述:



    7.1.4  自定义资源

        通常,当开发者需要在PE文件中附带自定义数据时,可以使用自定义资源。其在资源文件中的定义语法如下:

    资源ID    类型ID  [DISCARDABLE]

    BEGIN

    数据定义

    ......

    END

        大部分情况下,都是讲一个磁盘文件当做资源的内容。此时的语法简化为:

    资源ID 类型ID [DISCARDABLE] 文件名

    类型ID可以是大于255的数值或字符串,如可以定义如下自定义资源:


    7.2  PE资源表组织

        这节主要说PE文件中资源数据的组织方式,并通过实例介绍针对资源数据定义的数据结构以及在PE中定位资源表的方法。

    7.2.1  资源表的组织方式

        PE的资源组织方式类似于操作系统的文件管理方式。从根目录开始,下设一级子目录、二级子目录和三级子目录;三级子目录下才是文件。其三级目录结构如下:


    一级子目录按照资源类型分类。

    二级子目录按照资源ID分类。

    三级子目录按照资源代码页分类。

    三级子目录后即为节点,也就是所说的文件。这里的文件其实就是包含了资源数据的指针和大小等信息的一个数据结构而已。对于所有资源数据块的访问均可以从这里开始。

     

        由于一、二、三级目录的数据结构是相同的,均是由一个资源目录头加上多个现行跟随着的资源目录项组成,将主干和枝干的节点成为资源目录结构单元。如下图:


        从数据结构的角度来看,资源表示一个四层的儿茶排序树结构。其中,第一层为主干,第二、三层为枝干,叶子节点为第四层。主干和枝干的节点即为资源目录结构单元,完整示意图如下:


    7.2.2  资源表数据定位

        资源表是一张描述资源数据在PE中的分布情况的表。资源表是数据目录中注册的数据类型之一,其描述信息位于数据目录第3个目录项中。

     

    7.2.3  资源目录头IMAGE_RESOURCE_DIRECTORY

        资源表数据从第一级资源目录开始。资源的每一级目录都会有一个资源目录头,它标识了该类资源的属性、创建日期和版本等信息,其中也包含了随后的目录项的数量描述信息。

    详细结构定义如下:



    然后是结构详解:

    73.MAGE_RESOURCE_DIRECTORY.Characteristics

    +0000h,双字。资源属性,保留为将来使用,必须为0

    74.MAGE_RESOURCE_DIRECTORY.TimeDateStamp

    +0004h,双字。时间戳,即创建该资源的时间。

    75.MAGE_RESOURCE_DIRECTORY.MajorVersion/MinorVersion;

    +0008h,双字。资源版本号。未用,大部分情况为0

    76.MAGE_RESOURCE_DIRECTORY.NumberOfNamedEntries

    +000ch,双字。以名称命名的资源个数。

    77.MAGE_RESOURCE_DIRECTORY.NumberOfIdEntries

    +000eh,双字。以ID命名的资源个数。

    以上字段中,最重要的是7677两个字段。在资源脚本文件中,定义资源时,既可以使用字符串作为名称来标识一个资源,也可以通过ID号来标识资源。资源目录项的数量等于两者之和。

    7.2.4资源目录项IMAGE_RESOURCE_DIRECTORY_ENTRY 

        紧跟在资源目录后的数据结构,就是在资源目录中声明的资源目录项。一个资源目录可能有多个资源目录项(以名称定义的资源目录项或以ID定义的资源目录项,或两者组合),目录项和目录项之间是线性排列的。首先按照字母升序(不区分大小写)排列名称资源目录项,然后再按照ID升序排列资源目录项。下图是资源目录项及目录项之间的关系示意图。



    资源目录项数据结构的详细定义如下:

     


    上面有一个union定义,我也是第一次看到这个类型,百度了一下:


    78.IMAGE_RESOURCE_DIRECTORY_ENTRY.Namee1

      +0000h,双字。第一个union字段,它定义了目录项的名称或者ID

      该双字的高位(即31位)如果为1,则表示低地址部分为一个纸箱Uniconde字符串的指针(注意,这里的字符串不是Ansi字符串,所以另有规定);如果为0,则表示该字段为一个编号。

    资源中对字符串的定义全部采用Unicode编码,该指针并不是直接指向一个以“”结尾的字符串所在地址,而是指向了结构IMAGE_RESOURCE_DIR_STRING_U

    该结构完善了指针的定义(即不仅包含指针,还包含指针纸箱的块的长度),其详细结构如下:

     

    79.IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData

      +0004h,双字。这个字段是一个指针,当它的高位(第31位)为0时,指针指向的是描述资源数据块的指针,通常出现在第三级目录中;当高位为1时,地位数据指向下一级目录快的起始地址。

    提示:字段7879中的地址并不是基于文件起始地址的,它的偏移是基于资源表的起始位置。一定要清楚这一点,否则在定位资源表的时候会出现错误。

    7.2.5  资源数据项IMAGE_RESOURCE_DATA_ENTRY

        资源数据项其实就是前面所说的目录-文件中的文件。他是通过三次目录定位后找到的一个数据结构,下图显示了资源数据项与三级目录和最终的资源数据块之间的关系。


        第三级目录项中的字段IMAGE_RESOURCE_DIREXTORY_ENTRY.OffsetToData指向了资源数据项,而资源数据项中的OffsetToData字段则指向了资源数据块。

    资源数据项的详细结构如下:


    80.IMAGE_RESOURCE_DATA_ENTRY.OffsetToData

    +0000h,双字。该字段是一个纸箱资源数据块的指针,是一个RVA值,在文件中访问时需要注意转换成文件偏移。此处指向的资源数据块还不是赤裸裸的资源信息,而是附加了一些数据结构的资源快。

    81.IMAGE_RESOURCE_DATA_ENTRY.Size1

    +0004h,双字。资源数据的大小。

    82.IMAGE_RESOURCE_DATA_ENTRY.CodePage

    +0008h,双字。代码页,未用,大多数情况下为0.

    83.IMAGE_RESOURCE_DATA_ENTRY.Reserved

    +000ch,双字。保留字段。总是0

    对资源表的大部分编程,只要能解析出该结构中制定资源快所处的地址和资源快的大小,资源表的使命也就算完成了。

    7.2.6  三级结构中目录项的区别

        由于目录处的级别不同,目录中各字段所表述的内容也不一样;尽管他们具有相同的数据结构和完全相同的字段,在不同级别的目录项中有些数字段的含义是不一样的。

    1.IMAGE_RESOURCE_DATA_ENTRY.Name1

    (1)字段最高位(即31位)为1

      当结构用于第一层目录时,表示这是一个非标准的类型。

      当结构用于第二层目录时,表示这是一个非标准的命名。

      当结构用于第三层目录时,表示这是一个非标准的语言。

    (2)字段31位为0

      当结构用于第一层目录时,表示这是一个标准的类型。

      当结构用于第二层目录时,表示这是一个标准的命名。

      当结构用于第三层目录时,表示这是一个标准的语言。

    2.IMAGE_RESOURCE_DATA_ENTRY.OffsetToData

    (1)字段第31位为1

      当结构用于第一层目录时,下一级目录地址。

      当结构用于第二层目录时,下一级目录地址。

      当结构用于第三层目录时,第31位不为0

    (2)字段第31位为0

      第一层,第二层的这一位都不为0
      当结构用于第三层目录时,表示该字段指向一个数据项IMAGE_RESOURCE_DATA_ENTRY

    注意:由低31位组成的地址是基于资源起始地址的。

  • 相关阅读:
    转:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 解决方案
    Elementui 导航组件和Vuejs路由结合
    python 在线生成文字云
    TensorFlow创建简单的图片分类系统--机器学习
    kettle maven 配置
    Kettle api 二次开发之 日志的保存
    heatmap for arcgisjsapi
    Spring MVC 使用tomcat中配置的数据源
    点坐标旋转方法
    在servlet中使用Spring注入
  • 原文地址:https://www.cnblogs.com/csnd/p/12062081.html
Copyright © 2020-2023  润新知