内核攻防-(2)致盲EDR
字数 4824 2025-08-22 12:23:30

内核攻防:致盲EDR技术详解

需求背景

在APT攻击中,使用驱动致盲EDR(Endpoint Detection and Response)的意义在于通过加载恶意或修改的驱动程序,直接操作内核数据结构,禁用或清除EDR的回调和监控机制,从而绕过安全检测。这种方法能够隐藏攻击行为、规避日志记录和实时响应,确保攻击活动在受害系统中悄无声息地进行,提高持久性和隐蔽性。

驱动解析

内存读写驱动实现

项目代码: https://github.com/k3lpi3b4nsh33/rwdriver

devctrl_RwMemory函数是一个典型的驱动层代码,用于设备驱动程序的I/O控制请求处理,特别是内存读写操作相关的情况。

功能描述

  • 在内核模式下执行内存读写操作
  • 用于在同一进程内复制内存数据

参数说明

  • DeviceObject: 设备对象指针(未使用)
  • irp: I/O请求包指针
  • irpSp: IRP栈位置指针

主要流程

  1. 获取并验证系统缓冲区
  2. 验证内存操作参数(源地址、目标地址、大小)
  3. 执行内存复制操作
  4. 完成IRP请求

返回值

  • 成功: STATUS_SUCCESS
  • 失败: STATUS_INVALID_PARAMETER或STATUS_UNSUCCESSFUL

使用示例
通过设备I/O控制代码调用此函数,传入MEMORY_OPERATION结构体,包含源地址、目标地址和复制大小。

可能的应用场景

  1. 内存读写工具

    • 用户模式程序通过IOCTL调用该函数,向驱动请求读写当前进程的特定内存区域
    • 用于开发调试工具或与进程交互的应用程序
  2. 内核态内存编辑

    • 函数内部调用MmCopyVirtualMemory,直接操作进程的虚拟内存空间
    • 用途包括调试器工具、数据注入(如游戏外挂)、内存复制操作的驱动辅助实现
  3. 反病毒软件或内存分析工具

    • 用于安全领域,如反病毒引擎或内存分析工具,从特定进程中提取敏感信息

驱动利用Exe解析

项目代码: https://github.com/k3lpi3b4nsh33/BlindEdr

核心原理

所有操作的原理是:通过控制驱动的内存读写函数(DriverMemoryOperation),修改相关EDR内核数据结构的地址。

Common.c中,DriverMemoryOperation函数是与驱动交互的关键函数。它传入一个PMemOp结构体,在驱动中使用MmCopyVirtualMemory进行操作。从R3的角度来说,相当于使用了一个处于驱动层的Memcpy函数。

API哈希动态获取

实现的主要目的和意义

  1. 反检测和反调试

    • 避免在程序中直接存储API函数名称字符串
    • 规避静态分析和特征码检测
    • 增加逆向分析的难度
  2. 动态解析

    • 使用哈希值代替明文字符串
    • 运行时动态计算和匹配API函数
    • 绕过导入表(IAT)监控

实现方法

  1. 编写CityHash函数,使用三个不同的哈希值进行计算(FIRST_HASHSECOND_HASHTHIRD_HASH)
  2. API函数解析流程(GetProcAddressH):
    • 遍历模块导出表
    • 计算每个导出函数名的哈希值
    • 与预定义哈希值比对
    • 处理转发函数情况
    • 返回匹配函数地址
  3. 模块句柄的获取(GetModuleHandleH):
    • 支持内核模块和用户模块的处理
    • 使用NtQuerySystemInformation获取系统模块信息
    • 大小写不敏感的哈希匹配

EDR相关模块分析

FLTMGR.SYS的作用

  • 文件操作监控:EDR通过Windows文件系统过滤器框架拦截文件的创建、读取、修改和删除等操作
  • 行为记录:记录终端上的文件活动日志,为威胁分析和回溯提供数据支持
  • 实时拦截:在文件操作发生前拦截威胁操作

NTOSKRNL.exe的作用

  • 作为系统核心,提供基本的内核服务
  • 所有内核模式驱动程序都依赖其提供的接口
  • 用户程序通过系统调用访问其功能(如文件读写、网络通信)

内核函数地址解析机制

  1. 获取目标内核模块的实际基地址
  2. 通过哈希匹配从kernel32.dll中获取LoadLibraryExA/LoadLibraryA函数
  3. 对于FLTMGR.SYS,使用LoadLibraryExA并指定DONT_RESOLVE_DLL_REFERENCES标志加载驱动文件作为模板
  4. 对于ntoskrnl.exe,使用普通的LoadLibraryA加载
  5. 计算目标函数在用户态加载的模块中的偏移,加上实际的内核模块基地址,得到函数在内核空间中的真实地址

这种方法避免了直接读取内核内存,同时通过哈希隐藏了敏感的函数名和模块名。

EDR特征检测与清除技术

EDR特征检测

IsEDRHash函数

  • 基本原理:通过对驱动程序名称(DriverName)的哈希值或名称前缀匹配来检测特定的安全防护软件驱动程序
  • 哈希值匹配:
    • 将驱动程序名称转换为唯一哈希值
    • 与内置的已知安全驱动程序的哈希列表(AVDriverHashes)比较
    • 匹配则返回TRUE
  • 字符串匹配:
    • 检查驱动程序名称是否包含某些已知字符串(PrefixKESDriver)
    • 包含则返回TRUE

模式匹配技术

FindPattern函数

  1. 在内存中按字节逐地址扫描,寻找符合指定模式的指令或数据结构
  2. 模式匹配由外部定义的验证函数(如ValidateLeaPatternValidateCallJmpPattern等)提供逻辑
  3. 适配不同的模式和用途:
    • 寻找特定的汇编指令(如LEA或CALL)
    • 定位内核中的特定回调函数或数据结构

实现细节

  1. 验证输入参数
  2. 初始化搜索状态
  3. 逐地址搜索
  4. 调用验证函数
  5. 继续搜索
  6. 释放资源

示例:匹配LEA RAX, [RIP+Offset]指令

  1. DriverMemoryOperation依次读取内存数据到buffer
  2. 调用ValidateLeaRipPattern检查
  3. 匹配则返回地址

CalculateOffset函数

  • 功能:计算内存中的偏移量
  • 实现:
    • 从指定内存地址的某一偏移位置开始逐字节读取数据
    • 按照字节顺序将每个字节拼接成一个64位偏移量
    • 如果高位包含符号位,则进行符号扩展
    • 返回最终计算的偏移量

回调清除技术

CallbackManager.c

实现Windows内核回调的检测、管理和清理功能,主要处理三种回调:

  1. 进程创建回调(PsSetCreateProcessNotifyRoutine_CH):监控进程创建和终止
  2. 线程创建回调(PsSetCreateThreadNotifyRoutine_CH):监控线程创建和终止
  3. 镜像加载回调(PsSetLoadImageNotifyRoutine_CH):监控DLL和驱动加载

关键函数

  1. ProcessDriverCallback

    • 检查特定驱动回调函数是否与EDR相关,若是则清除回调
    • 计算内存地址,读取回调信息
    • 验证驱动程序名称,判断是否为已知的EDR驱动
    • 通过内核内存写入操作清除回调
  2. GetPspNotifyRoutineArrayH

    • 定位PspNotifyRoutineArray地址(存储内核回调函数的数组)
    • 根据Windows版本判断如何解析地址
    • 使用模式匹配和指令偏移提取目标地址
    • 兼容不同版本的Windows
  3. PrintAndClearCallBack

    • 扫描回调数组中的每个条目,打印相关信息,并清除EDR回调
    • 遍历回调数组,按索引逐一读取回调地址
    • 通过位操作解析回调函数的实际地址
    • 验证驱动程序名称,若是EDR驱动则清除其回调条目
  4. ClearThreeCallBack

    • 批量处理与进程、线程和模块加载相关的三种回调
    • 使用结构体加循环的方法进行清除回调函数
    • 获取各回调的数组地址并逐一清理

FilterCallBackManager.c

RemoveInstanceCallback函数

  1. 遍历和处理FLT_FILTER对应的所有FLT_INSTANCE实例,清除其关联的回调节点
  2. 核心逻辑:
    • 初始化偏移量(根据操作系统版本动态确定关键偏移量)
    • 遍历实例列表,访问每个实例并处理其内容
    • 处理回调节点数组,清除存在的回调节点
    • 处理完所有节点后遍历到下一个实例

ClearMiniFilterCallBack函数

  1. 枚举系统中所有MiniFilter驱动,进行回调清理
  2. 核心逻辑:
    • 定位全局MiniFilter数据结构
    • 处理MiniFilter驱动列表,清除EDR驱动的回调实例
    • 处理卷(Volume)回调,清除EDR相关的节点
    • 输出处理结果

ObjectCallBackManager.c

清除对象回调的核心逻辑

  1. 获取回调列表的头指针
    • 根据对象类型(PsProcessTypePsThreadType),找到回调链表头地址
    • 使用特定偏移量(取决于操作系统版本)解析内核结构
  2. 遍历回调链表
    • 读取每个节点的PreOperationPostOperation回调函数地址
  3. 判断是否为EDR回调
    • 检查回调函数所属的驱动程序名称是否属于已知的EDR驱动
  4. 清除EDR回调
    • 清空对应节点的回调地址(写入0)

关键函数

  1. ClearObRegisterCallbacks
    • 入口函数,负责调用其他函数枚举和清理回调
    • 定义两种对象类型(进程和线程),逐个处理
  2. GetPsProcessAndProcessTypeAddr
    • 根据对象类型获取回调链表头的地址
    • 通过模式搜索定位地址指针
  3. RemoveObRegisterCallbacks
    • 清除指定类型对象的回调列表中与EDR相关的回调
    • 遍历链表节点,统计回调节点数量并清理
  4. ProcessCallback
    • 处理每个回调函数地址,检查是否属于EDR驱动并清理

RegistryCallbackManager.c

主要功能

  • 清理与CmRegisterCallback注册的注册表回调函数
  • 枚举和打印当前已注册的驱动名称
  • 通过修改回调链表的头节点地址绕过Windows内核的PatchGuard保护机制

实现步骤

  1. 获取回调链表地址
    • 使用CmUnRegisterCallback函数地址定位链表头
    • 通过模式匹配和偏移量计算得到链表头
  2. 遍历回调链表
    • 读取每个节点,提取注册的回调函数地址
    • 获取回调函数所属驱动名称并打印
  3. 清空回调链表
    • 修改链表的头节点地址,使所有回调失效
    • 仅修改头节点以避免触发PatchGuard检测

常用的规避EDR技巧

IAT Camouflage技术

IatCamouflage函数的主要功能是通过混淆手段隐藏真实的意图或行为:

  1. 动态内存分配和随机化

    • 使用伪随机的种子和时间戳生成随机大小的内存缓冲区
    • 在缓冲区中存储伪随机值,增加调试和分析的复杂度
  2. 引入不可预测性

    • 使用__rdtsc()(获取CPU时间戳计数器)和随机化的哈希值生成不可预测的执行路径
  3. 混淆IAT使用痕迹

    • 调用一系列Windows API函数(如GetTickCount64GetSystemInfo等)
    • 引入大量看似无关的操作干扰逆向分析工具
  4. 隐藏执行逻辑

    • 将随机生成的哈希值与动态计算值(基于时间戳和系统信息)混合
    • 干扰静态和动态分析
  5. 内存清理

    • 在执行完伪代码逻辑后释放分配的随机缓冲区
    • 减少内存残留信息

操作演示

  1. 开启Windows测试模式,然后重启系统
  2. 创建驱动服务,开启驱动服务

项目背景

这个项目很大程度上受到RealBlindingEDR的启发。从简单的小驱动写起,然后再进行驱动函数调用。

内核攻防:致盲EDR技术详解 需求背景 在APT攻击中,使用驱动致盲EDR(Endpoint Detection and Response)的意义在于通过加载恶意或修改的驱动程序,直接操作内核数据结构,禁用或清除EDR的回调和监控机制,从而绕过安全检测。这种方法能够隐藏攻击行为、规避日志记录和实时响应,确保攻击活动在受害系统中悄无声息地进行,提高持久性和隐蔽性。 驱动解析 内存读写驱动实现 项目代码: https://github.com/k3lpi3b4nsh33/rwdriver devctrl_RwMemory 函数是一个典型的驱动层代码,用于设备驱动程序的I/O控制请求处理,特别是内存读写操作相关的情况。 功能描述 : 在内核模式下执行内存读写操作 用于在同一进程内复制内存数据 参数说明 : DeviceObject : 设备对象指针(未使用) irp : I/O请求包指针 irpSp : IRP栈位置指针 主要流程 : 获取并验证系统缓冲区 验证内存操作参数(源地址、目标地址、大小) 执行内存复制操作 完成IRP请求 返回值 : 成功: STATUS_ SUCCESS 失败: STATUS_ INVALID_ PARAMETER或STATUS_ UNSUCCESSFUL 使用示例 : 通过设备I/O控制代码调用此函数,传入 MEMORY_OPERATION 结构体,包含源地址、目标地址和复制大小。 可能的应用场景 内存读写工具 : 用户模式程序通过IOCTL调用该函数,向驱动请求读写当前进程的特定内存区域 用于开发调试工具或与进程交互的应用程序 内核态内存编辑 : 函数内部调用 MmCopyVirtualMemory ,直接操作进程的虚拟内存空间 用途包括调试器工具、数据注入(如游戏外挂)、内存复制操作的驱动辅助实现 反病毒软件或内存分析工具 : 用于安全领域,如反病毒引擎或内存分析工具,从特定进程中提取敏感信息 驱动利用Exe解析 项目代码: https://github.com/k3lpi3b4nsh33/BlindEdr 核心原理 所有操作的原理是:通过控制驱动的内存读写函数( DriverMemoryOperation ),修改相关EDR内核数据结构的地址。 在 Common.c 中, DriverMemoryOperation 函数是与驱动交互的关键函数。它传入一个 PMemOp 结构体,在驱动中使用 MmCopyVirtualMemory 进行操作。从R3的角度来说,相当于使用了一个处于驱动层的 Memcpy 函数。 API哈希动态获取 实现的主要目的和意义 : 反检测和反调试 避免在程序中直接存储API函数名称字符串 规避静态分析和特征码检测 增加逆向分析的难度 动态解析 使用哈希值代替明文字符串 运行时动态计算和匹配API函数 绕过导入表(IAT)监控 实现方法 : 编写 CityHash 函数,使用三个不同的哈希值进行计算( FIRST_HASH 、 SECOND_HASH 、 THIRD_HASH ) API函数解析流程( GetProcAddressH ): 遍历模块导出表 计算每个导出函数名的哈希值 与预定义哈希值比对 处理转发函数情况 返回匹配函数地址 模块句柄的获取( GetModuleHandleH ): 支持内核模块和用户模块的处理 使用 NtQuerySystemInformation 获取系统模块信息 大小写不敏感的哈希匹配 EDR相关模块分析 FLTMGR.SYS的作用 : 文件操作监控:EDR通过Windows文件系统过滤器框架拦截文件的创建、读取、修改和删除等操作 行为记录:记录终端上的文件活动日志,为威胁分析和回溯提供数据支持 实时拦截:在文件操作发生前拦截威胁操作 NTOSKRNL.exe的作用 : 作为系统核心,提供基本的内核服务 所有内核模式驱动程序都依赖其提供的接口 用户程序通过系统调用访问其功能(如文件读写、网络通信) 内核函数地址解析机制 获取目标内核模块的实际基地址 通过哈希匹配从 kernel32.dll 中获取 LoadLibraryExA / LoadLibraryA 函数 对于 FLTMGR.SYS ,使用 LoadLibraryExA 并指定 DONT_RESOLVE_DLL_REFERENCES 标志加载驱动文件作为模板 对于 ntoskrnl.exe ,使用普通的 LoadLibraryA 加载 计算目标函数在用户态加载的模块中的偏移,加上实际的内核模块基地址,得到函数在内核空间中的真实地址 这种方法避免了直接读取内核内存,同时通过哈希隐藏了敏感的函数名和模块名。 EDR特征检测与清除技术 EDR特征检测 IsEDRHash函数 : 基本原理:通过对驱动程序名称(DriverName)的哈希值或名称前缀匹配来检测特定的安全防护软件驱动程序 哈希值匹配: 将驱动程序名称转换为唯一哈希值 与内置的已知安全驱动程序的哈希列表( AVDriverHashes )比较 匹配则返回TRUE 字符串匹配: 检查驱动程序名称是否包含某些已知字符串( PrefixKESDriver ) 包含则返回TRUE 模式匹配技术 FindPattern函数 : 在内存中按字节逐地址扫描,寻找符合指定模式的指令或数据结构 模式匹配由外部定义的验证函数(如 ValidateLeaPattern 、 ValidateCallJmpPattern 等)提供逻辑 适配不同的模式和用途: 寻找特定的汇编指令(如LEA或CALL) 定位内核中的特定回调函数或数据结构 实现细节 : 验证输入参数 初始化搜索状态 逐地址搜索 调用验证函数 继续搜索 释放资源 示例:匹配LEA RAX, [ RIP+Offset]指令 : DriverMemoryOperation 依次读取内存数据到buffer 调用 ValidateLeaRipPattern 检查 匹配则返回地址 CalculateOffset函数 : 功能:计算内存中的偏移量 实现: 从指定内存地址的某一偏移位置开始逐字节读取数据 按照字节顺序将每个字节拼接成一个64位偏移量 如果高位包含符号位,则进行符号扩展 返回最终计算的偏移量 回调清除技术 CallbackManager.c 实现Windows内核回调的检测、管理和清理功能,主要处理三种回调: 进程创建回调( PsSetCreateProcessNotifyRoutine_CH ):监控进程创建和终止 线程创建回调( PsSetCreateThreadNotifyRoutine_CH ):监控线程创建和终止 镜像加载回调( PsSetLoadImageNotifyRoutine_CH ):监控DLL和驱动加载 关键函数 : ProcessDriverCallback : 检查特定驱动回调函数是否与EDR相关,若是则清除回调 计算内存地址,读取回调信息 验证驱动程序名称,判断是否为已知的EDR驱动 通过内核内存写入操作清除回调 GetPspNotifyRoutineArrayH : 定位 PspNotifyRoutineArray 地址(存储内核回调函数的数组) 根据Windows版本判断如何解析地址 使用模式匹配和指令偏移提取目标地址 兼容不同版本的Windows PrintAndClearCallBack : 扫描回调数组中的每个条目,打印相关信息,并清除EDR回调 遍历回调数组,按索引逐一读取回调地址 通过位操作解析回调函数的实际地址 验证驱动程序名称,若是EDR驱动则清除其回调条目 ClearThreeCallBack : 批量处理与进程、线程和模块加载相关的三种回调 使用结构体加循环的方法进行清除回调函数 获取各回调的数组地址并逐一清理 FilterCallBackManager.c RemoveInstanceCallback函数 : 遍历和处理 FLT_FILTER 对应的所有 FLT_INSTANCE 实例,清除其关联的回调节点 核心逻辑: 初始化偏移量(根据操作系统版本动态确定关键偏移量) 遍历实例列表,访问每个实例并处理其内容 处理回调节点数组,清除存在的回调节点 处理完所有节点后遍历到下一个实例 ClearMiniFilterCallBack函数 : 枚举系统中所有MiniFilter驱动,进行回调清理 核心逻辑: 定位全局MiniFilter数据结构 处理MiniFilter驱动列表,清除EDR驱动的回调实例 处理卷(Volume)回调,清除EDR相关的节点 输出处理结果 ObjectCallBackManager.c 清除对象回调的核心逻辑 : 获取回调列表的头指针 根据对象类型( PsProcessType 或 PsThreadType ),找到回调链表头地址 使用特定偏移量(取决于操作系统版本)解析内核结构 遍历回调链表 读取每个节点的 PreOperation 和 PostOperation 回调函数地址 判断是否为EDR回调 检查回调函数所属的驱动程序名称是否属于已知的EDR驱动 清除EDR回调 清空对应节点的回调地址(写入0) 关键函数 : ClearObRegisterCallbacks : 入口函数,负责调用其他函数枚举和清理回调 定义两种对象类型(进程和线程),逐个处理 GetPsProcessAndProcessTypeAddr : 根据对象类型获取回调链表头的地址 通过模式搜索定位地址指针 RemoveObRegisterCallbacks : 清除指定类型对象的回调列表中与EDR相关的回调 遍历链表节点,统计回调节点数量并清理 ProcessCallback : 处理每个回调函数地址,检查是否属于EDR驱动并清理 RegistryCallbackManager.c 主要功能 : 清理与 CmRegisterCallback 注册的注册表回调函数 枚举和打印当前已注册的驱动名称 通过修改回调链表的头节点地址绕过Windows内核的PatchGuard保护机制 实现步骤 : 获取回调链表地址 使用 CmUnRegisterCallback 函数地址定位链表头 通过模式匹配和偏移量计算得到链表头 遍历回调链表 读取每个节点,提取注册的回调函数地址 获取回调函数所属驱动名称并打印 清空回调链表 修改链表的头节点地址,使所有回调失效 仅修改头节点以避免触发PatchGuard检测 常用的规避EDR技巧 IAT Camouflage技术 IatCamouflage 函数的主要功能是通过混淆手段隐藏真实的意图或行为: 动态内存分配和随机化 : 使用伪随机的种子和时间戳生成随机大小的内存缓冲区 在缓冲区中存储伪随机值,增加调试和分析的复杂度 引入不可预测性 : 使用 __rdtsc() (获取CPU时间戳计数器)和随机化的哈希值生成不可预测的执行路径 混淆IAT使用痕迹 : 调用一系列Windows API函数(如 GetTickCount64 、 GetSystemInfo 等) 引入大量看似无关的操作干扰逆向分析工具 隐藏执行逻辑 : 将随机生成的哈希值与动态计算值(基于时间戳和系统信息)混合 干扰静态和动态分析 内存清理 : 在执行完伪代码逻辑后释放分配的随机缓冲区 减少内存残留信息 操作演示 开启Windows测试模式,然后重启系统 创建驱动服务,开启驱动服务 项目背景 这个项目很大程度上受到 RealBlindingEDR 的启发。从简单的小驱动写起,然后再进行驱动函数调用。