论坛首页 漏洞分析研究区 阅读主题

[翻译]利用 Microsoft Warbird 执行 Shellcode

290 浏览 0 回复
#1 楼主 2026-06-01 21:08:53
(本文翻译自德国安全实验室 Cirosec 的研究博文,文章详细分析了利用 Windows 内部代码保护框架 Microsoft Warbird 实现隐蔽加载 Shellcode 的高级对抗技术,原文链接在文章末尾)
在这篇博文中,我们将介绍 Microsoft Warbird 及其利用方式,即如何通过滥用它来隐蔽地加载 Shellcode,从而避开反病毒软件(AV)或终端检测与响应(EDR)解决方案的检测。我们将展示如何对 Shellcode 进行加密,并利用 Warbird API 让 Windows 内核为我们执行解密和加载。通过这种技术,你可以让 Shellcode 绕过那些拦截系统调用(syscall)的 EDR 解决方案:它允许你在一次系统调用中完成“分配可执行内存”、“解密 Shellcode” 以及 “跳转到已解密的 Shellcode 执行” 这三个步骤。在整个进程执行过程中,解密后的 Shellcode 永远不会出现在任何可写内存区域。你可以在Github上查看相关的概念验证(PoC)代码。
1. 基础(Basics)
1.1 介绍(Introduction)
Microsoft Warbird 是微软内部一套未公开的代码保护与混淆框架。它被用于数字版权管理(DRM),旨在保护敏感代码免受逆向工程和篡改。Warbird 支持多种混淆技术,例如基于虚拟机的混淆、常量混淆、分段加密(Section Encryption)或运行时代码保护。根据 “This is Security” 网站的报道,Microsoft Warbird 是在 Windows 8/2012 版本中引入的。其中的一个应用实例就是微软软件保护平台服务(sppsvc.exe),该服务主要负责处理 Windows 的激活算法。
Warbird 框架原本仅供微软内部服务专供。其提供的功能并非面向第三方开发者,且微软也在积极采取措施防止第三方调用。在向大家展示如何滥用这一框架之前,我们先来了解一下微软官方服务通常是如何使用 Warbird 的。
1.2 运行时代码保护(Runtime Code Protection)
在 Warbird 的诸多功能中,我们最感兴趣的、能够用于加载 Shellcode 的特性是代码的运行时解密。
Warbird 的运行时解密功能允许执行经过加密的代码。这些代码是使用专为 Warbird 开发的一种自定义 Feistel 密码(Feistel cipher)进行加密的。Feistel 密码的具体运作原理目前对我们来说并不重要,你只需要知道它是一种对数据块进行操作的对称加密算法。
在 Warbird 最初引入时,基本块(basic blocks)的解密和执行仅在用户模式下由进程自身完成。这意味着,当运行中的进程想要执行加密代码时,它会调用 Feistel 密码进行解密,分配一段新的可执行内存,将解密后的代码存入该内存,然后跳转到解密代码的起始位置执行。
为了缓解一些其他的攻击向量(例如 ROP 链等),微软在后来的某个阶段引入了任意代码防护机制(ACG,Arbitrary Code Guard),决定禁止某些用户模式进程分配新的可执行内存。这一举措防止了内存损坏漏洞利用 Windows API 来分配新的可执行内存并植入其 Shellcode。然而,ACG 同时也导致 Warbird 无法在这些进程中正常工作。
因此,加密代码的解密和内存分配工作被移到了内核层。这意味着,Windows 内核现在负责在进程的堆(Heap)中分配内存,并将其标记为可执行。这样一来,即便执行进程本身被禁止分配可执行内存(例如旧版 Microsoft Edge 中受特殊保护的浏览器进程),Warbird 依然可以使用。再强调一下:微软认为,提供一个内核级 API 来负责代码的解密和内存分配,比允许进程自行解密其加密代码要更“安全”——仅凭这一点,就足以令人感到惊讶(或引起安全研究员的警觉)了。
运行时解密例程的流程如下:
● 进程想要执行加密代码。
● 进程在其自身内存中定位相应的加密代码,并将其传递给内核。
● 内核对代码进行解密,在进程的堆(Heap)中分配一个新的可执行内存区域,将解密后的代码复制到该新内存区域,并将其标记为可执行。
● 内核将执行控制权交还给进程,使其从解密代码的起始位置开始执行。

1.3 Feistel 密码(Feistel Cipher)
Warbird 所使用的自定义 Feistel 密码是一个专有实现,微软对此没有任何公开文档。
值得庆幸的是,DownWithUp 的一篇博文已经记录了如何通过巧妙组合系统调用来利用 Warbird API,从而让内核替你完成任意数据的加密。通过这种方式,我们可以将内核视为 Feistel 密码的“黑盒”实现,而无需了解该算法本身的细节。
我们曾尝试使用他们的技术来为 Warbird 解密例程加密数据,但发现这种方式加密后的数据无法在运行时解密过程中正常工作。对我们来说幸运的是,2017 年泄露的 Warbird 框架源代码中包含了一个可运行的 Feistel 密码实现;我们可以利用它来加密 Shellcode,使其适配运行时解密例程。这段源代码已经在互联网上流传了一段时间,最近在 Github 上也可以获取到。
1.4 Warbird 系统调用(Warbird Syscall)
为了向内核请求解密和内存分配,进程必须调用 NtQuerySystemInformation 系统调用,并将 SystemInformationClass 参数设置为 SystemCodeFlowTransition (0xB9)。尽管微软官方并未公开此功能的文档,但得益于 Windows 源代码的泄露,我们可以获取大量关于该系统调用的信息。该系统调用接收一个指向结构体的指针,该结构体中包含用于指定待执行操作类型的 WbOperationType;同时还接收另一个指向结构体的指针,其中包含该操作所需的附加数据。根据泄露的源代码,WbOperationType 枚举包含以下取值:

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-289950.htm

暂无回复,快来抢沙发吧!

请登录后参与讨论

立即登录 注册账号