资源表

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

7.1资源分类

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

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

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

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

7.1.1  位图、光标、图标资源

位图、光标和图标是标识程序用途、修饰程序的最简约的符号,一般对应ico、cur、ani和bmp文件内容。这三种资源最终都是基于图片文件。在对资源脚本文件进行定义时,通常使用文件名,最后由资源编译器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命名的资源个数。

以上字段中,最重要的是76和77两个字段。在资源脚本文件中,定义资源时,既可以使用字符串作为名称来标识一个资源,也可以通过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编码,该指针并不是直接指向一个以“\0”结尾的字符串所在地址,而是指向了结构IMAGE_RESOURCE_DIR_STRING_U。

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

79.IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData

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

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

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位组成的地址是基于资源起始地址的。

WindowsPE 第七章 资源表的更多相关文章

  1. SQL笔记-第七章,表连接

    SQL中使用JOIN 关键字来使用表连接.表连接有多种不同的类型,被主流数据库系统支持的有交叉连接(CROSS JOIN).内连接(INNER JOIN).外连接(OUTTER JOIN),另外在有的 ...

  2. 第七章 资源在Windows编程中的应用 P157 7-8

    资源在基于SDK的程序设计中的应用实验 一.实验目的 1.掌握各种资源的应用及资源应用的程序设计方法.   二.实验内容及步骤 实验任务 1.熟悉菜单资源的创建过程: 2.熟悉位图资源的创建: 3.熟 ...

  3. 【原创】构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测CLR性能

    原文:[原创]构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)-托管资源优化-监测CLR性能 构建高性能ASP.NET站点 第七章 如何解决内存的问题(前中篇)—托管资源优化—监测C ...

  4. 第三百七十四节,Django+Xadmin打造上线标准的在线教育平台—创建课程app,在models.py文件生成4张表,课程表、课程章节表、课程视频表、课程资源表

    第三百七十四节,Django+Xadmin打造上线标准的在线教育平台—创建课程app,在models.py文件生成4张表,课程表.课程章节表.课程视频表.课程资源表 创建名称为app_courses的 ...

  5. 2017.2.28 activiti实战--第七章--Spring容器集成应用实例(五)普通表单

    学习资料:<Activiti实战> 第七章  Spring容器集成应用实例(五)普通表单 第六章中介绍了动态表单.外置表单.这里讲解第三种表单:普通表单. 普通表单的特点: 把表单内容写在 ...

  6. apue第七章学习总结

    apue第七章学习总结 1.main函数 程序是如何执行有关的c程序的? C程序总是从main函数开始执行.main函数的原型是 int main(int argc,char *argv[]); 其中 ...

  7. 第七章——DMVs和DMFs(3)——用DMV和DMF监控TempDB

    原文:第七章--DMVs和DMFs(3)--用DMV和DMF监控TempDB 前言: 我们都知道TempDB是SQLServer的系统数据库,且SQLServer的日常运作严重依赖这个库.因此,监控T ...

  8. Linux内核分析——第七章 链接

    第七章——链接 1.链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载到存储器并执行. 2.链接可以执行于编译时,加载时,运行时. 7.1编译器驱动程序 1.大多数编译系 ...

  9. 【黑金原创教程】【TimeQuest】【第七章】供源时钟与其他

    声明:本文为黑金动力社区(http://www.heijin.org)原创教程,如需转载请注明出处,谢谢! 黑金动力社区2013年原创教程连载计划: http://www.cnblogs.com/al ...

随机推荐

  1. 2018.9.9 nowcoder 普及组第一场

    2018.9.9 nowcoder 普及组第一场 C-括号 题目大意:一个只包含左右括号的字符串\(S\),希望删掉S中若干个字符,使得剩下的字符串是一个合法的括号串,有多少不同的方案. Soluti ...

  2. MySQL二进制安装脚本

    MySQL二进制包自行百度,晚上很多查找办法 #!/bin/bash #二进制安装mysql并初始化密码为123456 mysql_name=mysql-5.7.31-linux-glibc2.12- ...

  3. 基础篇:java.security框架之签名、加密、摘要及证书

    前言 和前端进行数据交互时或者和第三方商家对接时,需要对隐私数据进行加密.单向加密,对称加密,非对称加密,其对应的算法也各式各样.java提供了统一的框架来规范(java.security)安全加密这 ...

  4. 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.AQS框架简介 AQS诞生于Jdk1.5,在当时低效且功能单一的synchroni ...

  5. VScode 自定义用户代码块

    1定义html中的vue 见地址 https://blog.csdn.net/qq_40191093/article/details/82915028 2  https://www.cnblogs.c ...

  6. 用 Go + WebSocket 快速实现一个 chat 服务

    前言 在 go-zero 开源之后,非常多的用户询问是否可以支持以及什么时候支持 websocket,终于在 v1.1.6 里面我们从框架层面让 websocket 的支持落地了,下面我们就以 cha ...

  7. 使用ffmpeg 操作音频文件前后部分静音移除.

    指令特别简单, 但是却琢磨了一下午. 总结看文档时要细心, 主要ffmpeg的版本要 8.2.1 以上 ffmpeg -i in.mp3 -af silenceremove=start_periods ...

  8. Nacos概述及安装

    Nacos是什么? 在Spring Cloud中我们使用eureka.consul等做为服务注册中心,使用Spring Cloud Config做为配置中心.而Spring Cloud中,也可以使用n ...

  9. 学习笔记-git 上传

    0.git add * (如果你需要修改源码需要在 1 之前使用,然后再回到 1) 1.git commit -m '提交文字描述' 2.git push -u origin master (上传到主 ...

  10. Python中切片的应用

    Python中切片的应用 Python中可以通过切片实现对列表或者字符串取指定范围的操作,实际就是通过对列表或者字符串通过索引进行操作. 具体细节点击廖雪峰Python教程,其中的课后小问题在此记录下 ...