在Windows PE中,资源是指可执行文件中存放的一些固定不变的数据集合,例如图标、对话框、字符串、位图、版本信息等。PE文件中每个资源都会被分配对应的唯一资源ID,以便在运行时能够方便地查找和调用它们。PE文件中的资源都被组织成一个树形结构,其中最顶层为根节点(Root),下一级为资源类型(Type),再下一级为资源名称(Name),最终是实际的资源内容。

PIMAGE_RESOURCE_DIRECTORY是Windows PE可执行文件中的一个结构类型,用于描述资源(Resource)的树形结构,其中包括了每个资源的类型(Type)、名称(Name)和语言(Language),以及指向下一级PE资源目录的地址和相关信息等。

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY
{
union {
struct {
DWORD NameOffset:31;
DWORD NameIsString:1;
} DUMMYSTRUCTNAME;
DWORD Name;
WORD Id;
} DUMMYUNIONNAME;
union {
DWORD OffsetToData;
struct {
DWORD OffsetToDirectory:31;
DWORD DataIsDirectory:1;
} DUMMYSTRUCTNAME2;
} DUMMYUNIONNAME2;
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

PIMAGE_RESOURCE_DIRECTORY描述了Windows PE资源的目录结构,每个资源目录包括以下字段:

  • Characteristics:指定该目录的属性,如是否允许命名、是否允许ID等;
  • TimeDateStamp:指定该目录的时间戳;
  • MajorVersion / MinorVersion:指定PE文件中允许的最高版本和最低版本;
  • NumberOfNamedEntries:指定该目录中已经命名的资源条目数量;
  • NumberOfIdEntries:指定资源ID类型的数量;
  • PIMAGE_RESOURCE_DIRECTORY_ENTRY:指针,指向资源入口表,即PE文件中每个资源的入口地址。
  • PIMAGE_RESOURCE_DIRECTORY_ENTRY用于引用PE文件中资源的名称、类型和语言信息,它包括了Name/Id:指定资源的名称或ID,根据缩小范围的优先级进行查找,ID的优先级高于名称;
  • OffsetToData:指向该资源的数据偏移地址或其Resource Data Entry的地址。

读者在解析时通常需要在数据目录表PIMAGE_DATA_DIRECTORY中定位到IMAGE_DIRECTORY_ENTRY_RESOURCE资源表,通过循环的方式以此遍历出PIMAGE_RESOURCE_DIRECTORY_ENTRY中的每一个节点,最终输出资源信息,这段输出代码如下所示;

// --------------------------------------------------
// 定义资源表解析结构
// --------------------------------------------------
static char* szResName[0x11] = { 0, (char*)"鼠标指针", (char*)"位图", (char*)"图标", (char*)"菜单", (char*)"对话框", (char*)"字符串列表", (char*)"字体目录", (char*)"字体", (char*)"快捷键", (char*)"非格式化资源", (char*)"消息列表", (char*)"鼠标指针组", (char*)"zz", (char*)"图标组", (char*)"xx", (char*)"版本信息" }; int main(int argc, char * argv[])
{
BOOL PE = IsPeFile(OpenPeFile("c://pe/x86.exe"), 0); if (PE == TRUE)
{
// 获取数据目录表
PIMAGE_DATA_DIRECTORY pData = NtHeader->OptionalHeader.DataDirectory; // 获取到资源目录表
pData = &(pData[IMAGE_DIRECTORY_ENTRY_RESOURCE]); // 获取资源目录表的偏移
DWORD dwResOffset = RVAtoFOA(pData->VirtualAddress); // 获取到资源目录表
PIMAGE_RESOURCE_DIRECTORY pRes = (PIMAGE_RESOURCE_DIRECTORY)(GlobalFileBase + dwResOffset); // 获取紧跟着的IMAGE_RESOURCE_DIRECTORY_ENTRY的个数
DWORD dwResSize = pRes->NumberOfNamedEntries + pRes->NumberOfIdEntries; // 获取到PIMAGE_RESOURCE_DIRECTORY_ENTRY
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes + 1); printf("资源类型ID \t 类型 \n"); for (DWORD i = 0; i < dwResSize; i++)
{ // 如果为0则执行
if (!pResEntry[i].NameIsString)
{
if (pResEntry[i].Id < 0x11)
{
// printf("资源类型ID: %p --> 类型: %s\n", pResEntry[i].Id, szResName[pResEntry[i].Id]);
printf("%p \t %s \n", pResEntry[i].Id, szResName[pResEntry[i].Id]);
}
else
{
char type[20];
sprintf_s(type, "%d", pResEntry[i].Id);
// printf("资源类型ID: %p --> 类型: %s\n", pResEntry[i].Id, type);
printf("%p \t %s \n", pResEntry[i].Id, type);
}
}
// 如果为1则执行
else
{
PIMAGE_RESOURCE_DIR_STRING_U pstcString = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)pRes + pResEntry[i].NameOffset);
WCHAR szStr[MAX_PATH] = { 0 };
memcpy_s(szStr, MAX_PATH, pstcString->NameString, pstcString->Length * sizeof(WCHAR));
// printf("资源字符串: %ls\n", szStr);
}
}
}
else
{
printf("非标准程序 \n");
} system("pause");
return 0;
}

编译并运行上述程序片段,则读者可以看到当前程序中所包含的所有资源信息,为了简单可用此处并没有输出递归资源,仅仅输出了第一层,输出效果图如下所示;

2.8 PE结构:资源表详细解析的更多相关文章

  1. [PE结构]导入表与IAT表

    导入表的结构导入表的结构 typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; // 0 for termi ...

  2. 手写PE结构解析工具

    PE格式是 Windows下最常用的可执行文件格式,理解PE文件格式不仅可以了解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,而有些技术必须建立在了解PE文件格式的基础上,如 ...

  3. WindowsPE 第七章 资源表

    资源表 在程序设计中,总会设计一些数据.这些数据可能是源代码内部需要用到的常量,菜单选项.界面描述等:也可能是源代码外部的,比如程序的图标文件.北京音乐文件.配置文件等,以上这些数据统称为资源.按照程 ...

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

    PE格式第九讲,资源表解析 一丶熟悉Windows管理文件的方法 首先,为什么标题是这个,主要是为了下边讲解资源方便,因为资源结构体很乱.如果直接拿出来讲解,那么就会很晕. 1.windows管理文件 ...

  5. [PE结构分析] 11.资源表结构

    资源表是一个树形结构,可以设置成2的31次方的层数,Windows 使用了3级: 类型->名称->语言 其中涉及到四个结构: Data Description Resource Direc ...

  6. PE解析器的编写(四)——数据目录表的解析

    在PE结构中最重要的就是区块表和数据目录表,上节已经说明了如何解析区块表,下面就是数据目录表,在数据目录表中一般只关心导入表,导出表和资源这几个部分,但是资源实在是太复杂了,而且在一般的病毒木马中也不 ...

  7. Activiti数据库表结构(表详细版)

    http://blog.csdn.net/hj7jay/article/details/51302829 1  Activiti数据库表结构 1.1      数据库表名说明 Activiti工作流总 ...

  8. PE节表详细分析

    目录 PE节表详细分析 0x00 前言 0x01 PE节表分析 节表结构 节表数量 节表名字 节表大小 节位置 节表属性 0x02 代码编写 PE节表详细分析 0x00 前言 上一篇文章我们学习了PE ...

  9. 单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式

    单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式     一 表结构如下:  万行 CREATE TABLE t_audit_operate_log (  Fid b ...

  10. Win32汇编-编写PE结构解析工具

    汇编语言(assembly language)是一种用于电子计算机.微处理器.微控制器或其他可编程器件的低级语言,亦称为符号语言.在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地 ...

随机推荐

  1. 白话文解析LiteFlow的理念是什么?什么时候用该怎么用?干货满满

    官网:https://liteflow.cc/ Gitee:https://gitee.com/dromara/liteFlow Github:https://github.com/dromara/l ...

  2. WPF Window无边框窗体阴影效果

    WPF通过WindowChrome实现Window无边框窗体阴影效果 代码: <Window x:Class="SunCreate.PACP.Client.UI.GIS.CameraD ...

  3. JavaScript 基础 - Day01

    了解变量.数据类型.运算符等基础概念,能够实现数据类型的转换,结合四则运算体会如何编程. 体会现实世界中的事物与计算机的关系 理解什么是数据并知道数据的分类 理解变量存储数据的"容器&quo ...

  4. CH6803 导弹防御塔 (二分 + 匈牙利 / 网络流)

    链接:https://ac.nowcoder.com/acm/contest/1062/D 题目描述 Freda的城堡-- "Freda,城堡外发现了一些入侵者!" "喵 ...

  5. HDU-3032--Nim or not Nim?(博弈+SG打表)

    题目分析: 这是一个经典的Multi-SG游戏的问题. 相较于普通的Nim游戏,该游戏仅仅是多了拆成两堆这样的一个状态.即多了一个SG(x+y)的过程. 而根据SG定理,SG(x+y)这个游戏的结果可 ...

  6. ACM | 动态规划-数塔问题变种题型

    前言 数塔问题,又称数字三角形.数字金字塔问题.数塔问题是多维动态规划问题中一类常见且重要的题型,其变种众多,难度遍布从低到高,掌握该类型题目的算法思维,对于攻克许多多维动态规划的问题有很大帮助. 当 ...

  7. poj 2533 LIS(最长上升序列)

    ***一道裸题, 思路:在g数组内往里加元素,一直扩大这个数组,每次查询的时候,用二分查找,时间复杂度O(nlog(n)) *** #include<iostream> #include& ...

  8. Ubuntu22.04上使用systemctl命令配置开机自启动服务、脚本、命令

    systemctl介绍 systemctl是Linux系统上用于管理系统服务(systemd单元)的命令行工具.它可以用来启动.停止.重启.禁用.启用.查询和管理系统服务的状态. 以下是一些常用的sy ...

  9. 关闭 cockpit 登陆提示

    sudo rm /etc/issue.d/cockpit.issue sudo rm /etc/motd.d/cockpit

  10. bitcask论文翻译/笔记

    翻译 论文来源:bitcask-intro.pdf (riak.com) 背景介绍 Bitcask的起源与Riak分布式数据库的历史紧密相连.在Riak的K/V集群中,每个节点都使用了可插拔的本地存储 ...