登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 94|回复: 0

WindowsPE文件格式入门11.资源表

[复制链接]

78

主题

-6

回帖

71

积分

网站编辑

积分
71
发表于 2025-3-13 22:20:14 | 显示全部楼层 |阅读模式

资源表

img

  • 资源的管理方式采用windows资源管理器目录的管理方式,一般有三层目录。
  • 根目录 结构体IMAGE_RESOURCE_DIRECTORY:描述名称资源和ID资源各自的数量,不描述文件。资源本质都是二进制数据,光标图标是图片有自己的文件格式,字符串什么的需要编译后写进文件,对话框是资源脚本,在rc里。在rc里对话框是一堆字符串,编译器解析字符串后显示出来的,操作系统可以根据文本字符串来创建对话框,但由于需要解析语法效率很低。为了提高效率使用资源编译,将文本字符串生成二进制,用结构体来描述,读资源时将对应数据强转成结构体就完事了。链接时会把res所有二进制数据插入PE文件里。
    • 第一层目录描述了资源类型,一般只有目录,以RT_开头的一组宏分类。
    • 第二层目录指向各类资源ID。如果是图标类型的资源,每种分辨率都会占一个ID。目录项数由资源目录的数量字段控制。
    • 第三层目录再进去之后就是指向资源数据(即代码页)了,一般只会有一项。
  • 在PE里为了更快的找到资源,有一些组织方式。正常情况下所有资源数据都会在.rsrc里。
  • 流程:根目录 - 资源类型 - 资源ID - 资源数据。
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 

// 根目录 - 资源目录 - 名称资源和ID资源各自的数量
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;  // 属性
DWORD TimeDateStamp;    // 时间戳
WORD MajorVersion;      // 主版本号
WORD MinorVersion;      // 子版本号,前12字节无用

WORD NumberOfNamedEntries; // 按照名称命名的资源数量,一般都是0
WORD NumberOfIdEntries; // 按照ID命名的资源数量,编译器默认编译的一般都是序号
// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; // 柔性数组,项数为上两者之和
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;



// 第二层目录 - 表项,大小8字节
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {

//四个字节最高位是1那么资源的id是字符串,低31位是偏移(指向一个结构体)
//,如果是0 资源id是数值 ,低16位就是id值  
union { 
    struct { // 四字节共用体,资源ID(类型)/名称
        DWORD NameOffset:31;    //位段低31位
        DWORD NameIsString:1;   //位段最高位
        } DUMMYSTRUCTNAME;
        DWORD Name;             // 最高位为1,用这个字段解析,低31位指向名称的节内偏移
        WORD Id;                // 最高位为0,用这个字段解析,低两位是ID
    } DUMMYUNIONNAME;

 //四个字节 最高位是1那么是个目录,低31位是偏移(指向一个目录的结构体地址) 
 //       ,如果是0 那么是个数据,低31位是偏移(指向一个数据的结构体地址) 
 union { // 资源数据/资源目录
        DWORD OffsetToData; // 最高位为1,是目录,低31位是新目录的相对于根目录IMAGE_RESOURC
     struct {            // 最高位为0,是数据(类似文件),直接用IMAGE_RESOURCE_DATA_ENTRY解析
        DWORD OffsetToDirectory:31;  //位段低31位
        DWORD DataIsDirectory:1;     //位段最高位
       } DUMMYSTRUCTNAME2;
    } DUMMYUNIONNAME2; 
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;


// 名称解析  -- ASCII
typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING {
  WORD Length;           // 长度
  CHAR NameString[ 1 ];     // ASCII字符串
} IMAGE_RESOURCE_DIRECTORY_STRING, *PIMAGE_RESOURCE_DIRECTORY_STRING;

// 名称解析  -- UNICODE
typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
  WORD Length;          // 长度
  WCHAR NameString[ 1 ]; // UNICODE字符串
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;

// 数据项
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
  DWORD OffsetToData; // 资源数据RVA,这里的OFFSET是相对资源节的偏移
  DWORD Size;         // 资源数据的长度
  DWORD CodePage;     // 代码页,一般是0
  DWORD Reserved;     // 保留字段
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

主要目的不是为了提取资源,而是在条件比较恶劣的情况下,在资源里面看看是不是塞了一些恶意的东西

资源id可以以数值命名,也可以以字符串命名

img

img

img

img

资源类型宏

img

以 类型 6 字符串为例继续解析

img

img

img

img

img

img

img

在看一下菜单资源

菜单类型是4

img

img

img

img

img

img

img

img

img

二进制数据对比,可以看到是一样的

img

往资源里面添加一个PE

因为该类型不属于已有类型,所以添加自定义类型

img

img

img

再用 winhex 打开 exe

img

img

资源类型

img

img

0x85 = 133 可以从资源.h 文件中看出,id是对的

img

800001a0 最高位是1 是个目录 ,偏移是 1a0 9a00+1a0= 9ba0

img

img

img

20c88 + 26000 = 46c88 所以数据从 20c88 到 4c688

把对应区域的数据拷贝出来保存到一个 文件里面

img

对比MD5 值,可以看到文件一模一样

使用自定义资源

    HRSRC hRsrc = FindResource(hInst, MAKEINTRESOURCE(IDR_EXE3), TEXT("EXE"));
    HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
    LPVOID pRes = LockResource(hGlobal);    //返回资源的首地址

提取资源文件

以扫雷为例

image.png

image.png

4200 + 5e0 = 47e0 , 4200 + 60 = 4260

格式是 wav

image.png

image.png

4200+1d0 = 43d0

image.png

image.png

image.png

把数据拷出来复制到新文件, 以wav作为格式

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|断点社区 |网站地图

GMT+8, 2025-4-5 06:41 , Processed in 0.112129 second(s), 23 queries , Yac On.

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

快速回复 返回顶部 返回列表