1. 恶意驱动样本概述
这个恶意驱动样本是一个典型的内核级攻击框架,它通过滥用Windows内核提供的合法回调机制实现隐蔽注入和进程保护。从逆向分析来看,该样本主要针对64位Windows系统,通过多层次的系统回调注册构建了一个完整的攻击链。
样本最显著的特点是采用"主动+被动"双重攻击模式:
- 被动模式:通过PsSetLoadImageNotifyRoutine监控系统DLL加载事件
- 主动模式:通过CreateSystemThread创建内核线程主动寻找目标进程
这种混合架构使得攻击具有更高的可靠性,即使某一种注入方式被安全软件拦截,另一种方式仍可能成功。我在分析过程中发现,该样本特别关注explorer.exe、taskmgr.exe和perfmon.exe这三个高权限进程,这显然是为了获取系统级权限并规避任务管理器的监控。
2. 核心回调机制分析
2.1 映像加载通知回调
样本通过PsSetLoadImageNotifyRoutine注册了一个NotifyRoutine回调函数,这是整个攻击链的起点。这个Windows内核API原本设计用于防病毒软件等合法用途,允许驱动在系统加载任何PE映像(DLL或EXE)时获得通知。
回调函数的伪代码逻辑如下:
void NotifyRoutine( PUNICODE_STRING FullImageName, // 加载的映像完整路径 HANDLE ProcessId, // 加载映像的进程ID PIMAGE_INFO ImageInfo // 映像信息结构体 ){ // 1. 检查进程ID有效性(排除系统关键进程) // 2. 验证当前IRQL等级为PASSIVE_LEVEL // 3. 检查映像路径是否包含\System32\或\SysWOW64\ // 4. 判断进程架构(32位/64位) // 5. 检查进程名是否为explorer.exe/taskmgr.exe/perfmon.exe // 6. 满足条件则触发注入流程 }在实际调试中,我注意到该样本特别处理了WoW64进程的情况。它会通过PsGetProcessWow64Process判断当前进程是32位还是64位环境,并只对64位进程进行注入,这可能是为了避免在32位环境中留下更多痕迹。
2.2 对象管理器回调
样本还注册了ObRegisterCallback来监控进程和线程句柄操作。这是一种高级的内核保护技术,通常被用于:
- 进程保护:防止其他进程通过PROCESS_TERMINATE权限终止恶意进程
- 反调试:阻止调试器获取PROCESS_VM_READ/WRITE权限读取或修改内存
- 早期预警:监控对特定进程的句柄操作请求
在IDA中分析对应的回调函数时,我发现它对名为"diamondage.exe"的进程进行了特殊保护,这很可能是恶意软件自身的进程名。这种保护使得常规的任务管理器或Process Explorer等工具无法终止该进程。
3. 注入技术深度解析
3.1 APC注入机制
样本采用APC(Asynchronous Procedure Call)注入技术将恶意DLL加载到目标进程。APC注入的核心原理是利用线程的APC队列异步执行加载操作,关键步骤如下:
- 通过PsLookupThreadByThreadId获取目标线程
- KeInitializeApc初始化APC对象
- KeInsertQueueApc将APC插入线程队列
以下是样本中APC注入的关键代码片段:
NTSTATUS InjectAPC(HANDLE ProcessId, PWSTR DllPath) { PKAPC pApc = ExAllocatePool(NonPagedPool, sizeof(KAPC)); PETHREAD pThread; // 获取目标线程 PsLookupThreadByThreadId(ProcessId, &pThread); // 初始化APC KeInitializeApc(pApc, pThread, OriginalApcEnvironment, (PKKERNEL_ROUTINE)KernelRoutine, NULL, NULL, KernelMode, NULL); // 插入队列 KeInsertQueueApc(pApc, NULL, NULL, 0); // 释放资源 ExFreePool(pApc); ObDereferenceObject(pThread); return STATUS_SUCCESS; }在实际测试环境中,我观察到这种注入方式有几个特点:
- 无文件落地:DLL直接从内存加载
- 难以检测:内核模式的APC注入用户态安全软件难以监控
- 高成功率:只要目标线程进入可警告状态就会执行
3.2 主动注入技术
除了APC注入外,样本还采用了更激进的主动注入方式:
- 通过CreateSystemThread创建内核线程
- 使用KeStackAttachProcess附加到目标进程地址空间
- 直接写入Shellcode到目标进程
这种技术的优势在于:
- 完全在内核态执行,绕过用户态Hook
- 不依赖特定API,对抗安全软件的API监控
- 可以注入到高权限系统进程
在IDA中可以看到,样本使用的Shellcode模板如下:
48 83 EC 28 sub rsp, 28h 48 31 C9 xor rcx, rcx 48 31 D2 xor rdx, rdx 49 B8 00 00 00 00 00 00 00 00 mov r8, 0 49 B9 00 00 00 00 00 00 00 00 mov r9, 0 48 B8 ... mov rax, <函数地址>4. 对抗分析与检测方案
4.1 恶意行为特征总结
通过对该样本的完整分析,可以总结出以下检测指标:
驱动特征:
- 注册PsSetLoadImageNotifyRoutine回调
- 使用ObRegisterCallback进行进程保护
- 创建内核线程(CreateSystemThread)
进程行为:
- 注入explorer.exe/taskmgr.exe/perfmon.exe
- 加载路径为C:\ProgramData\DiamondAge\的DLL
- 存在名为diamondage.exe的受保护进程
代码特征:
- Shellcode中包含特定的字节序列
- 使用KeStackAttachProcess附加进程
- 查找LdrLoadDll函数地址的动态解析
4.2 检测与防御方案
基于这些特征,我建议采用以下防御措施:
静态检测:
# YARA规则示例 rule MaliciousDriver { strings: $psSetLoadImage = "PsSetLoadImageNotifyRoutine" $obRegister = "ObRegisterCallbacks" $createSystemThread = "CreateSystemThread" $shellcode = {48 83 EC 28 48 31 C9 48 31 D2 49 B8} condition: any of them }动态检测方案:
监控内核回调注册:
- 使用Windows ETW记录回调注册事件
- 特别关注PsSetLoadImageNotifyRoutine和ObRegisterCallback
进程注入检测:
- 监控explorer.exe等系统进程的DLL加载
- 检查非Microsoft签名的模块
内核线程分析:
- 扫描系统中运行的内核线程
- 检查线程起始地址是否在可疑驱动范围内
5. 逆向工程实战技巧
5.1 驱动加载与调试
在分析这类恶意驱动时,我通常采用以下步骤:
使用OSR Driver Loader在测试环境中加载驱动
通过WinDbg双机调试附加到测试机
设置关键函数断点:
bp /w "@$thread->Process->ImageFileName == 'malware.sys'" nt!PsSetLoadImageNotifyRoutine bp malware!DriverEntry使用!analyze -v分析崩溃转储
重要提示:分析恶意驱动必须在隔离的虚拟机环境中进行,避免影响宿主系统。我通常会禁用虚拟机的网络连接,并定期拍摄快照以便回滚。
5.2 IDA分析技巧
对于这类复杂驱动,在IDA中分析时可以采用以下方法提高效率:
重命名关键函数:
- 根据调用关系标记回调函数
- 对APC相关函数添加前缀"APC_"
创建结构体:
// 手动定义IMAGE_INFO结构体 struct IMAGE_INFO { DWORD Characteristics; DWORD ImageBase; DWORD ImageSize; // ...其他字段 };使用IDAPython脚本自动化分析:
# 查找所有APC相关调用 from idautils import * from idaapi import * apc_funcs = ["KeInitializeApc", "KeInsertQueueApc"] for func in Functions(): for addr in XrefsTo(func): print("Found APC call at: %08X" % addr.frm)
5.3 常见问题排查
在分析过程中,我遇到过几个典型问题及解决方案:
驱动验证失败:
- 解决方法:启用测试签名模式
bcdedit /set testsigning on回调函数无法触发:
- 检查是否正确设置了通知回调
- 验证目标进程是否真的加载了DLL
Shellcode分析困难:
- 使用WinDbg的!address命令确定内存属性
- 使用u命令反汇编特定地址
通过这次分析,我深刻认识到现代恶意软件越来越倾向于滥用合法的内核机制来实现攻击。这种"living-off-the-land"技术使得检测变得更加困难,也对我们安全研究人员提出了更高要求。在后续的工作中,我会继续关注内核回调滥用方面的研究,特别是微软新引入的内核保护机制如Kernel Mode Code Integrity (KMCI)等技术的实际防护效果。