2.8 PE结构:资源表详细解析

pe,结构,资源,详细,解析 · 浏览次数 : 34

小编点评

**资源简介** 在 Windows PE 中,资源是指可执行文件中的静态数据集合,例如图标、对话框、字符串、位图、版本信息等。 PE 文件中的资源被组织成一个树形结构,称为 **PIMAGE_RESOURCE_DIRECTORY**。 **PIMAGE_RESOURCE_DIRECTORY 结构** PIMAGE_RESOURCE_DIRECTORY 是一个结构,用于描述 PE 文件资源的目录结构。每个资源目录包含以下字段: - **Characteristics:** 指定该目录的属性,如允许命名、是否允许ID等。 - **TimeDateStamp:** 指定该目录的时间戳。 - **MajorVersion / MinorVersion:** 指定PE文件中允许的最高版本和最低版本。 - **NumberOfNamedEntries:** 指定该目录中已经命名的资源条目数量。 - **NumberOfIdEntries:** 指定资源ID类型的数量。 - **PIMAGE_RESOURCE_DIRECTORY_ENTRY:** 指向资源入口表,即 PE 文件每个资源的入口地址。 **解析资源信息** 可以使用 **PIMAGE_DATA_DIRECTORY** 和 **PIMAGE_RESOURCE_DIRECTORY** 结构来解析 PE 文件资源。通过循环遍历 **PIMAGE_RESOURCE_DIRECTORY_ENTRY** 中的每个节点,可以获取资源的名称、类型、语言等信息。 **示例代码** ```c // 定义资源表解析结构 static char* szResName[0x11] = { 0, (char*)\"鼠标指针\", (char*)\"位图\", (char*)\"图标\", (char*)\"菜单\", (char*)\"对话框\", (char*)\"字符串列表\", (char*)\"字体目录\", (char*)\"字体\", (char*)\"快捷键\", (char*)\"非格式化资源\", (char*)\"消息列表\", (char*)\"鼠标指针组\", (char*)\"zz\", (char*)\"图标组\", (char*)\"xx\", (char*)\"版本信息\" }; // 获取到资源目录表 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); // 打印资源信息 for (int i = 0; i < dwResSize; i++) { if (pResEntry[i].Characteristics & CHAR_BIT_NAME) { printf("%s ", pResEntry[i].Name); } else if (pResEntry[i].Characteristics & CHAR_BIT_TYPE) { printf("%s ", szResName[pResEntry[i].Id]); } } ``` **输出结果** ``` 鼠标指针 图标 菜单 对话框 字符串列表 字体目录 字体 快捷键 非格式化资源 消息列表 鼠标指针组 zz 图标组 xx 版本信息 ```

正文

在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;
}

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

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/6532d336.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与2.8 PE结构:资源表详细解析相似的内容:

2.8 PE结构:资源表详细解析

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

Blazor前后端框架Known-V1.2.8

# V1.2.8 Known是基于C#和Blazor开发的前后端分离快速开发框架,开箱即用,跨平台,一处代码,多处运行。 - Gitee: [https://gitee.com/known/Known](https://gitee.com/known/Known) - Github:[https:/

Layui 2.8.0 正式发布,官网全新文档站朴实归来

前言 两年前 Layui 官网宣布了下线声明,说实话当时内心确实感慨万千毕竟这个免费为我们后端程序员提供的一个前端快熟开发框架的官网就这样下线了确实十分的惋惜,但是庆幸的是官网的下线,只是单纯一个网站自身生命周期的结束,它并不意味着 Layui 这样一个开源项目的停更,Layui 仍然在 Githu

[转帖]正则表达式及在Jmeter中的应用

目录 1.正则表达式 1.1 什么是正则表达式 1.2 为什么使用正则表达式 2.语法 2.1 普通字符 2.2 限定符 2.3 非打印字符 2.4 特殊字符 2.5 定位符 2.6 修饰符(标记) 2.7 选择 2.8 运算符优先级 3.常用正则表达式及在线工具 4.Jmeter之正则表达式提取器

Unity开发Hololens2—交互发布配置

> 博客地址:https://www.cnblogs.com/zylyehuo/ ## 环境配置 ```bash unity2021.3.15f visual studio 2019 pro MRTK 2.8.3 OpenXR 1.8.0 Hololens2 ``` > Hololens2 环境配置

[转帖]【Kafka】(二)Kafka去Zookeeper化,kraft模式搭建

1.简介 由于zookeeper慢慢的成了kafka的瓶颈,kafka提出了去zookeeper化的概念,并在2.8版本之后版本都包含了kraft模式,也就是不需要使用zookeeper了,目前这种模式还不成熟,企业中使用kafka还是推荐使用zk+kafka的方式,否则可能会出现意想不到的错误。

RBD与Cephfs

目录1. RBD1. RBD特性2. 创建rbd池并使用2.1 创建rbd2.2 创建用户2.3 下发用户key与ceph.conf2.4 客户端查看pool2.5 创建rbd块2.6 映射rbd并挂载先看一下块设备2.7 开机自动映射2.8 rbd create参数2.9 rbd映射基本操作3.

极简版 haproxy的搭建步骤

## 背景 ``` 发现四层nginx的代理报错. 然后想着换用一下haproxy的配置. 早些时候 看过tidb的一些最佳时间, 这里简单整理一下. ``` ## 下载 ``` https://src.fedoraproject.org/repo/pkgs/haproxy/haproxy-2.8.

Redis 常用的数据结构简介与实例测试【Redis 系列二】

〇、都有哪些数据结构? Redis 提供了较为丰富的数据类型,常见的有五种:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)。 随着 Redis 版本的更新,后面又支持了四种数据类型: BitMap(2.2 版新增)、HyperLogLog(2.8 版

Redis scan等命令的学习与研究

Redis scan等命令的学习与研究 摘要 背景跟前几天说的一个问题类似. 为了验证自己的设想, 所以晚上继续写脚本进行了一轮次的验证. 不过上次讨论时,打击好像都没听懂我说的 所以这次准备从基础开始讲起. 很多好东西在上来量之后可能会变成坏东西 scan 命令 Redis 在2.8 之后增加了s