EvilBytecode/Ebyte-amsi-patchless-vehhwbp

GitHub: EvilBytecode/Ebyte-amsi-patchless-vehhwbp

利用硬件断点和VEH异常处理器实现无内存修改的AMSI绕过,在函数执行前拦截并强制返回安全结果。

Stars: 45 | Forks: 8

# Ebyte-amsi-patchless-vehhwbp 使用硬件断点和向量化异常处理器(Vectored Exception Handler)实现无补丁 AMSI 绕过,在 `AmsiScanBuffer` 和 `AmsiScanString` 执行前拦截它们。该绕过技术从原始栈帧读取第 5 个参数(AMSI 结果指针),强制返回干净结果,并在不修改内存中 AMSI 代码的情况下返回给调用者。 ## 背景 ### AMSI 架构 AMSI 通过 `amsi.dll` 导出的 `AmsiScanBuffer` 和 `AmsiScanString` 提供内容扫描功能。 ### 硬件断点 (HWBP) x64 调试寄存器 (DR0-DR7) 提供 CPU 级别的断点功能: - **DR0-DR3**:断点地址(共 4 个可用) - **DR6**:调试状态寄存器 - **DR7**:调试控制寄存器(启用断点,设置类型/长度) 对于执行断点(在 DR7 中配置),CPU 会在执行断点地址处的指令**之前**触发 `STATUS_SINGLE_STEP` (NTSTATUS 0x80000004)。 ### 向量化异常处理器 (VEH) 通过 `AddVectoredExceptionHandler()` 注册的 VEH 处理器会在 SEH 处理器之前被调用。它们接收包含完整 CPU 上下文(RIP, RSP, RAX 等)的 `EXCEPTION_POINTERS`,并可以修改它以重定向控制流。 ## 逆向工程分析 ### AmsiScanBuffer 函数序言 入口点反汇编(在 x64dbg 中 Ctrl + G -> AmsiScanbuffer/AmsiScanString)`0x00007FFB30778160`: ``` 00007FFB30778160 | 48:895C24 08 | mov qword ptr ss:[rsp+8],rbx 00007FFB30778165 | 48:896C24 10 | mov qword ptr ss:[rsp+10],rbp 00007FFB3077816A | 48:897424 18 | mov qword ptr ss:[rsp+18],rsi 00007FFB3077816F | 57 | push rdi 00007FFB30778170 | 41:56 | push r14 00007FFB30778172 | 41:57 | push r15 00007FFB30778174 | 48:83EC 70 | sub rsp,70 ``` ### x64 调用约定 在函数入口(序言之前),栈布局如下: ``` [rsp+0x00] = Return address [rsp+0x08] = Shadow space [rsp+0x10] = Shadow space [rsp+0x18] = Shadow space [rsp+0x20] = 5th parameter (AMSI_RESULT* result pointer) ``` 寄存器参数:`RCX` (HAMSICONTEXT), `RDX` (buffer), `R8` (length), `R9` (name)。 **关键发现:** 在序言修改栈之前,结果指针位于 `[rsp+0x20]`。 ## 技术实现 ### 阶段 1:初始化 1. 解析 `amsi.dll` 并获取 `AmsiScanBuffer`/`AmsiScanString` 地址 2. 通过 `AddVectoredExceptionHandler(1, VehHandler)` 注册 VEH 处理器 3. 使用 `CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD)` 枚举所有线程 **局限性:** 除非实施额外的监控,否则初始化后创建的线程将不会设置断点。 ### 阶段 2:硬件断点安装 对于每个现有线程: 1. 使用 `THREAD_GET_CONTEXT | THREAD_SET_CONTEXT` 打开线程 2. 使用 `CONTEXT_DEBUG_REGISTERS` 标志获取上下文 3. 设置 `DR0 = AmsiScanBuffer`, `DR1 = AmsiScanString` 4. 配置 `DR7` 以启用本地执行断点 5. 使用 `SetThreadContext()` 写回上下文 **注意:** 某些 EDR 和受保护进程可能会限制调试寄存器的写入。此技术可能不适用于所有 Windows 版本或进程保护环境。 ### 阶段 3:基于异常的拦截 当 AMSI 函数被调用时: 1. 硬件断点触发 → CPU 触发 `STATUS_SINGLE_STEP` (0x80000004) 2. VEH 处理器接收包含完整上下文的异常 3. 验证异常地址与目标函数匹配 4. 从 `[rsp+0x20]`(第 5 个参数)读取结果指针 5. 清零 `AMSI_RESULT` 结构 6. 重定向控制流: - `RIP = return address` (来自 `[rsp+0x00]`) - `RSP += 8` (模拟 `RET`) - `RAX = 0` (成功) 7. 返回 `EXCEPTION_CONTINUE_EXECUTION` ## 攻击流程 ``` DLL Load → InitializeThread() → Thread Enumeration → HWBP Installation ↓ Application calls AmsiScanBuffer() ↓ HWBP triggers → STATUS_SINGLE_STEP → VEH Handler ↓ PoisonScanResult() + ModifyReturnFlow() ↓ Execution resumes at return address (RAX=0, result=clean) ``` ## PoC image ## 参考资料 - [Microsoft x64 调用约定](https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention) - [硬件调试寄存器](https://wiki.osdev.org/CPU_Registers_x86-64#Debug_Registers) - [向量化异常处理](https://docs.microsoft.com/en-us/windows/win32/debug/vectored-exception-handling) - [AMSI 文档](https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal) - [CS 无补丁 AMSI 绕过](https://www.crowdstrike.com/en-us/blog/crowdstrike-investigates-threat-of-patchless-amsi-bypass-attacks/) ## 免责声明 本研究仅用于教育和防御性安全目的。请仅在授权的安全测试环境中使用。 **作者:** Evilbytecode **日期:** 2025 年 6 月
标签:AmsiScanBuffer, AMSI绕过, Conpot, DNS 反向解析, EDR对抗, Patchless, TGT, UML, VEH异常处理, Windows安全, x64汇编, 二进制安全, 云资产清单, 免杀技术, 内存操作, 动态分析规避, 威胁检测, 攻防演练, 暴力破解检测, 硬件断点, 端点可见性, 逆向工程