利用双机调试环境对杀软内核研究
字数 3680
更新时间 2026-02-27 03:00:50

利用双机调试环境对杀软内核研究

前言

在 Windows 架构中,杀软内核驱动通常扮演着“超级裁判”的角色。它通过在内核中植入一系列通知回调(Notification Routines)和微过滤监听器(Minifilter Callbacks),将自己强行插入到系统处理关键动作(如进程启动、文件读写、内存映射)的路径上。

分析这些驱动的概念核心可以归纳为以下三个维度:

监控点的“锚定”与“劫持”

杀软并不生成系统动作,它只“订阅”动作。分析的首要目标是确认它在内核中注册了哪些眼线。

  • 注册回调:利用 PsSetCreateProcessNotifyRoutine 等标准接口,确保任何新进程的诞生都必须先经过它的逻辑判断。
  • 对象过滤:通过 ObRegisterCallbacks 监控句柄操作,防止恶意程序尝试打开 LSASS 等敏感进程的句柄。
  • 文件过滤:利用 Minifilter 框架,在文件到达磁盘前进行扫描,这是拦截勒索软件或恶意载荷(Payload)落地的核心战场。

策略池的“匹配”与“决策”

当一个动作被拦截下来后,驱动内部会进入逻辑决策阶段。

  • 静态特征匹配:将当前进程名、路径或证书信息与内存中的全局规则链表(例如 MpBmDocOpenRules)进行快速比对。
  • 动态行为评分:根据进程短时间内的 API 调用序列(例如:申请内存 -> 修改权限 -> 远程注入)进行启发式评估。
  • 内核态与用户态的通信:内核驱动(EDR Driver)通过 FilterCommunicationPort 将复杂的判定任务“外包”给用户态的高性能分析服务,并根据返回的结果决定是否给该动作判“死刑”。

“阻断”与“放行”的终极对抗

分析的终点在于理解杀软如何下达指令。

  • 状态码注入:在回调中将 CreationStatus 修改为 STATUS_ACCESS_DENIED,从内核底层撤销该动作的合法性。
  • 上下文擦除:在恶意代码执行前,通过抹除其内存映射或强制结束其线程池来实现无感阻断。

搭建双机调试环境

本文以主机 Windows 11 调试虚拟机 Windows 10 为例。

虚拟机配置步骤

  1. 打开虚拟机设置,移除打印机,避免占用串口位置。
  2. 添加一个串行端口,配置参数需与示例保持一致。
  3. 添加串口管道,路径设置为 \.\pipe\com_1
  4. 启动虚拟机,以管理员身份运行命令提示符,执行以下命令:
    bcdedit /set “{current}” bootmenupolicy Legacy
    bcdedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200
    bcdedit /copy “{current}” /d “Debug”
    bcdedit /debug “{<上一步返回的GUID>}” on
    
  5. 运行 msconfig,在“引导”选项卡中选择名为“Debug”的启动项。

主机配置与连接

  1. 在主机上使用新版 Windbg 进行调试。
  2. 在 Windbg 中配置串行端口(例如 com1,波特率 115200)。
  3. 重启虚拟机,在启动菜单中选择“Debug”项。
  4. 如果 Windbg 显示“connect”,则表示双机调试环境搭建成功。

深入分析杀软内核回调机制

一、 创建进程回调分析 (PsSetCreateProcessNotifyRoutineEx)

杀软通过 PsSetCreateProcessNotifyRoutineEx 注册回调。每当一个新的 EPROCESS 被分配并准备运行时,内核会暂停进程,并逐一询问杀软进程的安全性。

1. 定位与查看回调

在 Windbg 中,可以查看 Windows Defender (WdFilter) 的进程创建回调函数:

1: kd> u WdFilter!MpCreateProcessNotifyRoutineEx L50

通过对反汇编代码的分析,可以识别出 Defender 的多个安全检查点。

2. 关键检测点分析

  • 文件名检查与规范化
    在地址 fffff80a83ab8d6c处,代码会获取ImageFileName指针。随后,在fffff80a83ab8d8f 调用 WdFilter!MpGetImageNormalizedName。此举并非直接信任原始路径,而是进行路径格式化,旨在防止通过符号链接或长路径名等方式进行的路径欺骗。
  • 恶意文件处理与状态码注入
    在地址 fffff80a83ab8ea2处,指令mov dword ptr [rdi+40h],0C0000022h 将拒绝访问的状态码 (STATUS_ACCESS_DENIED) 写入 _PS_CREATE_NOTIFY_INFO结构的CreationStatus` 字段,从根本上否决进程创建。
  • 父进程上下文检测
    fffff80a83ab921e调用WdFilter!MpGetProcessContextById获取父进程上下文。随后在fffff80a83ab9230 进行标记 (bts dword ptr [rcx+34h], 0Fh),这是为了检测父进程的上下文信息,可能用于判断创建链条是否可疑。
  • 文档编辑器/宏病毒防御
    fffff80a83ab9241调用WdFilter!MpSetProcessDocOpenRule。此函数会回溯父进程,检查其是否为文档编辑器(如 msaccess.exe, powerpoint.exe, acrord32.exe),并检测其是否试图启动子进程(如 cmd, powershell`),以防御利用文档宏或脚本的威胁。
  • 用户态通信(云查杀/启发式)
    fffff80a83ab93e4调用WdFilter!MpSendProcessMessage`。此调用可能负责将进程信息发送给用户态服务,进行更复杂的云端查杀或启发式分析。
  • 特殊进程处理
    • MpSetProcessExempt: 判断进程是否为关键系统进程,这类进程可能享有豁免权。
    • MpSetProcessHardening: 应用相关安全策略,例如禁止进程加载非微软签名的 DLL。
  • 检测创建进程的调用者
    fffff80a83ab9300调用IoThreadToProcess`,旨在获取发起创建请求的线程所属的进程,并与当前目标进程进行比较,以检测是否存在跨进程的远程创建行为。
  • 白名单校验
    通过调用 FltParseFileName 获取文件全路径,再调用 RtlEqualUnicodeStringRtlPrefixUnicodeString 与预定义的白名单路径或字符串进行比对,若匹配则放行。
  • 扫描超时设置
    查询全局数据结构,可发现 Defender 默认的扫描超时时间(例如,示例中地址 fffff80a83a779a8 处的值 000013880000ea60 可能代表 60 秒)。

二、 线程创建回调分析 (PsSetCreateThreadNotifyRoutine)

现代 EDR/杀软广泛利用 PsSetCreateThreadNotifyRoutine 监控线程创建,使得传统的 CreateRemoteThread 注入方式极易被检测。

1. 定位回调数组

通过反汇编系统函数 PspSetCreateThreadNotifyRoutine,可以定位到线程回调数组 PspCreateThreadNotifyRoutine 的地址(例如 fffff800'16f89970)。

2. 分析已注册的回调

查询该地址,可以发现多个驱动已注册回调。以 Windows Defender 为例:

1: kd> dps ffff8283`48008580 L2
ffff8283`48008580 00000000`00000020
ffff8283`48008588 fffff80a`83aaf690 WdFilter!MpCreateThreadNotifyRoutine

1: kd> dps ffff8283`480086d0 L2
ffff8283`480086d0 00000000`00000020
ffff8283`480086d8 fffff80a`83ab5db0 WdFilter!MpCreateThreadNotifyRoutineEx
  • MpCreateThreadNotifyRoutine:通常进行基础过滤,例如检查全局数据结构 MpData 以判断创建者是否在白名单内。
  • MpCreateThreadNotifyRoutineEx:此函数更为关键,它能够获取 PS_CREATE_THREAD_NOTIFY_ROUTINE_EX 结构,其中包含线程的初始栈空间和起始地址。它的一项核心检测是检查 StartAddress 是否指向一个合法的、具有 SEC_IMAGE 属性的内存映射区域。如果线程的起始地址指向通过 VirtualAlloc 等 API 分配的普通内存区域,则会被立即识别为可疑的代码注入。

3. 关键检测逻辑

  • 系统进程豁免:代码中 cmp r12d,4 的指令表明,系统进程(PID 通常为 4)创建线程可能不受监控。
  • 跨进程注入检测:函数会获取发起线程创建的当前进程 PID,并与目标进程 PID 进行比较。若不相等,则标记为跨进程注入。

4. 第三方杀软分析(以火绒为例)

安装并重启后,可以在同一回调数组中发现火绒驱动 (sysdiag) 注册的回调函数。通过反汇编其函数(如 KslD!tk::COSCallback::CreateThreadNotifyRoutineEx),可以发现其内部同样维护了一套复杂的回调链,对线程创建进行迭代检查和过滤。

 全屏