大理寺少卿 发表于 2025-3-13 22:20:14

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

## 资源表

!(./mdimg/pe/1637035220379-aa5791bc-c507-4001-82ef-5d815011e4fc.jpeg)

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

```c++
#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可以以数值命名,也可以以字符串命名

!(./mdimg/pe/1656596095665-4eea22c8-2be0-4167-9810-11e33194035a.png)

!(./mdimg/pe/1656596170142-1f70c8c6-bec4-4490-8248-6406bd598aac.png)

!(./mdimg/pe/1656596598368-7d55052a-3045-4606-a308-a7652de38dd5-170519775205939.png)

!(./mdimg/pe/1656596811632-17994084-5bff-40a7-aa90-f0e3651ba3ef.png)

资源类型宏

!(./mdimg/pe/1656596863001-c2b89d20-300c-434b-9ebf-a5a77a4da234.png)

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

!(./mdimg/pe/1656598325529-99715370-6ee6-4c39-bc9d-6db2a27705a1.png)

!(./mdimg/pe/1656598645543-64eabd57-3d98-4599-a0c9-0c7f811cc21f.png)

!(./mdimg/pe/1656598755622-b5d41e2e-4a45-4b8f-84f1-4ec1af13dfa6.png)

!(./mdimg/pe/1656598866401-80af1fa0-7b77-47a6-8388-10cfd7f6060d.png)

!(./mdimg/pe/1656598944983-cd217bbc-9371-4d52-ab37-899de1eb8a45.png)

!(./mdimg/pe/1656599004551-2c466924-4c1a-4a22-8b2a-788b4ba78236.png)

!(./mdimg/pe/1656599218429-05cadbfd-5e2d-4216-b55f-ebe2958e9494.png)

在看一下菜单资源

菜单类型是4

!(./mdimg/pe/1656596598368-7d55052a-3045-4606-a308-a7652de38dd5.png)

!(./mdimg/pe/1656599553532-a6b0ef19-cdb9-462a-be09-da8c9c1c67f7.png)

!(./mdimg/pe/1656599697698-cb9a1e18-679b-4cd4-b729-2c2d25210bd4.png)

!(./mdimg/pe/1656599905041-0b11273a-115b-4660-8dc8-e50a5a83fc1a.png)

!(./mdimg/pe/1656600011248-6ce5d5a5-1d7d-4886-9f81-3f558a65cdac.png)

!(./mdimg/pe/1656600065646-e66d3f5f-d0be-4eb8-bef4-d52112995be9.png)

!(./mdimg/pe/1656600137259-7214b8f0-9c88-4ab8-9918-fd1daf69bacd.png)

!(./mdimg/pe/1656600149164-b7f19a8e-c2d4-42fc-bfe9-449904ea4d06.png)

!(./mdimg/pe/1656603009218-b51c72ad-3f0d-4210-864a-9199a61133fd.png)

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

!(./mdimg/pe/1656602973843-1b61d5da-5f91-43e0-a3ac-158d189fba29.png)

往资源里面添加一个PE

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

!(./mdimg/pe/1656603313338-0399abd1-4389-462e-a1fb-361b0b44dff3.png)

!(./mdimg/pe/1656603461464-f0bc292d-dab8-4a7b-9c8a-ee9c686b8456.png)

!(./mdimg/pe/1656604115625-2f9a7943-99ac-48f6-b123-584e22e31f07.png)

再用 winhex 打开 exe

!(./mdimg/pe/1656603653063-24948849-9e71-494b-a0bc-02bcd81c37f8.png)

!(./mdimg/pe/1656603750239-dc0d6732-daef-4535-b9cc-d64b5a4475ee.png)

资源类型

!(./mdimg/pe/1656603870098-936f88f2-6726-451b-915c-1d801d99bd81.png)

!(./mdimg/pe/1656603975793-2e54a16b-2386-4e83-b082-3e4155e9aba2.png)

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

!(./mdimg/pe/1656604028327-26d8559f-10ba-4e1c-8852-b02f6a477e22.png)

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

!(./mdimg/pe/1656604198479-8b41b975-d0d0-41a2-8ce7-1173a6d402ff.png)

!(./mdimg/pe/1656604306113-dc0e2654-ec13-48d8-8fc5-ef46a7ef4b63.png)

!(./mdimg/pe/1656604345754-43e4f276-57e1-473a-a521-966359645836.png)

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

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

!(./mdimg/pe/1656604673900-ab1d2428-7aa5-454d-88d6-82682bc8bf3a.png)

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

#### 使用自定义资源

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

提取资源文件

以扫雷为例

!(./mdimg/pe/1656605797467-4ad609ea-7f9a-4053-91f4-9a7089c81ede.png)

!(./mdimg/pe/1656605937500-b826ceb4-2d98-4f59-b6e3-b3adc987ead9.png)

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

```
格式是 wav
```


!(./mdimg/pe/1656606000153-adcb74ce-9880-4d55-9340-d7ec845cdb45.png)

!(./mdimg/pe/1656606086219-0f574262-a51b-4c53-b229-aaa9a0e1cac2.png)

4200+1d0 = 43d0

!(./mdimg/pe/1656606150023-759c4374-50ad-4b2e-8548-39267d4bb503.png)

!(./mdimg/pe/1656606222836-be1e374a-c5f0-4b4f-8b26-208c820b5437.png)

!(./mdimg/pe/1656606272244-f3d7c6a8-0055-447c-b4da-bebc9e432425.png)

把数据拷出来复制到新文件,以wav作为格式
页: [1]
查看完整版本: WindowsPE文件格式入门11.资源表