文章总结: 文章系统解析EDR架构与检测机制,设计哲学为纵深防御与多源关联,假设失陷、重在尽快发现与响应。总体架构为用户态加内核态混合传感器网络:用户态hookDLL挂钩ntdll敏感API并借ETW采集参数上下文,内核态驱动通过进程线程映像回调、ObRegisterCallbacks句柄权限剥离及注册表文件过滤获取难以绕过的高保真信号。结论强调免杀须使EDR无法从任何信号源拼出恶意结论,单点绕过价值有限。 综合评分: 82 文章分类: 终端安全,安全工具,免杀,红队,安全建设
EDR架构与检测机制
原创
pandazhengzheng pandazhengzheng
安全分析与研究
2026年8月27日 22:00 广东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
目录
- EDR 的设计哲学
- EDR 总体架构
- 用户态组件详解
- 内核态组件详解
- 核心检测机制
- 信号采集、关联与判定
- Elastic Defend 的具体实现
- 攻击者规避策略映射
- 检测面的不可消除性与对抗动态
- 小结
1. EDR 的设计哲学
EDR(Endpoint Detection and Response,端点检测与响应)的命名本身就揭示了其三层职责:
- Detection(检测):在端点上采集尽可能多、尽可能高保真的行为信号;
- Response(响应):在判定为恶意时执行响应动作(隔离主机、终止进程、回滚、采集取证包);
- Endpoint(端点):与网络侧的 IDS/IPS、SIEM 互补,提供”最后一跳”的主机内可见性。
EDR 的设计哲学可概括为 **”纵深防御 + 多源关联”**:
- 纵深防御:不依赖单一信号源。用户态 hook、内核回调、ETW、内存扫描、文件/网络监控同时存在,攻击者需同时规避所有层才完全隐蔽。
- 多源关联:单一原子事件(如一次
VirtualAllocEx)通常不告警;EDR 将多个原子事件按时间窗口、主体关系关联成 行为序列,再与规则匹配。这使得”单点绕过”价值有限——即便绕过某一信号,其余信号仍可能拼出完整行为链。 - 高保真优先:在用户态信号易被绕过的情况下,EDR 越来越依赖内核态、硬件辅助(ETW-TI、VBS/HVCI)的高保真信号。
- 假设 breach:EDR 假设攻击者已进入主机,重点在于”尽快发现并响应”而非”阻止进入”。
理解这一哲学至关重要:免杀的目标不是让某个 API 不告警,而是让 EDR 无法从任何信号源拼出”这是一个恶意行为”的结论。
2. EDR 总体架构
EDR 在 Windows 主机上的部署形态是一个 混合态(用户态 + 内核态)的传感器网络,由一个主进程编排,多个传感器分布到系统各处。
┌─────────────────────────────────────────────────────────────────┐
│ 用户态(User-Mode) │
│ │
│ ┌──────────────┐ ┌──────────────────────────────────────┐ │
│ │ EDR 主进程 │ │ 受保护进程(explorer.exe / svchost / │ │
│ │ elastic-agent│◄──┤ lsass / powershell / ...) │ │
│ │ .exe │ │ ┌──────────────────────────────┐ │ │
│ │ │ │ │ 注入的 Hook DLL(sensor) │ │ │
│ │ - 编排 │ │ │ - inline hook on ntdll │ │ │
│ │ - 规则引擎 │ │ │ - ETW consumer │ │ │
│ │ - 上报 │ │ │ - 调用栈回溯 │ │ │
│ │ - 响应执行 │ │ └──────────────────────────────┘ │ │
│ └──────┬───────┘ └──────────────────────────────────────┘ │
│ │ │
└─────────┼────────────────────────────────────────────────────────┘
│ IOCTL / 共享内存 / ETW
┌─────────┼────────────────────────────────────────────────────────┐
│ ▼ 内核态(Kernel-Mode) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ EDR 内核驱动(elastic-driver.sys) │ │
│ │ - PsSetCreateProcessNotifyRoutine(Ex) │ │
│ │ - PsSetCreateThreadNotifyRoutine │ │
│ │ - PsSetLoadImageNotifyRoutine │ │
│ │ - ObRegisterCallbacks(句柄创建) │ │
│ │ - CmRegisterCallback(注册表) │ │
│ │ - MiniFilter(文件系统) │ │
│ │ - WFP / NDIS(网络) │ │
│ │ - ETW-TI 订阅(Threat Intelligence) │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
2.1 信号流向
- 原子事件产生:用户态 API 调用、内核回调触发、ETW 事件写入;
- 本地预处理:传感器对事件做过滤、富化(补充进程上下文、命令行、签名状态);
- 上报至 EDR 主进程:通过 IPC(命名管道、共享内存、ALPC)或 ETW 实时通道;
- 规则引擎评估:在本地按规则做行为序列匹配,产生告警;
- 云端关联:事件同时上报至云端 SIEM/Elasticsearch,做跨主机、跨时间的关联分析与 ML 检测;
- 响应:本地或云端触发响应动作。
2.2 为什么需要”混合态”
- 用户态:能感知 API 参数、调用栈、内存内容,但易被同进程内的攻击者修改/绕过;
- 内核态:对用户态透明、难以绕过,但参数上下文(尤其是用户态缓冲区内容)获取成本高,且受 PatchGuard 约束;
- 两者互补:用户态 hook 提供”丰富的参数上下文”,内核回调提供”不可绕过的存在性证明”,ETW-TI 提供”高保真的敏感操作遥测”。
3. 用户态组件详解
3.1 EDR 主进程
以 Elastic Defend 为例,主进程为 elastic-agent.exe,其下挂载多个 input/beat(如 endpoint-defend input)。主进程职责:
- 策略下发与编排:从 Elastic Security 控制面拉取检测规则、响应策略、漏洞驱动黑名单,分发给各传感器;
- 传感器生命周期管理:启动、注入、重启 hook DLL;
- 事件聚合与上报:将本地事件批量发送至 Elasticsearch(Fleet/ES 端点);
- 响应执行:接收响应指令(kill、quarantine、isolate),通过内核驱动或用户态 API 执行;
- 自保护:通过内核驱动保护自身进程不被终止、自身驱动不被卸载、自身配置不被修改。
3.2 注入到受保护进程的 Hook DLL
这是 EDR 用户态检测的核心载体。注入方式包括:
- 早期注入(进程创建时):内核驱动在
PsSetCreateProcessNotifyRoutineEx回调中,对新建进程挂起并通知用户态 EDR,EDR 通过QueueUserAPC+NtMapViewOfSection或CreateRemoteThread+LoadLibrary注入 hook DLL,再恢复进程。此方式使 hook DLL 在进程第一条用户态指令前就位。 - 运行时注入:对已运行的受保护进程,通过
CreateRemoteThread注入。 - AppInit_DLLs:较老的机制,对加载 User32 的进程自动加载指定 DLL,现已较少使用且易被察觉。
3.2.1 Hook DLL 的工作内容
注入后,hook DLL 会:
- 解析
ntdll.dll导出表,定位需要 hook 的Nt*/Zw*函数; - 安装 inline hook:保存原始序言字节,覆写为
jmp <edr_handler>(x64 下通常用mov rax, addr; jmp rax的 12 字节形式,或热补丁式的 5 字节jmp rel32+ nop); - 安装 ETW consumer:订阅
Microsoft-Windows-Kernel-*、.NET Runtime、PowerShell等 Provider; - 建立与主进程的 IPC 通道:用于上报事件、接收策略更新;
- 注册 DLL 通知:通过
LdrRegisterDllNotification感知后续 DLL 加载,对新加载的 DLL(如攻击者注入的 payload DLL)做扫描。
3.2.2 Hook 的目标函数(典型集合)
| 函数 | 检测意图 |
| — | — |
| NtAllocateVirtualMemory | 检测跨进程/可执行内存分配(RWX、Private+Execute) |
| NtProtectVirtualMemory | 检测权限提升至可执行(尤其 RWX→RX 的 shellcode 准备) |
| NtWriteVirtualMemory | 检测跨进程内存写入(shellcode 注入) |
| NtCreateThreadEx | 检测跨进程线程创建(Remote Thread Injection) |
| NtSetInformationThread | 检测 ThreadHideFromDebugger、APC 相关操作 |
| NtQueueApcThread(Ex/Ex2) | 检测 APC 注入 |
| NtOpenProcess / NtOpenThread | 检测跨进程句柄获取(注入前置) |
| NtMapViewOfSection | 检测反射 DLL 加载、进程 hollowing |
| NtUnmapViewOfSection | 检测 module hollowing |
| NtCreateProcessEx | 检测进程 hollowing |
| NtSetContextThread | 检测 thread hijacking |
| NtLoadDriver | 检测驱动加载(BYOVD) |
| RtlAddFunctionTable / LdrLoadDll | 检测反射加载、模块登记 |
3.2.3 Hook 处理例程的逻辑
当被 hook 的 API 被调用时,控制权先转到 EDR 处理例程,例程典型逻辑:
edr_handler(args):
1. 提取参数:目标进程/线程句柄、内存地址、大小、保护属性
2. 解析句柄:NtQueryObject 获取目标进程 PID、映像名
3. 调用栈回溯:RtlVirtualUnwind 检查返回地址合法性
4. 上下文富化:当前进程命令行、父进程、签名状态
5. 规则预匹配:是否命中"高风险操作"特征
6. 决策:
- 放行 → 调用原函数(trampoline)
- 阻断 → 返回 STATUS_ACCESS_DENIED
- 放行并上报 → 调用原函数 + 异步上报事件
- 同步上报 → 上报后等待云端判定再放行/阻断
3.3 ETW 用户态消费者
ETW(Event Tracing for Windows)是 Windows 内置的高性能事件追踪框架。EDR 通过 EnableTraceEx2 启用 Provider,通过 ProcessTrace 消费事件。关键 Provider:
| Provider GUID | 提供的事件 |
| — | — |
| Microsoft-Windows-Kernel-Process | 进程创建/退出、线程创建/退出、映像加载 |
| Microsoft-Windows-Kernel-Image | 映像加载/卸载 |
| Microsoft-Windows-Kernel-File | 文件操作 |
| Microsoft-Windows-Kernel-Network | 网络连接 |
| Microsoft-Windows-Kernel-Registry | 注册表操作 |
| Microsoft-Windows-DotNETRuntime | .NET Assembly 加载、方法 JIT |
| Microsoft-Windows-PowerShell | PowerShell 脚本执行、命令 |
| Microsoft-Windows-Kernel-Process (内核) | 内核态进程事件 |
注意:ETW 自身也通过 EtwEventWrite 写入事件,该函数位于 ntdll,EDR 可对其 hook,从而感知并篡改其他 ETW 消费者的事件流(攻击者反之也可 patch EtwEventWrite 使 EDR 收不到事件,即”ETW blind”)。
4. 内核态组件详解
内核态组件是 EDR 最难绕过的部分,因为:
- 用户态进程无法直接修改内核数据结构(除非通过漏洞);
- 内核回调由操作系统在固定路径触发,用户态无法”不经过”这些路径;
- ETW-TI 由 Microsoft 在内核埋点,EDR 只需订阅即可获得高保真事件。
4.1 EDR 内核驱动
以 Elastic 为 elastic-driver.sys,需通过 ELAM(Early Launch Anti-Malware)或普通方式加载。驱动职责:
4.1.1 进程/线程/映像通知回调
PsSetCreateProcessNotifyRoutineEx(Callback, TRUE); // 进程创建/退出
PsSetCreateThreadNotifyRoutine(Callback); // 线程创建/退出
PsSetLoadImageNotifyRoutine(Callback); // 映像加载
-
进程创建回调:获得
PCREATE_PROCESS_NOTIFY_INFO,含父 PID、命令行、映像路径、创建状态。EDR 在此: -
比对漏洞驱动黑名单,阻断加载;
-
检查可疑父子关系(如
winword.exe→cmd.exe→powershell.exe); -
触发用户态 hook DLL 注入。
-
线程创建回调:获得创建者 PID、新线程 TID、目标进程 PID。跨进程线程创建(创建者 ≠ 目标)是注入强信号。
-
映像加载回调:获得映像基址、大小、路径、PID。EDR 在此:
-
记录每个进程加载的模块清单,供后续”模块是否在 Ldr 链表”校验;
-
检测从临时路径、UNC 路径加载的 DLL;
-
检测映像加载后
.text被修改(module stomping)。
4.1.2 对象回调(句柄创建)
OB_CALLBACK_REGISTRATION reg = {
.OperationRegistrationCount = 2,
.OperationRegistration[0] = { OB_PREOP_HANDLE_CREATE, PreOpCreateHandle },
.OperationRegistration[1] = { OB_PREOP_HANDLE_DUPLICATE, PreOpDuplicateHandle },
...
};
ObRegisterCallbacks(®, &handle);
EDR 对 PsProcessType、PsThreadType 注册 Pre-Operation 回调,在句柄创建/复制返回给调用方前修改 GrantedAccess,剥离危险权限:
- 对 EDR 自身进程:剥离
PROCESS_TERMINATE、PROCESS_VM_WRITE、PROCESS_VM_OPERATION、PROCESS_CREATE_THREAD,实现自保护; - 对
lsass.exe等敏感进程:剥离PROCESS_VM_READ,阻断凭据转储; - 对跨进程句柄:记录”谁拿到了对谁的什么权限”,供行为关联。
关键点:ObRegisterCallbacks 在句柄真正创建前生效,攻击者无法在用户态绕过——即便调用 NtOpenProcess 的 stub 被 hook 绕过,句柄仍要经过对象回调。
4.1.3 注册表回调
CmRegisterCallback(RegistryCallback, NULL, &cookie);
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全分析与研究 pandazhengzheng pandazhengzheng《EDR架构与检测机制》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论