从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的检测架构——要绕过先要理解

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级对抗

为什么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)

为什么直接Syscall已经不够了

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

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

间接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,所以返回   
// 地址保持在调用者的合法堆栈中)   
}   
}

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的完整攻防

ETW的内部架构与攻击面

ETW由三个核心组件构成,每个都是潜在的攻击面: ·Providers(提供程序):产生事件的组件,如内核和用户态应用程序 ·Controllers(控制器):管理ETW会话的组件,负责启动/停止追踪 ·Consumers(消费者):接收和处理事件的组件,如EDR的遥测收集器

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

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)

回调的工作原理

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

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

  1. 进程通知回调

  • API: PsSetCreateProcessNotifyRoutine(Ex)

  • 内部结构: PspCreateProcessNotifyRoutine[]

  • 触发时机: 进程创建/退出时

  • 脱钩方法: 遍历数组,将EDR的回调条目清零

  1. 线程通知回调

  • API: PsSetCreateThreadNotifyRoutine(Ex)

  • 内部结构: PspCreateThreadNotifyRoutine[]

  • 触发时机: 线程创建/退出时

  1. 模块加载回调

  • API: PsSetLoadImageNotifyRoutine(Ex)

  • 内部结构: PspLoadImageNotifyRoutine[]

  • 触发时机: DLL/EXE加载到内存时

  1. 注册表回调

  • API: CmRegisterCallback(Ex)

  • 内部结构: CallbackListHead(双向链表)

  • 触发时机: 任何注册表操作时

  1. 对象管理器回调

  • API: ObRegisterCallbacks

  • 内部结构: ObpCallbackListHead

  • 触发时机: 进程/线程句柄的创建和复制时

  • 脱钩难度: 最高——回调结构在受保护的内核内存中

实战脱钩流程

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

  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规避技术来验证检测能力的有效性,是保持安全态势的必需手段。