文章总结: 本文深入探讨内核级攻击技术,指出用户态免杀无法绕过EDR的内核信号源,如进程回调与ETW-TI。主流进入内核途径为BYOVD,利用已签名漏洞驱动获取内核读写原语,进而关闭EDR回调、操作内核数据结构。文章详述了漏洞驱动实例、原语构建、PatchGuard规避及完整免杀链,强调内核攻击的高收益与高风险,为红队实战提供深度技术参考。 综合评分: 90 文章分类: 红队,免杀,漏洞分析
内核级攻击
原创
pandazhengzheng pandazhengzheng
安全分析与研究
2026年8月31日 22:00 广东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
目录
- 为什么需要内核级攻击
- 用户态免杀的极限
- 进入内核的途径
- BYOVD(Bring Your Own Vulnerable Driver)
- 内核读写原语的构建
- 关闭 EDR 内核回调
- 关闭 ETW-TI
- 对 EDR 驱动与用户态进程的攻击
- DKOM 与内核结构操作
- PatchGuard 与稳定性挑战
- EDR 的内核态防御与演进
- 完整内核级免杀链
- 硬件辅助防御与未来
- 内核数据结构的深度剖析
- BYOVD 的实战细节与漏洞驱动剖析
- PatchGuard 的深度分析与规避策略
- 完整内核级免杀链的实战编排
- 小结
1. 为什么需要内核级攻击
1.1 用户态无法触及的信号源
EDR 最强的信号源全部位于内核:
- **
PsSetCreateProcessNotifyRoutineEx**:进程创建/退出通知; - **
PsSetCreateThreadNotifyRoutine**:线程创建/退出通知; - **
PsSetLoadImageNotifyRoutine**:映像加载通知; - **
ObRegisterCallbacks**:句柄创建/复制回调; - **
CmRegisterCallbackEx**:注册表操作回调; - MiniFilter:文件系统操作回调;
- WFP/NDIS:网络回调;
- ETW-TI:内核埋点的高保真事件。
这些信号源由操作系统在固定内核路径触发,用户态进程无法”不经过”这些路径,也无法在用户态关闭它们。只要系统正常运行,这些信号必然产生。
1.2 用户态免杀的极限
前四节的技术组合后,用户态检测面基本覆盖,但:
- shellcode 的每一次系统调用仍被 ETW-TI 记录;
- 进程/线程/映像/句柄操作仍触发内核回调;
- EDR 的内核驱动仍正常工作,汇总所有信号。
结论:对于依赖内核态高保真信号的 EDR(如 Elastic Defend),纯粹的用户态免杀不足以完全逃过检测。攻击者若要彻底”失聪”EDR,必须进入内核关闭这些信号源。
1.3 内核级攻击的收益与代价
收益:
- 使 EDR 的内核信号源整体失效;
- 可直接操作内核数据结构,绕过所有用户态与内核态检查;
- 可破坏 EDR 驱动本身,使其静默或崩溃。
代价:
- 需要漏洞驱动或内核漏洞(门槛高、易被黑名单);
- 需要规避 PatchGuard(稳定性挑战);
- 内核操作一旦失误即 BSOD,隐蔽性反而下降;
- 内核操作本身产生新信号(驱动加载、内核修改),形成新检测面。
2. 用户态免杀的极限
2.1 各检测面的用户态可绕过性
| 检测面 | 用户态可绕过性 | 说明 | | — | — | — | | inline hook | ✓ | Indirect Syscalls | | 用户态 ETW | ✓ | patch EtwEventWrite | | 内存扫描 | ✓ | Module Stomping + Sleep Mask | | 调用栈 | ✓/部分 | Indirect Syscalls + Call Stack Spoofing | | 行为序列 | 部分 | 拆分、噪声、LOLBins | | ETW-TI | ✗ | 内核埋点,用户态无法绕过 | | 内核回调 | ✗ | OS 固定路径,用户态无法绕过 | | PPL 自保护 | ✗ | 需内核操作或 PPL 绕过漏洞 |
2.2 ETW-TI 的不可绕过性
ETW-TI 的埋点位于内核深处(如 MiAllocateVirtualMemory 内部、NtQueueApcThread 的内核实现内),在系统调用的内核处理路径上。即使用户态不经过 ntdll stub(Indirect Syscalls),syscall 指令仍进入内核,仍经过这些埋点。用户态无法关闭、绕过或篡改 ETW-TI 事件。
唯一方式:进入内核,修改 ETW-TI Provider 的 EnableInfo(使其认为没有消费者),或修改 EDR 驱动中订阅 ETW-TI 的逻辑。
2.3 内核回调的不可绕过性
PsSetCreateProcessNotifyRoutineEx 等回调在 NtCreateUserProcess、PspInsertProcess 等内核函数的固定路径上调用。只要进程创建,回调必然触发。用户态无法”不创建进程”或”不让回调触发”。
唯一方式:进入内核,从回调数组中移除 EDR 注册的回调项。
3. 进入内核的途径
3.1 途径概览
| 途径 | 门槛 | 稳定性 | 隐蔽性 | | — | — | — | — | | BYOVD(漏洞驱动) | 中 | 高 | 中(驱动加载有信号) | | 内核漏洞利用 | 极高 | 低 | 高(无驱动加载) | | 早期内核介入(bootkit/UEFI) | 极高 | 中 | 高(但 Secure Boot 阻拦) | | 合法签名驱动 + 漏洞 | 中 | 高 | 中 | | PPL 绕过漏洞 | 高 | 中 | 高 |
3.2 BYOVD 的主导地位
现代 Windows 64 位强制 驱动签名强制(DSE),仅加载经微软签名(含 EV、Attestation、WHQL)的驱动。攻击者无法直接加载自写的未签名驱动。但 已签名但存在漏洞的合法驱动 可正常加载,其漏洞可被利用获得内核读写原语——这就是 BYOVD(Bring Your Own Vulnerable Driver)。
BYOVD 是当前最主流的进入内核途径,因其:
- 门槛适中:漏洞驱动公开可用;
- 稳定性高:合法驱动加载稳定,漏洞利用成熟;
- 无需内核漏洞:不依赖 Windows 内核零日。
4. BYOVD(Bring Your Own Vulnerable Driver)
4.1 原理
- 获取一个已签名但存在漏洞的合法驱动(如
RTCore64.sys、gigabyte.sys、dbutil_2_3.sys、procexp152.sys、iqvw64e.sys等); - 将驱动落盘(其签名合法,可正常通过
NtLoadDriver加载); - 通过驱动的 IOCTL 漏洞获得 任意地址读写 原语;
- 利用该原语定位并关闭 EDR 回调。
4.2 典型漏洞驱动
| 驱动 | 厂商 | 漏洞 | 原语 |
| — | — | — | — |
| RTCore64.sys | Micro-Star (MSI) | 任意物理地址读写 | 物理内存读写 |
| gigabyte.sys | Gigabyte | 任意 MSR/IO 读写 | 内核代码执行 |
| dbutil_2_3.sys | Dell | 任意内核地址读写 | 内核读写 |
| procexp152.sys | Sysinternals (ProcExp) | 任意内核地址读写 | 内核读写 |
| iqvw64e.sys | Intel | 任意内核地址读写 | 内核读写 |
| gdrv.sys | Gigabyte | 任意物理/内核读写 | 内核读写 |
| amp.sys | Palo Alto | 任意内核读写 | 内核读写 |
关键:这些驱动签名合法(WHQL 或 EV),可正常加载。漏洞在于其 IOCTL 处理例程未校验用户态传入的地址/大小,允许用户态指定任意内核地址读写。
4.3 EDR 的反制:漏洞驱动黑名单
EDR(包括 Elastic Defend)维护一个 漏洞驱动黑名单,在映像加载回调(PsSetLoadImageNotifyRoutine)中拦截已知漏洞驱动:
- 检测驱动映像名、哈希、签名者;
- 命中黑名单 → 阻断加载(返回
STATUS_ACCESS_DENIED)或加载后立即卸载。
攻击者的应对:
- 使用尚未被列入黑名单的漏洞驱动(零日或新披露);
- 在 EDR 驱动就位前加载(早期启动);
- 篡改 EDR 的黑名单数据结构(需已进入内核,鸡生蛋问题);
- 修改漏洞驱动的映像名/哈希以绕过黑名单匹配(但签名校验仍需通过)。
4.4 BYOVD 的加载流程
// 1. 落盘漏洞驱动
DWORD len = decodeBase64(vulnDriver, driverPath);
// 2. 创建服务并加载
SC_HANDLE hSvc = CreateService(hSCM, "vulndrv", ..., SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, driverPath);
StartService(hSvc, 0, NULL);
// 3. 打开设备句柄
HANDLE hDev = CreateFile("\\\\.\\vulndrv", ...);
// 4. 通过 IOCTL 获得内核读写原语
DeviceIoControl(hDev, IOCTL_READ, &readReq, ..., &result, ...);
4.5 从物理地址读写到虚拟地址读写
部分漏洞驱动提供物理地址读写(如 RTCore64.sys)。需将物理地址读写转换为虚拟地址读写:
- 利用
MmGetPhysicalAddress的逆运算,或通过页表自映射(PML4)将虚拟地址翻译为物理地址; - 或利用漏洞驱动的其他能力(如
gdrv.sys可直接读写虚拟地址)。
更直接的方式:寻找提供虚拟地址读写的漏洞驱动(如 dbutil_2_3.sys),无需转换。
5. 内核读写原语的构建
5.1 原语接口
内核读写原语提供两个操作:
BOOL kRead(PVOID kAddr, PVOID buf, SIZE_T len); // 读内核内存
BOOL kWrite(PVOID kAddr, PVOID buf, SIZE_T len); // 写内核内存
5.2 通过漏洞驱动 IOCTL
struct ReadReq { PVOID kAddr; PVOID uBuf; SIZE_T len; };
struct WriteReq { PVOID kAddr; PVOID uBuf; SIZE_T len; };
BOOL kRead(PVOID kAddr, PVOID buf, SIZE_T len) {
ReadReq req = { kAddr, buf, len };
DWORD ret;
return DeviceIoControl(hVulnDev, IOCTL_ARBITRARY_READ, &req, sizeof(req), &ret, sizeof(ret), &ret, NULL);
}
5.3 原语的扩展能力
有了任意内核读写,可:
- 解析 ntoskrnl 导出:读
PsLoadedModuleList找到ntoskrnl.exe基址,解析其导出表获取PsSetCreateProcessNotifyRoutine等符号地址; - 扫描未导出符号:通过特征码扫描或从 PDB 获取偏移,定位未导出的全局数组(如
PspCreateProcessNotifyRoutine); - 读写 EDR 驱动内存:定位 EDR 驱动的关键数据结构(规则数组、回调上下文);
- 修改内核数据结构:如
EPROCESS.Token、EPROCESS.ActiveProcessLinks。
6. 关闭 EDR 内核回调
6.1 回调的内核数据结构
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全分析与研究 pandazhengzheng pandazhengzheng《内核级攻击》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。












评论