EDR规避深度剖析:系统调用间接执行、ETW绕过与内核回调脱钩

admin 2026-07-14 05:49:03 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文深入剖析了2025年终端安全对抗中EDR规避的三大前沿技术:间接系统调用通过从ntdll.dll内合法地址执行syscall来绕过用户态hook;ETW绕过通过patchEtwEventWrite等函数使EDR无法接收关键事件;内核回调脱钩通过遍历并清零EDR注册的回调函数指针来隐藏进程创建等行为。文章指出攻击者已能在500ms内完成规避,防御方则向硬件虚拟化、行为分析和内存完整性扫描演进。建议防御者采用纵深防御策略,结合应用白名单、网络分段和最小权限原则。 综合评分: 84 文章分类: 红队,渗透测试,恶意软件,安全工具,实战经验


cover_image

EDR规避深度剖析:系统调用间接执行、ETW绕过与内核回调脱钩

原创

Pik安全实验室 Pik安全实验室

Pik安全实验室

2026年7月13日 15:54 广东

在小说阅读器读本章

去阅读

从Userland到Kernel:2025年终端安全对抗的最前线  |  前沿攻防技术系列

————————————————————————————————————————

一、终端对抗的新格局

EDR(Endpoint Detection and Response)已经成为企业安全的基础设施。CrowdStrike、Microsoft Defender for Endpoint、SentinelOne三巨头占据了全球90%以上的市场份额。但与此同时,EDR规避技术也进入了高度工程化的阶段——从简单的进程注入发展到了内核回调脱钩、硬件断点利用等底层对抗。

2025年,攻击者已经不再讨论”能不能绕过EDR”,而是讨论”绕过EDR需要多少毫秒”。MITRE ATT&CK评估数据显示,顶级攻击团队能够在500ms内完成从初始执行到EDR供应商遥测盲区的转移。

本文将从攻防双视角,深入终端安全对抗的最前沿技术。注意:所有内容均基于公开研究和防御视角,旨在帮助安全团队理解攻击面,而非提供攻击工具。

二、EDR的检测架构——要绕过先要理解

2.1 EDR的传感器布局

现代EDR不是单一模块,而是一个多层传感器网络。理解每个传感器的能力和盲区是规避的基础:

| | | | | | — | — | — | — | | 传感器层 | 实现方式 | 可见范围 | 规避难度 | | 用户态API Hook | ntdll.dll的IAT/EAT Hook | Ring3 API调用 | 中等——已有成熟绕过方案 | | 内核回调(Kernel Callback) | PsSetCreateProcessNotifyRoutine等 | 进程/线程/模块/注册表事件 | 高——需要内核级操作 | | ETW(Event Tracing for Windows) | 系统级事件追踪框架 | 网络连接、DNS查询、进程创建等 | 中高——可被patch | | Minifilter驱动 | 文件系统过滤驱动 | 所有文件读写操作 | 高——触及底层文件IO | | AMSI(Antimalware Scan Interface) | 脚本引擎集成的扫描接口 | PowerShell/VBS/JS/.NET加载 | 低——极易被patch | | 硬件虚拟化(VBS/HVCI) | 基于Hypervisor的隔离监控 | 内核内存完整性 | 极高——需要Hypervisor级对抗 |

2.2 为什么ETW是攻击者的首选目标

ETW是Windows上最强大但最不被理解的安全基础设施。几乎每个攻击行为都会产生ETW事件:

·进程创建 → Microsoft-Windows-Kernel-Process Provider → Event ID 1

·网络连接 → Microsoft-Windows-Kernel-Network Provider → Event ID 3

·DNS查询 → Microsoft-Windows-DNS-Client Provider → Event ID 3008

·PowerShell执行 → Microsoft-Windows-PowerShell Provider → Event ID 4103/4104

·.NET程序集加载 → Microsoft-Windows-DotNETRuntime Provider

攻击者的核心逻辑是:如果我能控制ETW,我就能控制EDR看到什么。以下是三种核心绕过手法。

三、系统调用间接执行(Indirect Syscall)

3.1 为什么直接Syscall已经不够了

早期EDR规避方案使用直接的syscall指令来绕过ntdll.dll的用户态Hook。但现代EDR已经进化——它们在内核层面通过ETW栈跟踪或内核回调监控syscall的返回地址。如果syscall指令来自ntdll.dll以外的内存区域(如手动分配的可执行内存),立即触发告警。

这就是间接系统调用(Indirect Syscall)诞生的背景——在ntdll.dll模块内部找一个合法的syscall指令地址,将控制流”伪装”成来自合法模块。

3.2 间接Syscall的核心实现

// 间接系统调用的核心逻辑(C伪代码) typedef NTSTATUS (NTAPI* pNtAllocateVirtualMemory)(     HANDLE, PVOID*, ULONG_PTR, PSIZE_T, ULONG, ULONG );

// 步骤1:从ntdll.dll中定位syscall gadget PVOID FindSyscallGadget() {     HMODULE ntdll = GetModuleHandle(L”ntdll.dll”);     PUCHAR base = (PUCHAR)ntdll;

    // NtAllocateVirtualMemory在ntdll中的偏移     PUCHAR func = base + GetNtFunctionOffset(“NtAllocateVirtualMemory”);

    // 在函数体内搜索 syscall; ret 序列(0x0F 0x05 0xC3)     for (int i = 0; i < 32; i++) {         if (func[i] == 0x0F && func[i+1] == 0x05 && func[i+2] == 0xC3) {             return &func[i];  // 返回合法syscall gadget的地址         }     }     return NULL; }

// 步骤2:设置SSN(System Service Number)和参数 NTSTATUS IndirectNtAllocateVirtualMemory(     HANDLE hProcess, PVOID* baseAddr, ULONG_PTR zeroBits,     PSIZE_T size, ULONG allocType, ULONG protect) {     PVOID gadget = FindSyscallGadget();     DWORD ssn = GetSyscallNumber(“NtAllocateVirtualMemory”);

    // 设置寄存器:RAX=SSN, R10=第一个参数     // 然后跳转到ntdll.dll中的合法syscall gadget     // 此时内核看到的返回地址在ntdll.dll内,EDR不会触发告警     __asm {         mov r10, rcx           // 第一个参数放入R10         mov eax, ssn           // 系统调用号         jmp gadget             // 跳转到合法gadget(不是call,所以返回                                // 地址保持在调用者的合法堆栈中)     } }

3.3 EDR的反制:调用栈验证

面对间接syscall,EDR厂商升级了检测策略——通过内核回调(PsSetCreateProcessNotifyRoutine等)获取用户态调用栈,验证调用来源:

EDR内核回调中的调用栈验证逻辑:

  1. 捕获syscall发生时的用户态RSP
  2. 遍历调用栈帧
  3. 验证关键函数的返回地址是否落在对应模块的合法地址范围内
  4. 如果发现返回地址指向未知内存区域或    栈帧结构异常 → 判定为间接调用,触发高级告警

攻击者的进一步对抗:

  • Stack Spoofing:伪造调用栈帧使得栈回溯结果   看起来完全合法
  • 使用ROP链在合法模块内部跳转(如ntdll中   的其他gadget),使栈回溯指向合法地址

Stack Spoofing示例(简化): __asm {     // 推送伪造的返回地址,都是合法模块内的地址     push fake_ret_addr_3   // ntdll!LdrpDoDebuggerBreak+0x1c     push fake_ret_addr_2   // kernel32!BaseThreadInitThunk+0x14     push fake_ret_addr_1   // ntdll!RtlUserThreadStart+0x21     jmp indirect_syscall_gadget     // 当EDR回溯这个栈时,看到的是一个完全正常的调用链 }

四、ETW的完整攻防

4.1 ETW的内部架构与攻击面

ETW由三个核心组件构成,每个都是潜在的攻击面:

·Providers(提供程序):产生事件的组件,如内核和用户态应用程序

·Controllers(控制器):管理ETW会话的组件,负责启动/停止追踪

·Consumers(消费者):接收和处理事件的组件,如EDR的遥测收集器

攻击者主要针对Provider和Consumer之间的数据路径。核心技术是patch EtwEventWrite(ntdll中的ETW写入函数),使其在关键事件发生时不写入数据。

4.2 ETW Patch的三种技术路线

技术1:直接Patch EtwEventWrite // 最粗暴但有效的方法——让ETW写入直接返回成功 // 找到EtvEventWrite函数,将函数开头改为 ret 0x14 PUCHAR etwFunc = GetProcAddress(ntdll, “EtwEventWrite”); DWORD oldProtect; VirtualProtect(etwFunc, 1, PAGE_EXECUTE_READWRITE, &oldProtect); *etwFunc = 0xC3;  // 0xC3 = RET指令 VirtualProtect(etwFunc, 1, oldProtect, &oldProtect);

技术2:Hook NtTraceEvent // EtwEventWrite最终会调用NtTraceEvent进行实际的系统调用 // 在NtTraceEvent入口处设置inline hook // 检测到特定GUID(如PowerShell的ETW Provider GUID)时直接返回

技术3:内存补丁 EtwEventWriteFull // Patch EtwEventWriteFull中的关键逻辑分支 // 使其在任何过滤条件下都跳过事件写入 // 更隐蔽但需要定位正确的偏移量

防御检测:

  • 检查ntdll.dll的.text段完整性(内存 vs 磁盘对比)
  • 监控VirtualProtect调用中涉及ntdll地址的情况
  • ETW本身可以监控其他ETW Provider的健康状态

五、内核回调脱钩(Kernel Callback Unhooking)

5.1 回调的工作原理

EDR在内核注册多种回调来接收系统事件。Windows内核维护着多个回调数组——每个数组是一个链表或数组结构,EDR将自己的回调函数地址插入其中。攻击者可以遍历这些数组,删除或无效化EDR的回调:

关键回调类型及其在内核中的位置:

  1. 进程通知回调    – API: PsSetCreateProcessNotifyRoutine(Ex)    – 内部结构: PspCreateProcessNotifyRoutine[]    – 触发时机: 进程创建/退出时    – 脱钩方法: 遍历数组,将EDR的回调条目清零

  2. 线程通知回调    – API: PsSetCreateThreadNotifyRoutine(Ex)    – 内部结构: PspCreateThreadNotifyRoutine[]    – 触发时机: 线程创建/退出时

  3. 模块加载回调    – API: PsSetLoadImageNotifyRoutine(Ex)    – 内部结构: PspLoadImageNotifyRoutine[]    – 触发时机: DLL/EXE加载到内存时

  4. 注册表回调    – API: CmRegisterCallback(Ex)    – 内部结构: CallbackListHead(双向链表)    – 触发时机: 任何注册表操作时

  5. 对象管理器回调    – API: ObRegisterCallbacks    – 内部结构: ObpCallbackListHead    – 触发时机: 进程/线程句柄的创建和复制时    – 脱钩难度: 最高——回调结构在受保护的内核内存中

5.2 实战脱钩流程

回调脱钩的基本流程(需要驱动级权限执行):

  1. 获取内核基址:通过NtQuerySystemInformation(SystemModuleInformation)枚举内核模块

  2. 定位回调数组:通过特征码扫描或PDB符号解析,定位PspCreateProcessNotifyRoutine等全局变量

  3. 枚举回调条目:遍历数组中的每个回调结构,检查回调地址所属的驱动模块

  4. 识别EDR回调:判断回调函数地址是否属于EDR的驱动模块(如CsAgent.sys for CrowdStrike)

  5. 脱钩操作:将目标回调条目的函数指针清零,或标记为Inactive

  6. 清理痕迹:恢复被修改的内核结构的原始保护属性

防御要点:PatchGuard(内核补丁保护)会在随机间隔检查关键内核结构的完整性,包括回调数组。检测到篡改后会触发Bug Check 0x109(CRITICAL_STRUCTURE_CORRUPTION)导致蓝屏。高级攻击者通过禁用PatchGuard(需要Bootkit级别攻击)或利用Hypervisor虚拟化在更深层拦截来绕过。

六、EDR厂商的反制演进

防御方并非停滞不前。以下是2024-2025年EDR厂商的核心反制手段:

·从内核回调向硬件虚拟化迁移:Microsoft的VBS(Virtualization-Based Security)将关键安全组件移至Hypervisor层,即使攻击者控制了内核也难以触及

·用户态行为分析:不再单纯依赖API监控,而是分析进程整体的行为图(父子进程关系、网络连接模式、内存分配模式)

·机器学习异常检测:在传感器端部署轻量级ML模型,检测异常的系统调用模式(如短时间高密度syscall = 可疑)

·内存完整性扫描:定期对比关键DLL(ntdll/kernel32)的磁盘版本和内存版本,检测Inline Hook和Patch

·内核回调的”看门狗”机制:定期验证所有注册回调都在正常运行,被脱钩立即告警

七、总结

终端安全对抗的本质是一场永无止境的军备竞赛。攻击者向底层迁移(Ring3→Ring0→Hypervisor→固件),防御方也向底层迁移。但有一个不变的原则:纵深防御。

对于防御者来说,不要指望单一的EDR能阻止所有攻击。结合应用白名单、网络分段、最小权限和运行时行为分析的多层防御体系,才能显著提高攻击成本。同时,定期进行红队演练,模拟最新的EDR规避技术来验证检测能力的有效性,是保持安全态势的必需手段。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Pik安全实验室 Pik安全实验室 Pik安全实验室《EDR规避深度剖析:系统调用间接执行、ETW绕过与内核回调脱钩》

评论:0   参与:  0