第三期:动态行为监控与 API Hooking —— EDR 的“眼睛”与绕过思路

引言 :静态特征可以被抹去,文件可以被加密,但只要程序想要运行、想要注入、想要联网,它就必须在内存中执行动作 。本期我们将深入 Windows 内核与用户态的交界处,解析 EDR 是如何通过 Hook(钩子) ​ 监控一切的,以及攻击者常用的 Direct Syscalls​ 等绕过原理。


一、为什么静态不够?动态才是王道

作为防御者,你必须明白一个铁律:代码如果不运行,就没有危害;一旦运行,就必然留下痕迹。

监控层级 能看到什么 代表工具
**内核层 (Kernel)**​ 进程创建、线程创建、驱动加载、注册表回调 Windows ETW, Sysmon, EDR Kernel Driver
**用户层 (User Mode)**​ API 调用参数、内存读写、网络连接详情 API Monitor, User-mode Hooks

二、EDR 的核心武器:API Hooking(用户态钩子)

大多数 EDR 并不会直接拦截内核,而是通过在用户态插入 **DLL(如 EdrClient.dll)**​ 来实现监控。

1. IAT Hooking(导入表挂钩)

  • 原理 :修改程序的导入地址表(IAT)。当程序调用 CreateFile时,实际上跳转到了 EDR 的代码。

  • 检测信号 :在调试器中看到 CreateFile指向的不是 kernel32.dll,而是一个陌生的 DLL。

2. Inline Hooking(内联挂钩)

  • 原理 :直接修改 API 函数开头的前 5-12 个字节(改为 JMP指令),强行劫持执行流。

  • 目的 :EDR 可以检查参数。例如,如果发现 VirtualAlloc申请的内存属性是 RWX,立即阻断。

3. 防御者视角:如何确认被 Hook?

你可以使用 Process Explorer ​ 或 API Monitor​ 查看进程的模块和钩子。

  • 现象 :某些关键 API 的入口点代码显示为 jmp qword ptr [xxxx]

三、攻击者的反制:Unhooking 与 Syscall

既然 EDR 盯着 API,攻击者就决定不调用 API ,或者绕过 API 直接找系统内核

1. Unhooking(脱钩)

  • 原理 :从磁盘重新读取干净的 ntdll.dll文件,覆盖当前内存中被 EDR Hook 了的代码。

  • 防御信号 :检测到进程对 ntdll.dll的内存区域进行了写操作(WriteProcessMemory或自写)。

2. Direct Syscalls(直接系统调用)

这是现代免杀的灵魂技术。

  • 背景 :Windows API 调用链通常是 User App -> ntdll.dll -> syscall -> kernel。EDR 监控的是 ntdll.dll

  • 绕过 :攻击者直接在代码中硬编码 syscall指令,跳过 ntdll.dll

  • 工具参考SysWhispers2(用于生成系统调用存根)。

防御者笔记 :Direct Syscalls 会让 EDR 失去 API 参数上下文。例如,你只知道程序发起了 NtWriteVirtualMemory,但不知道它具体写了什么内容。

3. Hell's Gate / Halo's Gate

  • 原理:动态寻找系统调用号(Syscall Number),避免在代码中硬编码,防止 YARA 规则匹配。

四、防御实战:Sysmon 配置与 Sigma 规则

作为网安工程师,你无法阻止 Hooking 的绕过,但你可以通过行为关联来发现异常。

1. 监控"可疑的 API 调用序列"

单一 API 不可怕,组合拳才致命。

高危行为组合

  1. VirtualAlloc(申请内存) + WriteProcessMemory(写入内存) + CreateRemoteThread(创建远程线程)。

2. Sysmon 配置示例

请确保你的 Sysmon 监控了 Event ID 8 (CreateRemoteThread) ​ 和 Event ID 10 (Process Access)

XML 复制代码
<Sysmon schemaversion="4.50">
  <EventFiltering>
    <!-- 监控进程注入行为 -->
    <RuleGroup name="Suspicious Injection" groupRelation="or">
      <CreateRemoteThread onmatch="include">
        <TargetImage condition="end with">explorer.exe</TargetImage>
        <TargetImage condition="end with">svchost.exe</TargetImage>
      </CreateRemoteThread>
    </RuleGroup>
  </EventFiltering>
</Sysmon>

3. Sigma 规则示例(检测 Direct Syscall 行为)

虽然难以直接检测 Syscall,但可以检测异常的内存属性

yaml

复制代码
title: 检测 RWX (Read-Write-Execute) 内存分配
logsource:
    category: process_access
detection:
    selection:
        CallTrace|contains: 'unknown'
        GrantedAccess: '0x1FFFFF' # 所有可能的权限
    condition: selection
level: high

五、工具实操:Process Monitor 深度使用

ProcMon​ 是你最好的朋友。

  1. 设置过滤器Operation is CreateRemoteThread then Include

  2. 观察细节

    • Source : 谁发起的?(如 powershell.exe

    • Target : 注入了谁?(如 lsass.exe

    • Result: 成功了还是被拦截了?


六、总结与下期预告

本期我们揭示了 EDR 如何通过 Hooking ​ 监控动态行为,以及攻击者如何通过 Direct Syscalls ​ 试图"隐身"。请记住:防御者不需要堵住所有的 Syscall 漏洞,只需要监控 Syscall 之后的异常行为(如 LSASS 转储)。

下期预告

第四期:无文件攻击与内存驻留(Fileless Attacks) 。我们将聚焦于 Reflective DLL Injection ​ 和 Process Hollowing(进程镂空) 。你将学会如何在没有文件落地的情况下,检测潜伏在 svchost.exe体内的恶意代码。


💡 思考题

如果一个程序调用了 NtAllocateVirtualMemory并在 lsass.exe中写入了数据,但没有触发 CreateRemoteThread,它可能使用了什么技术?(提示:考虑 APC 注入或早鸟注入)。