• PE文件格式详解(八)


    0x00 前言

      前面了解了PE文件的输入和输出,今天来看看另一个重要的结构——资源。资源结构是很典型的树形结构,层层查找,最终找到资源位置。

    0x01 资源结构介绍

    Windows程序的各种界面成为资源,包括加速键,位图,光标,对话框,图标,菜单,串标,工具栏,版本信息等等,在所有的PE文件中资源结构是最为复杂的。下图为资源的树形结构图:

       通常来讲,资源的目录为三层结构。最上面的为根目录,它存储了资源的类型同时存储指向下一级的指针,二级目录包含资源id(至于啥事资源ID后面会讲到)和指向第三级的指针,三级目录存储资源代码和指向真正资源的指针。这里最要理解的是这三级目录用的都是同一结构。这个结构包含两个子结构——资源目录结构(IMAGE_RESOURCE_DIRECTORY)和资源目录入口地址结构(IMAGE_RESOURCE_DIRECTOTY_RNTRY)。理解了这两个结构各自的作用就能明白整个资源结构。下面分别从这两个结构讲起。

    0x02 资源目录结构(IMAGE_RESOURCE_DIRECTORY

    资源目录结构是由数据目录表的第三个子项(Resource Table)所指向的(想想数据目标表有多重要把,基本上后面所讲都要从它开始)。该结构包含16个字节,共6个字段,下面的该结构的定义:

    // 【资源表位于数据目录表的第三项,共动态分配字节, 其中结构体中的成员指出的RVA偏移量都是对于此结构体的地址作为基地址】

    typedef struct _IMAGE_RESOURCE_DIRECTORY

    {

    DWORD Characteristics; //理论上为资源的属性,不过事实上总是0

    DWORD TimeDateStamp; //资源的产生时刻

    WORD MajorVersion; //理论上为资源的版本,不过事实上总是0

    WORD MinorVersion

    WORD NumberOfNamedEntries;      //以名称(字符串)命名的入口数量

    WORD NumberOfIdEntries; //ID(整型数字)命名的入口数量

    } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

    这六个字段真正有用的是最后两个字段:

    WORD NumberOfNamedEntries:标明入口数量,所谓入口数量,资源目录入口地址结构(IMAGE_RESOURCE_DIRECTOTY_RNTRY)结构的数量,这个结构都是紧紧跟着资源目录结构(IMAGE_RESOURCE_DIRECTORY),不过它标记数量的方式是用字符串。

    WORD NumberOfIdEntries:这个字段本质上和前一个字段一模一样,不过它是用id来标明数量。注意:最后统计资源入口地址结构数量的时候是这两个的相加的和。

    0x03 资源目录入口地址结构(IMAGE_RESOURCE_DIRECTORY_ENTRY

     资源目录入口地址结构虽然很简单,但是却非常重要。它不仅包含了指向下一级目录的地址,好包含了指向真正资源的数据入口地址。

    typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY

    {

    DWORD  Name;        //目录项的名称字符串指针或者ID

    DWORD  OffsetToData;    //资源数据偏移地址或者子目录偏移地址

    }_IMAGE_RESOURCE_DIRECTORY_ENTRY, *P_IMAGE_RESOURCE_DIRECTORY_ENTRY;

    这两个字段都是极为重要的,下面将详细讲解这两个字段的含义:

    Name:大小为双字,该字段定义了目录项的名称或者ID。当用于第一级目录时,它表示的是资源的类型,用于第二级目录时表示资源的名称,用于第三级目录时,用于表示资源的代码页号编号。当最高位是0的时候,表示字段的值作为ID来使用(前面说了该字段可以表示资源的类型,资源的类型就是用ID来区分的,不同资源类型ID不一样)。当最高位是1时,地位字段表示一个指针,这个指针就是指向了资源的名称的UNICODE编码(前面也讲到该字段可以表示目录的名称)。下表统计了系统已经定义的资源类型。表一

    类型ID

    资源类型

    类型ID

    资源类型

    01h

    光标(Cursor

    08h

    字体(Font

    02h

    位图(Bitmap

    09h

    加速键(Accelerator

    03h

    图标(Icon

    0ah

    未格式资源(Unformatted

    04h

    菜单(Menu

    Obh

    消息表(MessageTable

    05h

    对话框(Dialog

    0ch

    光标组(Group Cursor

    06h

    字符串(Stiring

    0eh

    图标组(Group Icon

    07h

    字体目录(Font Directory

    10h

    版本信息(Version Information

    OffsetToData:双字结构,是一个指针。当最高为为1时,低位指向的是下一级目录的起始地址,当最高为是0时,指向的是真正的数据资源的目录入口结构(IMAGE_RESOURCR_DIRCTORY_DATA)。

    重要说明:当字段NameOffset作为指针时,该指针是从资源区块开始的地方算起的偏移量,不是RVA,即根目录的起始位置偏移量(就是从第一级资源目录结构(IMAGE_RESOURCE_DIRECTORY)的起始地址算起

    0x03 实例讲解资源的结构

    工具:hexworkshoplordPE,目标PE文件:pediy.exe

    下面我将一级级逐级追击资源:

    1)根目录

    首先找到数据目录表的第三项,它指向了第一级目录即根目录地址。它在PE文件头偏移88h处。地址为:0ch+88h=148h。直接跳转至148h处,如下图:

    标明RVA=4000h,这里本来如果要跳转至根目录是要进行地址转化,但是这里是特殊情况,由于这个PE文件磁盘分页和内存分页的值相等,故RVA=Offset,缘由可看下图:

     我们现在直接跳转至4000h处,该处即为根目录起始地址,如下图:

     现在我们按照顺序以西读出这个第一个结构IMAGE_RESOURCE_DIRECTORY的六个字段的值。记在下表中:表二

    Charateristics

    TimeStamp

    MajorVersion

    MinnorVersion

    NumberOfEntris

    NumberOfIdEntries

    0000 0000

    0000 0000

    0000

    0000

    0000

    0003

    由最后两个字段可知紧随IMAGE_RESOURCE_DIRECTORY的共有三个IMAGE_RESOURCE_DIRECTORY_ENTRY结构,如下图:

     依次将数据读出登记在下表:表三

    第一个Dir_entry结构

    第二个Dir_entry结构

    第三个Dir_entry结构

    偏移地址

    4010h

    4018h

    4020h

    字段Name

    0000 0003h

    0000 0004h

    0000 000Eh

    字段OffsetToData

    8000 0028h

    8000 0040h

    8000 0058h

     由于有三个下级目录,我们就以第二个IMAGE_RESOURCE_DIRECTORY_ENTRY结构来分析下一级资源结构。

    2)二级目录

      根目录的IMAGE_RESOURCE_DIRECTORY_ENTRY结构的字段Name=0000 0004h,最高为0,所以它表示资源类型,低位值为0004h,这个资源的ID号,查询表一可得这是个菜单(Mune资源)。再来看字段OffsetToData=8000 0040h,明显最高为是1,所以这个指针指向的是下一级资源目录。其低31位值是40h,这个就是下级目录距离根目录的偏移地址,地址为:

    4000h+40h=4040h。我们跳往地址4040h处,得到下图:

     依次读出IMAGE_RESOURCE_DIRECTORY结构的六个字段统计在下表:

    Charateristics

    TimeStamp

    MajorVersion

    MinnorVersion

    NumberOfEntris

    NumberOfIdEntries

    0000 0000

    0000 0000

    0000

    0000

    0000

    0000 0001

    根据最后一个字段可知,紧跟这结构IMAGE_RESOURCE_DIRECTORY的结构IMAGE_RESOURCE_DIRECTORY_ENTRY只有一个,如下图:

     我们依次读出两个字段的值:Name=8000 00E8h OffsetToData=8000 0088h。由于字段Name的最高位是1,所以低位字段表示指向结构IMAGE_RESOURCE_DATA_STRING_U结构,这个结构存储了资源名的unicod值,我们跳往40E8h处,如下图:

     由上图可知资源名是PEDIY。第二个字段OffsetToData的最高位是1,低位表示指向下级目录的地址,我们跳往4088h

    3)第三级目录

    跳转至地址4088h,我们来到了第三级目录,如下图:

     依次读出六个字段统计在下表:

    Charateristics

    TimeStamp

    MajorVersion

    MinnorVersion

    NumberOfEntris

    NumberOfIdEntries

    0000 0000

    0000 0000

    0000 0000

    0000 0000

    0000 0000

    0000 0001

    根据最后一个字段可知紧随结构IMAGE_RESOURCE_DIRECTORY只有一个IMAGE_RESOURCE_DIRECTORY_ENTRY结构,如下图:

     字段Name=0000 0409h,字段OffsetToData=0000 00C8h。在第三级目录中Name字段表示代码页编号,这里是409表示英语,OffsetToData最高位是0,低31位作为指针指向资源数据入口结构(IMAGE_RESOURCE_DATA_ENTRY)。该结构的定义如下:

    IMAGE_RESOURCE_DATA_ENTRY STRUCT

       {

    OffsetToData  DWORD //资源数据的RVA

    Size         DWORD//资源数据的长度

    CodePage    DWORD//代码页,一般为0

    Reserved     DWORD//保留字段

    };IMAGE_RESOURCE_DATA_ENTRY ENDS

    我们直接跳转至40c8h处,如下图:

    逐个读出各个字段的值统计在下表中:

    OffsetToData

    Size

    CodePage

    Reserved

    0000 4400

    0000 005a

    0000 0000

    0000 0000

    至此,我们总算找到了资源的真正地址即在字段OffsetToData=4400h,大小为字段Size=5ah。  

    如下图就是资源:

  • 相关阅读:
    求大神回答这个管理系统不知道为啥不成功急!
    这个函数到底什么意思如何调用
    判断浮点数是否为零的问题
    字符串与列表的 常用方法
    变量名命名规范 运算符 流程控制
    ACM C++
    struts s:iterator循环遍历数据 自动生成序号
    JAVA将一个EXCEL多行订单产品字符串分解成一个个子订单 +连接符连接
    JS在HTML中获取到所有选中的checkbox的值
    自己做的java-WEB项目。希望360浏览器能够默认使用极速模式打开
  • 原文地址:https://www.cnblogs.com/2f28/p/9836455.html
Copyright © 2020-2023  润新知