0%
毅种循环

模块 15 - Payload 存放 - .rsrc 段

恶意软件开发课程 - Payload 存放 - .rsrc 段


模块 15 - Payload 存放 - .rsrc 段#

[!IMPORTANT] 本知识库声明

本知识库由本人整理自互联网 MalDev Academy 泄露资源,并由本人手动翻译为中文,过程中增加了大量关键技术提示实践心得

  1. 内容完整性:并未修改任何核心代码与技术逻辑,仅做汉化与注释加强。
  2. 版权归属:原始知识产权归原作者/官方所有。
  3. 支持正版:本仓库仅供内部学习交流,如果您有经济能力,请务必支持正版课程
  4. 权利申诉:如相关内容侵犯了您的权益,请联系我,我将立即核实并删除。

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] 📚 知识扩展 - 资源访问流程

访问资源段的标准流程:

1. FindResourceW   → 根据 ID 查找资源,返回 HRSRC 句柄

2. LoadResource    → 加载资源,返回 HGLOBAL 句柄

3. LockResource    → 锁定资源,返回内存指针

4. SizeofResource  → 获取资源大小
plaintext

为什么需要这么多步骤?

  • Windows 资源系统设计时考虑了内存管理和性能优化
  • 不是所有资源都会立即加载到内存,而是按需加载
  • 这些 API 提供了灵活的资源管理机制

以下代码片段将使用上述 Windows API 访问 .rsrc 段并获取 payload 地址和大小。

编译并运行上述代码后,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 类型添加
  • 通过 FindResourceWLoadResourceLockResourceSizeofResource 访问资源
  • 资源段是只读的,需要复制到可写缓冲区才能修改或解密
  • HeapAlloc 是创建临时缓冲区的理想选择

下一步:
在后续模块中,我们将学习如何加密存储在 .rsrc 段中的 payload,并在运行时解密!