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)。
重要说明:当字段Name和Offset作为指针时,该指针是从资源区块开始的地方算起的偏移量,不是RVA,即根目录的起始位置偏移量(就是从第一级资源目录结构(IMAGE_RESOURCE_DIRECTORY)的起始地址算起)
0x03 实例讲解资源的结构
工具:hexworkshop,lordPE,目标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。
如下图就是资源:
PE文件格式详解(八)的更多相关文章
- PE文件格式详解(七)
PE文件格式详解(七) Ox00 前言 前面好几篇在讲输入表,今天要讲的是输出表和地址的是地址重定位.有了前面的基础,其实对于怎么找输出表地址重定位的表已经非常熟悉了. 0x01 输出表结构 ...
- PE文件格式详解,第一讲,DOS头文件格式
PE文件格式详解,第一讲,DOS头文件格式 今天讲解PE文件格式的DOS头文件格式 首先我们要理解,什么是文件格式,我们常说的EXE可执行程序,就是一个文件格式,那么我们要了解它里面到底存了什么内容 ...
- PE文件格式详解,第二讲,NT头文件格式,以及文件头格式
PE文件格式详解,第二讲,NT头文件格式,以及文件头格式 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) PS:本篇博客 ...
- PE文件格式详解,第三讲,可选头文件格式,以及节表
PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...
- PE文件格式详解(六)
0x00 前言 前面两篇讲到了输出表的内容以及涉及如何在hexWorkShop中找到输出表及输入DLL,感觉有几个地方还是没有理解好,比如由数据目录表DataDirectory[16]找到输出表表后以 ...
- PE文件格式详解(下)
作者:MSDN译者:李马 预定义段 一个Windows NT的应用程序典型地拥有9个预定义段,它们是.text..bss..rdata..data..rsrc..edata..idata..pdata ...
- PE文件格式详解(上)
作者:MSDN 译者:李马 摘要 Windows NT 3.1引入了一种名为PE文件格式的新可执行文件格式.PE文件格式的规范包含在了MSDN的CD中(Specs and Strategy, Spec ...
- PE 文件格式详解
PE文件 是微软 Win32 环境下可执行文件的标准格式. 所谓的可执行文件并不仅仅是常见的 EXE 文件,DLL,SYS,VXD 等文件也都属于 PE 格式. |-------> DOS_MZ ...
- PE文件格式详解(一)
PE文件格式介绍(一) 0x00 前言 PE文件是portable File Format(可移植文件)的简写,我们比较熟悉的DLL和exe文件都是PE文件.了解PE文件格式有助于加深对操作系统的理解 ...
随机推荐
- python自学Day05(自学书籍python编程从入门到实践)
第6章 字典 6.1 一个简单的字典 先跟随书本创建一个简单的字典感受一下. alien_0 = {'color':'green','points':5} print(alien_0['color'] ...
- Grafana邮箱告警
1.grafana-server 配置 smtp 服务器 vim /etc/grafana/grafana.ini #修改一下内容 ################################## ...
- SpringCloud多数据源实现
1.枚举多数据源-定义一一对应变量 /** * * 列出所有的数据源key(常用数据库名称来命名) * 注意: * 1)这里数据源与数据库是一对一的 * 2)DatabaseType中的变量名称就是数 ...
- 下拉式菜单中的内容堆叠(ul型)
今天使用ul创建下拉式菜单,菜单中的内容堆在了一起. 这是我的html代码 <!DOCTYPE html> <html lang="en"> <hea ...
- 03.Java的前世今生
C&C++ 1972年C诞生 ◆贴近硬件,运行极快,效率极高. ◆操作系统,编译器,数据库,网络系统等 ◆指针和内存管理 1982年C++诞生 ◆面向对象 ◆兼容C ◆图形领域.游戏等 背景 ...
- Python函数&异常处理
1. 函数基础 1.1 参数和返回值 1.1.1 参数 位置参数.关键字参数 def my_func1(x, y, z): print(x+y+z, "计算结束") my_func ...
- 短短1天我学会了如何修改Butterfly的配置文件
目录 一.修改默认语言 二.创建标签.分类.关于和留言版页面 三.添加搜索框 四.飘带背景 五.使用Valine添加评论功能并支持邮箱提醒 六.收录谷歌.百度 一.修改默认语言 说明:安装Butter ...
- Swift Core Data 图片存储与读取
1.首先推出选择拍照还是相册的alert,代码如下: UIAlertController *alert = [UIAlertController alertControllerWithTitle:ni ...
- ojdbc6中OraclePreparedStatement的ArrayIndexOutOfBoundsException异常BUG-6396242
现场信息 Caused by: java.lang.ArrayIndexOutOfBoundsException: -32203 at oracle.jdbc.driver.OraclePrepare ...
- bug的描述
我们知道了自身的症状,那么就从这里开始,一起聊一聊一个优秀的 BUG,应该包含哪些方面的内容呢? 标题 其实每一个 BUG 也都是一个小的文档,既然是文档,我们首先就要做好一个 “标题党”,当然,此 ...