模块 15 - Payload 存放 - .rsrc 段
恶意软件开发课程 - Payload 存放 - .rsrc 段
模块 15 - Payload 存放 - .rsrc 段#
[!IMPORTANT] 本知识库声明
本知识库由本人整理自互联网 MalDev Academy 泄露资源,并由本人手动翻译为中文,过程中增加了大量关键技术提示与实践心得。
- 内容完整性:并未修改任何核心代码与技术逻辑,仅做汉化与注释加强。
- 版权归属:原始知识产权归原作者/官方所有。
- 支持正版:本仓库仅供内部学习交流,如果您有经济能力,请务必支持正版课程。
- 权利申诉:如相关内容侵犯了您的权益,请联系我,我将立即核实并删除。
Payload 存放 - .rsrc 段#
简介#
将 payload 保存在 .rsrc 段对于恶意软件作者来说是一种更干净的方法,因为较大的 payload 无法存储在 .data 或 .rdata 段中,受限于大小限制,在编译时会导致 Visual Studio 报错。
.rsrc 段#
以下步骤展示了如何将 payload 存储在 .rsrc 段中。
步骤 1: 添加资源文件#
在 Visual Studio 中,右键点击 “Resource files” (资源文件),然后选择 Add > New Item (添加 > 新建项)。

步骤 2: 选择资源文件类型#
点击 “Resource File”(资源文件)。

步骤 3: 添加资源#
这将生成一个新的侧边栏 “Resource View”(资源视图)。右键点击 .rc 文件(默认名称为 Resource.rc),然后选择 “Add Resource”(添加资源) 选项。

步骤 4: 导入资源#
点击 “Import”(导入)。

步骤 5: 选择 Payload 文件#
选择 calc.ico 文件,这是重命名为 .ico 扩展名的原始 payload。

步骤 6: 指定资源类型#
会出现一个提示,要求输入资源类型。输入 “RCDATA”(不带引号)。

[!IMPORTANT] 📚 知识扩展 - RCDATA 资源类型
Windows 定义了多种标准资源类型:
资源类型 说明 常见用途 RT_ICON图标资源 程序图标 RT_BITMAP位图资源 图像数据 RT_STRING字符串表 本地化字符串 RT_DIALOG对话框 UI 定义 RT_RCDATA原始数据 自定义二进制数据 RCDATA (Raw Data) 是一种通用的资源类型,用于存储任意二进制数据。这正是我们需要的!
为什么不使用其他类型?
RT_ICON/RT_BITMAP等类型有特定的数据格式要求RT_RCDATA没有格式限制,可以存储任何字节序列
步骤 7: 查看导入的 Payload#
点击 OK 后,payload 应以原始二进制格式显示在 Visual Studio 项目中。

步骤 8: 查看资源头文件#
退出 Resource View 后,应该可以看到 resource.h 头文件,其命名与步骤 2 中的 .rc 文件相对应。该文件包含一个 define 语句,引用了资源段中 payload 的 ID(IDR_RCDATA1)。这对于稍后从资源段检索 payload 非常重要。

访问 .rsrc 段中的 Payload#
编译后,payload 现在存储在 .rsrc 段中,但无法直接访问它。相反,必须使用几个 Windows API 来访问它:
| API 函数 | 功能说明 |
|---|---|
| FindResourceW ↗ | 获取资源段中指定 ID 的数据位置 |
| LoadResource ↗ | 检索资源数据的 HGLOBAL 句柄,可用于获取资源在内存中的基地址 |
| LockResource ↗ | 从句柄获取指向资源段中指定数据的指针 |
| SizeofResource ↗ | 获取资源段中指定数据的大小 |
[!IMPORTANT] 📚 知识扩展 - 资源访问流程
访问资源段的标准流程:
plaintext1. FindResourceW → 根据 ID 查找资源,返回 HRSRC 句柄 ↓ 2. LoadResource → 加载资源,返回 HGLOBAL 句柄 ↓ 3. LockResource → 锁定资源,返回内存指针 ↓ 4. SizeofResource → 获取资源大小为什么需要这么多步骤?
- Windows 资源系统设计时考虑了内存管理和性能优化
- 不是所有资源都会立即加载到内存,而是按需加载
- 这些 API 提供了灵活的资源管理机制
以下代码片段将使用上述 Windows API 访问 .rsrc 段并获取 payload 地址和大小。
#include <Windows.h>
#include <stdio.h>
#include "resource.h" // 包含 IDR_RCDATA1 的定义
int main() {
HRSRC hRsrc = NULL; // 资源句柄
HGLOBAL hGlobal = NULL; // 全局内存句柄
PVOID pPayloadAddress = NULL; // Payload 内存地址
SIZE_T sPayloadSize = NULL; // Payload 大小
// 通过 ID (IDR_RCDATA1) 获取存储在 .rsrc 中的数据位置
hRsrc = FindResourceW(NULL, MAKEINTRESOURCEW(IDR_RCDATA1), RT_RCDATA);
if (hRsrc == NULL) {
// 函数失败时的处理
printf("[!] FindResourceW Failed With Error : %d \n", GetLastError());
return -1;
}
// 获取 HGLOBAL,即指定资源数据的句柄,因为稍后调用 LockResource 时需要它
hGlobal = LoadResource(NULL, hRsrc);
if (hGlobal == NULL) {
// 函数失败时的处理
printf("[!] LoadResource Failed With Error : %d \n", GetLastError());
return -1;
}
// 获取我们 payload 在 .rsrc 段中的地址
pPayloadAddress = LockResource(hGlobal);
if (pPayloadAddress == NULL) {
// 函数失败时的处理
printf("[!] LockResource Failed With Error : %d \n", GetLastError());
return -1;
}
// 获取我们 payload 在 .rsrc 段中的大小
sPayloadSize = SizeofResource(NULL, hRsrc);
if (sPayloadSize == NULL) {
// 函数失败时的处理
printf("[!] SizeofResource Failed With Error : %d \n", GetLastError());
return -1;
}
// 将指针和大小打印到屏幕上
printf("[i] pPayloadAddress var : 0x%p \n", pPayloadAddress);
printf("[i] sPayloadSize var : %ld \n", sPayloadSize);
printf("[#] Press <Enter> To Quit ...");
getchar();
return 0;
}c编译并运行上述代码后,payload 地址及其大小将打印到屏幕上。需要注意的是,此地址位于 .rsrc 段中,这是只读内存,任何尝试更改或编辑其中数据的操作都会导致访问违例错误 (Access Violation)。
要编辑 payload,必须分配一个与 payload 大小相同的缓冲区,并将其复制过去。可以在这个新缓冲区中进行更改,例如解密 payload。
[!WARNING] ⚠️ 重要警告 - 只读内存限制
.rsrc段具有PAGE_READONLY权限,这意味着:
- ✅ 可以读取数据
- ❌ 不能写入或修改数据
- ❌ 不能直接执行其中的 shellcode
如果尝试修改
.rsrc中的数据,Windows 会触发访问违规异常 (Exception Code:0xC0000005)解决方案:
将 payload 复制到可写的内存缓冲区(如下一节所示)。
更新 .rsrc Payload#
由于无法直接从资源段中编辑 payload,因此必须将其移动到临时缓冲区。为此,使用 HeapAlloc ↗ 分配与 payload 大小相同的内存,然后使用 memcpy 将 payload 从资源段移动到临时缓冲区。
// 使用 HeapAlloc 调用分配内存
PVOID pTmpBuffer = HeapAlloc(GetProcessHeap(), 0, sPayloadSize);
if (pTmpBuffer != NULL){
// 将 payload 从资源段复制到新缓冲区
memcpy(pTmpBuffer, pPayloadAddress, sPayloadSize);
}
// 打印缓冲区的基地址 (pTmpBuffer)
printf("[i] pTmpBuffer var : 0x%p \n", pTmpBuffer);
c由于 pTmpBuffer 现在指向一个持有 payload 的可写内存区域,因此可以解密 payload 或对其执行任何更新。
调试示例#
下图显示了存储在资源段中的 Msfvenom shellcode。

继续执行后,payload 被保存在临时缓冲区中。

总结#
.rsrc段适合存储大型 payload,不受.data/.rdata大小限制- 使用 Visual Studio 的资源导入功能,将 payload 作为
RCDATA类型添加 - 通过
FindResourceW→LoadResource→LockResource→SizeofResource访问资源 - 资源段是只读的,需要复制到可写缓冲区才能修改或解密
HeapAlloc是创建临时缓冲区的理想选择
下一步:
在后续模块中,我们将学习如何加密存储在 .rsrc 段中的 payload,并在运行时解密!