news 2026/8/22 15:09:31

Voidgate三大核心机制拆解:VirtualAlloc、硬件断点与VEH如何协同工作

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Voidgate三大核心机制拆解:VirtualAlloc、硬件断点与VEH如何协同工作

Voidgate三大核心机制拆解:VirtualAlloc、硬件断点与VEH如何协同工作

【免费下载链接】VoidgateA technique that can be used to bypass AV/EDR memory scanners. This can be used to hide well-known and detected shellcodes (such as msfvenom) by performing on-the-fly decryption of individual encrypted assembly instructions, thus rendering memory scanners useless for that specific memory page.项目地址: https://gitcode.com/gh_mirrors/vo/Voidgate

Voidgate 是一个围绕内存扫描绕过(bypass AV/EDR memory scanners)展开的教学型 C++ 项目,它演示如何让 shellcode 在内存中始终保持 XOR 加密,仅在 CPU 执行到某条指令的瞬间,用 VEH 单步解密这一条指令,执行完立即重新加密,使内存扫描器在任何时刻都抓不到完整的 shellcode 特征。本文带你拆解 VirtualAlloc、硬件断点与 VEH 三大核心机制是如何协同工作的。

🔍 先搞懂:Voidgate 要解决什么问题

传统内存扫描(如 AV/EDR 的内存扫描器)会遍历进程内存,匹配已知 shellcode 特征码(例如 msfvenom 生成的载荷)。常见的对抗思路是"先加密驻留、执行前解密",但一旦解密完成,完整明文就暴露在内存中,扫描器迟早能抓到。

Voidgate 的答案是:任何时刻,内存里最多只有一条解密后的汇编指令

对比项常规 shellcode 执行Voidgate 方式
内存中的 shellcode解密后完整驻留始终加密,仅当前指令为明文
内存扫描器视角可匹配完整特征码只能看到密文 + 单条指令
执行速度正常每条指令触发一次异常处理,明显变慢
适用场景通用小型初始载荷(如 msfvenom 反弹 shell)

一句话概括三大角色:

  • ⚙️VirtualAlloc:准备一块"可执行 + 可读写"的内存舞台;
  • 🚦硬件断点(HWBP):在 shellcode 入口处精准"踩刹车",把执行流交给异常机制;
  • 🕵️VEH:扮演"贴身调试器",每条指令执行前后完成解密/加密,并用单步模式持续接力。

🧩 机制一:VirtualAlloc 开辟可执行内存区

入口代码在voidgate-master/Voidgate/main.cpp。程序启动后第一件事是调用VirtualAlloc,以PAGE_EXECUTE_READWRITE权限申请一段堆内存(第 17 行),大小 = 加密载荷长度 + 前后各 32 字节(0x20)填充,填充常量定义在voidgate-master/Voidgate/Voidgate.h第 6 行的SHELLCODE_PADDING

关键细节有三个:

  1. 整块内存先填充 NOP(0x90),再把加密后的 shellcode 拷到中间(第 29-31 行)——这段"内存海绵"让载荷边界不那么生硬,也预留了容错空间;
  2. 程序记录三个全局地址:payload_base(入口点)、payload_lower_boundpayload_upper_bound(第 25-33 行);
  3. 这三个地址是后面 VEH 判断"当前指令是不是我们的 shellcode"的唯一依据。

为什么必须"可执行 + 可读写"?因为 VEH 要在这块内存上边执行、边原地改写(解密/加密),普通的只读代码段做不到。

🚦 机制二:硬件断点——在入口处精准踩刹车

SetHardwareBreakpoint函数(voidgate-master/Voidgate/Voidgate.cpp第 72-92 行)是第二个角色。它通过GetThreadContext/SetThreadContext操作当前线程的调试寄存器:

  • Dr0写入 shellcode 入口地址(第 81 行)——"在哪个地址踩刹车";
  • Dr7设置启用位(第 82 行)——"让刹车生效"。

硬件断点相比软件断点(如int 3)有一个关键优势:内存里不会多出任何可见字节。扫描器翻遍内存也找不到断点痕迹,只会看到纯密文。

main把执行流跳转到 payload 入口(第 36-44 行)时,CPU 一碰到 Dr0 指定的地址就触发调试异常——相当于给 VEH 递上了第一根"接力棒"。

🕵️ 机制三:VEH 单步解密——永远只解密一条指令

main.cpp第 39 行通过AddVectoredExceptionHandler注册 VEH,处理函数VehDecryptHeapAsm位于voidgate-master/Voidgate/Voidgate.cpp(第 10-70 行)。它的工作循环可以概括为五步:

  1. 只认领单步异常:异常码不是EXCEPTION_SINGLE_STEP就放行给其他处理器(第 65-68 行);
  2. 范围校验:读取 RIP,若不在 payload 上下界内(比如跳进了 kernel32 的函数),直接恢复执行、不做任何加解密(第 24-27 行);
  3. 加密上一条:把全局变量last_decrypted_asm记录的那条已执行指令重新 XOR 加密(第 32-46 行);
  4. 解密当前条:以 RIP 为起点 XOR 解密当前指令(最多 15 字节,即 x64 单条指令最大长度,常量见Voidgate.h第 7 行)(第 48-59 行);
  5. 设置单步标志:在 EFlags 中置位 TRAP 标志(第 21 行),保证下一条指令再次触发异常,循环继续。

XOR 密钥的偏移并不是固定的:GetXorKeyIndexForAsm(第 94-100 行)用「当前指令地址 − 载荷基址」对密钥长度取模,保证同一条指令每次加解密都用同一组密钥字节。密钥同时硬编码在main.cpp(第 9 行)和加密工具voidgate-master/XorEncryptPayload/XorEncryptPayload.cpp(第 59 行)中,两端必须完全一致,否则解出来的就是乱码。

🔄 三者协同:一条指令的完整生命周期

把三个机制串起来,执行流是这样接力的:

  1. VirtualAlloc铺好可执行内存,密文 shellcode 就位(main.cpp 第 17-33 行);
  2. 硬件断点守在入口,主线程跳转后立刻被调试异常拦下;
  3. VEH 接管:解密第 1 条指令,置位 TRAP,放行执行,同时记下这条指令的地址;
  4. CPU 执行完这 1 条指令 → TRAP 触发EXCEPTION_SINGLE_STEP
  5. VEH 回来:把第 1 条重新加密,解密第 2 条,再次置位 TRAP;
  6. 如此逐条接力……内存扫描器任意时刻采样,都只能看到密文 + 1 条明文指令
  7. shellcode 执行完毕(回连成功),VirtualFree释放内存(main.cpp 第 48 行)。

🚀 六步复现 PoC:从 msfvenom 到回连成功

想亲手验证这套内存扫描绕过机制,按下面顺序操作即可(仓库获取:git clone https://gitcode.com/gh_mirrors/vo/Voidgate):

  1. 用 msfvenom 生成目标载荷(README 给出的示例为 x64 反弹 TCP shell);
  2. 运行XorEncryptPayload.exe <shellcode文件路径>完成 XOR 加密,工具会直接输出 C 数组;
  3. 把输出的数组替换voidgate-master/Voidgate/main.cpp中的payload[]
  4. 确认加密工具与main.cpp中的 XOR 密钥完全一致;
  5. 在监听机上启动nc -nvlp 443
  6. 执行Voidgate.exe,稍等片刻即可看到回连。

⏱️ 注意:由于每条指令都要走一遍异常处理(官方说明每次至少额外执行 300 条指令),执行速度会显著变慢——msfvenom 这类"求小而慢"的载荷甚至可能耗时 15 秒以上,这是机制的固有代价而非 bug。

⚠️ 已知限制:哪些场景不适合 Voidgate

README 明确列出了三条限制,研究或复现前务必了解:

限制原因影响
执行极慢每条指令都触发 VEH 加解密大型、循环密集型载荷基本不可用
载荷内NtCreateThread新建线程新线程没有安装硬件断点入口在新线程里的载荷会失败
载荷内部引用自身数据(内嵌字符串、常量等)VEH 只解密 RIP 处的代码,不解密数据区取到的是密文,行为异常

因此 Voidgate 最适合作为初始接入的小载荷,或 stage-1 引导载荷(先落地再拉取剩余 payload)。

✅ 总结:一张表看懂三大核心机制

机制核心 API职责源码位置
可执行内存区VirtualAlloc分配 RWX 内存,铺 NOP 与密文voidgate-master/Voidgate/main.cpp
硬件断点SetThreadContext(Dr0/Dr7)在入口无痕拦截执行流voidgate-master/Voidgate/Voidgate.cpp
VEH 单步解密AddVectoredExceptionHandler逐条解密/加密,维持"仅一条明文"voidgate-master/Voidgate/Voidgate.cpp

Voidgate 的价值不在于某个单一 API,而在于三者协同形成的闭环:VirtualAlloc 提供"可原地改写的舞台",硬件断点提供"无痕的第一脚刹车",VEH 提供"持续单步的解密引擎"。理解了这条接力链,你就掌握了内存扫描绕过中最经典的"运行时逐指令解密"范式。(本项目为学术目的,实际使用请遵守当地法律法规。)

【免费下载链接】VoidgateA technique that can be used to bypass AV/EDR memory scanners. This can be used to hide well-known and detected shellcodes (such as msfvenom) by performing on-the-fly decryption of individual encrypted assembly instructions, thus rendering memory scanners useless for that specific memory page.项目地址: https://gitcode.com/gh_mirrors/vo/Voidgate

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/22 15:07:41

RoundPrices取整难题精讲:airbnb题库中贪心策略的完整解法

RoundPrices取整难题精讲&#xff1a;airbnb题库中贪心策略的完整解法 【免费下载链接】airbnb 项目地址: https://gitcode.com/gh_mirrors/ai/airbnb RoundPrices&#xff08;价格取整&#xff09;是 airbnb 面试题库&#xff08;gh_mirrors/ai/airbnb&#xff09;中的…

作者头像 李华
网站建设 2026/8/22 15:07:31

Jongo对象映射指南:Jackson让POJO与MongoDB文档无缝互转

Jongo对象映射指南&#xff1a;Jackson让POJO与MongoDB文档无缝互转 【免费下载链接】jongo Query in Java as in Mongo shell 项目地址: https://gitcode.com/gh_mirrors/jo/jongo Jongo 是一个轻量级 Java 框架&#xff0c;它的核心能力是通过内置的 Jackson 对象映射…

作者头像 李华