VirtualAlloc免杀技术原理解读
TOPIC SOURCE
一个简单寻找无文件落地后门与内存免杀shellcode的工具
在最近一次红队演练中,笔者意外捕获到一段运行在VirtualAlloc分配区域的 shellcode,恰恰说明了这种“内存免杀”手法仍在活跃。若不清楚其底层机制,防御方往往只能盲目拦截,导致误报频发。
VirtualAlloc 在内存分配中的角色
Windows 内核提供的 VirtualAlloc 能在进程地址空间中预留、提交或保护一块连续内存。与 HeapAlloc 不同,它不依赖任何特定堆结构,因而常被用作“裸露”代码的落脚点。攻击者只需一次 API 调用即可得到 RWX(可读写可执行)的页面,随后把解密后的 payload 写入并跳转执行。
免杀实现的核心路径
典型流程大致如下:
1)调用 VirtualAlloc 申请 RWX 页面;
2)将加密的 shellcode 通过 WriteProcessMemory 或直接 memcpy 写入;
3)利用 CreateThread、NtCreateThreadEx 或 APC 触发执行。加密手段从单纯 XOR 到多轮 AES 再到自定义混淆层层叠加,目的在于让静态扫描工具只能看到一段随机数据。
检测思路的技术细分
- 基于
StackWalkEx的线程栈回溯:遍历每条线程的调用帧,定位 PC 落在VirtualAlloc返回的内存区域。 - 页面属性监控:实时拦截
VirtualProtect将 PAGE_READWRITE 改为 PAGE_EXECUTE 的行为。 - 加密解密行为关联:检测短时间内连续出现的
VirtualAlloc → memcpy → CreateThread调用链。 - 异常 PE 结构:无文件映射的代码通常缺失 MZ/PE 标记,或出现 “NOIMAGE” 区段,可作为二次过滤。
误报与防御的平衡点
不少合法软件(尤其是自带脚本引擎的游戏或数据分析工具)同样会使用 VirtualAlloc 动态生成代码。完全阻断会导致业务中断,因而实际部署时往往结合行为阈值:若同一进程在短时间内多次申请 RWX 页面并立即启动线程,才触发告警。这样既降低了误报,又保留了对真正免杀木马的捕获能力。

参与讨论
这套路确实常见,防御要跟上。
看到作者把加密层拆得这么清楚,感觉像在看现场拆弹,真是让人心跳加速😅,期待更多细节。
VirtualAlloc 能直接拿到 RWX 页面,确实是免杀的好选手。
其实可以通过监控 NtAllocateVirtualMemory 的调用频率来进一步降低误报。
这种加密方式在 macOS 上有对应的实现吗?