一、前言
应不少读者的要求,我们新开了一个安全运营板块。这个板块主要用来记录我们在日常安全运营项目中遇到的典型案例,包括排查思路、处置过程和事后复盘。之前银狐远控那篇文章发出去后,很多师傅私信问我们,安全运营项目里除了远控木马,还会遇到哪些棘手的事情。说实话,EDR 告警和病毒查杀日志看起来只是屏幕上一行红色的提示,但背后可能藏着一整套从用户态到内核态的完整攻击链条。
接前文复盘,那次的突破口是深信服 EDR 的外联告警。而今天要分享的,是我们近期在同一个安全运营项目中遇到的另一个案例。火绒弹出查杀提示,对象是一个在 C 盘根目录下的 setup.exe。起初我们以为这只是一次普通的木马落地,但顺着查杀日志往下挖,发现这个样本不仅会通过 U 盘扩散,还会在内核层伪装成显卡驱动,甚至对安全软件做进程拦截。它的完整攻击链覆盖了用户态传播、内核态驻留和系统调用篡改,清理起来比一般的木马要麻烦得多。
二、事件缘起与取证
2026 年 6 月初,工程师在巡检火绒终端管理后台时,发现一台终端上报了病毒查杀记录。被拦截的文件路径是 C:\setup.exe,文件名看起来像是正常的安装程序,但位置直接落在系统盘根目录,这本身就很不寻常。正常的软件安装包不会孤零零在 C 盘根目录,更不会在没有用户主动下载的情况下凭空出现。
火绒终端查杀日志,目标文件为 C:\setup.exe,直接落在系统盘根目录,文件名具有伪装性
我们第一时间登录该终端,发现这个文件已经被火绒隔离,但现场没有其他人记得运行过这个程序。询问使用者后得知,该终端近期接过同事的 U 盘拷贝过文件。这个细节立刻引起了我们的警觉:如果是通过 U 盘投递,那意味着同一批 U 盘可能已经在内网多台终端上插过,感染面可能不止这一台。
顺着这个思路,我们往前排查了这台终端的火绒历史记录,发现查杀时间集中在近期,且路径特征高度一致。这提示我们该样本可能不是通过网络下载落地,而是依靠物理介质传播。在内网环境中,U 盘、移动硬盘往往是被忽视的攻击面,很多终端的 USB 端口并没有做严格的管控,同事之间互相借用 U 盘拷贝资料也是常态。
三、样本分层拆解
把样本从隔离区提取出来后,我们开始做静态分析。这个样本的体积只有 40 KB 左右(40960 bytes),但结构非常紧凑,不是普通的单文件木马,而是一个多阶段的自解包传播器。它的设计思路很明确:外层越轻量,越容易通过 U 盘快速复制;内层越隐蔽,越能在目标终端上长期驻留。
3.1 双层异或壳与第一层释放器
样本入口首先恢复一段被异或隐藏的壳代码。还原后的入口会定位自身镜像基址,将 .text 节区中 RVA 0x1028 到 0x1827 这段 0x800 字节的数据,按 0x1E 逐字节异或解密,然后转入第一层释放逻辑。
第一层释放器初始化所需 API 后,读取自身 PE 的第 16 个数据目录项。这里有个细节:它没有用标准的资源节,而是把压缩数据藏在了自定义的数据目录项里,这对依赖自动化解密资源的分析工具来说是个小干扰。释放器通过一套自定义的 LZ 风格回溯复制算法解压数据,解压输出被写入临时目录,文件名由字符串 Zjgligldm,bjj 逐字节加 2 还原,得到 \linkinfo.dll。写盘完成后,释放器调用 LoadLibraryA 加载该模块,并调用导出序号 101 进入二阶段逻辑。
从 setup.exe 启动到最终 linkinfo.dll 执行的完整多阶段解包链,包含双层异或壳解密与自定义目录项解压
第一层释放器从自身 PE 第 16 个数据目录项提取位流压缩数据,经自定义 LZ 风格算法解压后写出 linkinfo.dll
3.2 二阶段模块 linkinfo.dll
linkinfo.dll 被加载后,调用导出序号 101 进入主逻辑。它首先创建两组互斥体:PNP#DMUTEX#1#DL5 和 PNP#NETMUTEX#1#DL5,用于防止重复实例运行,同时区分本地传播路径与网络更新路径。
随后它创建一个隐藏的窗口类 lME,并调用 RegisterDeviceNotificationA 注册设备通知。这个窗口不是给用户看的,而是用来接收系统消息,特别是 0x219(设备到达)消息,从而感知 U 盘的插入。同时,它还会对系统目录下 \drivers\ 建立变更通知句柄,监控驱动层面的动静。
二阶段模块通过隐藏窗口 lME 监听设备变更消息,触发 U 盘投放与本地目录遍历感染,并建立驱动目录监控
四、传播与驻留机制
4.1 U 盘投放
当使用者把 U 盘插入已感染的终端,二阶段模块收到 0x219 消息后,会提取盘符,判断是否为可移动磁盘。确认后,它在 U 盘根目录下写入两个文件:
boot.exe:样本的副本
Autorun.inf:自动运行配置文件,由编码字符串 ^Cwvqtwp0kph 逐字节减 2 还原得到
这两个文件的属性被设置为 7(只读、隐藏、系统),在 Windows 默认设置下用户看不到,也删不掉。当这张 U 盘插到其他终端时,如果系统开启了自动运行,boot.exe 就会直接执行,完成跨主机传播。
U 盘插入后,样本在根目录投放 boot.exe 与 Autorun.inf,并设置隐藏、系统、只读属性以躲避人工排查
4.2 本地目录遍历感染
除了 U 盘,它还会感染本地磁盘上的可执行文件。遍历模块通过 FindFirstFileA / FindNextFileA 递归扫描,深度不超过 5 层,只处理 .exe 文件,同时跳过以下路径:
\QQ
\WINNT\
\WINDOWS\
LOCAL SETTINGS\TEMP\
此外,它内部维护了一份 44 项的排除名单,避开一些系统文件和常见软件。每感染 3 个文件后暂停 100 ms,降低行为密度,避免触发高敏感度的行为检测。这种设计说明作者对终端安全软件的查杀策略有一定了解,知道如何通过节奏控制来规避特征检测。
4.3 用户态驻留与注入
为了长期驻留,linkinfo.dll 会启用 SeDebugPrivilege,定位 explorer.exe 进程,将自身模块路径写入目标地址空间,然后遍历线程,通过 QueueUserAPC(LoadLibraryA) 把 DLL 注入到 Explorer 中。这样一来,即使当前进程被结束,explorer.exe 作为系统核心进程会持续承载恶意代码,实现无文件落地的持久化效果。
五、内核层的对抗与伪装
这个样本最麻烦的地方,不是 U 盘传播,而是它在内核层建立了一套完整的防御和对抗机制。如果只清理了用户态的文件,没有处理内核驱动,几个小时后样本就会像野草一样重新长出来。
5.1 驱动落地与服务伪装
二阶段模块会从内置的位流压缩块中解压出一个驱动(此驱动程序未经数字签名,由于 Windows XP 默认不强制驱动签名校验,因此可正常加载运行),还原后的服务名为 nvmini,落地路径为 system32\drivers\nvmini.sys。它先尝试通过 CreateServiceA / OpenServiceA / StartServiceA 正常启动服务,如果失败,则直接调用 ZwLoadDriver 装载。
这个驱动的 PE 时间戳是 2007 年,伪装成 "NVIDIA Compatible Windows Miniport Driver",属于典型的旧驱动冒用。驱动安装后,其系统线程 StartRoutine 会持续监控 HKLM\SYSTEM\CurrentControlSet\Services\nvmini,一旦发现服务项被删除或篡改,立即通过 ZwSetValueKey 重写 ErrorControl、Start、Type、Tag、Group、DisplayName、ImagePath 等关键值,然后调用 ZwNotifyChangeKey 阻塞等待下一次变化。这意味着,你前脚在注册表里删掉它,它后脚就自动重建。
驱动通过服务管理器或 ZwLoadDriver 装载,并持续监控注册表实现自恢复,伪装成 NVIDIA 显卡驱动以躲避人工排查
5.2 驱动回调与用户态协同
驱动入口会创建三条协同通道:
- 设备对象:
\Device\DL5CProc
- 用户态访问路径:
\DosDevices\DL5CProc
- 同步事件:
\BaseNamedObjects\DL5CEvent
随后注册 PsSetCreateProcessNotifyRoutine 与 PsSetLoadImageNotifyRoutine。当有新进程创建时,驱动把 PID 写入全局变量,并触发 DL5CEvent。用户态的 linkinfo.dll 则打开 \\.\DL5CProc 和 DL5CEvent,等待事件到来后通过 DeviceIoControl(..., 0x25270860, ...) 取回 PID。
拿到 PID 后,它不会盲目注入,而是先对新进程做筛选。筛选逻辑结合主模块名、完整路径和内存中的 34 项目标表判断是否命中规则。如果命中,则执行 OpenProcess → TerminateProcess → DeleteFileA,直接结束并删除目标文件。这条链本质上是一个针对特定安全软件和监控工具的拦截清除通道,解释了为什么有些终端上装了其他安全工具后会出现异常退出或文件消失的情况。
5.3 SSDT 钩子与模块入口短路
驱动的镜像加载回调还会对特定模块做入口点篡改。当以下模块被加载时:
\WININFO.RXK
\RICHDLL.DLL
\WINDHCP.DLL
\DLLHOSTS.DLL
\NOTEPAD.DLL
\RPCS.DLL
\RDIHOST.DLL
\RDFHOST.DLL
\RDSHOST.DLL
\LGSYM.DLL
\RUND11.DLL
\MDDDSCCRT.DLL
\WSVBS.DLL
\CMDBCS.DLL
\UPXDHND.DLL
驱动会附加到目标进程,把入口点前 5 字节改写为 33 C0 C2 0C 00(xor eax, eax; retn 0Ch),直接短路返回,让模块无法执行正常初始化代码。这种手法会让依赖这些模块的安全工具或分析插件直接失效。
同时,驱动还对多个系统调用做 SSDT 钩子:
| 被钩系统调用 |
作用 |
| ZwLoadDriver |
监控并拦截驱动加载 |
| ZwEnumerateKey |
枚举到 nvmini 时调整索引,隐藏服务项 |
| ZwClose |
句柄操作监控 |
| ZwQueryDirectoryFile |
目录查询过滤 |
| ZwSaveKey |
注册表保存拦截 |
| ZwDeleteKey |
对包含驱动服务名的对象返回拒绝状态 |
| ZwDeleteValueKey |
对包含驱动服务名的对象返回拒绝状态 |
这就解释了为什么有些工具查杀后,服务项看起来还在,或者根本看不到这个服务:内核层的查询结果已经被篡改了。
5.4 更新与配置链
样本在 %WINDIR%\AppPatch\AcLue.dll 路径下加载组件并解析导出函数 DLPInit、DLPUpdate、DLPTerminate、DLPVersion。其隐藏窗口过程还会检查同路径下 AcLue.dll.new 是否存在;若存在且校验通过,则释放旧模块、复制新文件覆盖原文件并重新装载。这说明样本具备组件热更新能力。
同时,样本内置 URL http://top.cn3721.org/c.asp,并围绕该地址构造更新请求,模板为 %s?action=update&version=%u。虽然该域名目前可能已失效,但这一机制说明样本在设计之初就预留了远程控制通道。
六、清除与加固
基于以上分析,我们制定了以下清除方案,并在客户现场完成了闭环处置。
- 立即隔离与断链 隔离所有接入过可疑 U 盘的终端,禁用移动存储设备的自动运行功能,从源头切断 U 盘传播途径。
- 用户态清理 全网排查 C 盘根目录及 U 盘根目录是否存在
setup.exe、boot.exe、Autorun.inf。清理 %WINDIR%\AppPatch\AcLue.dll 及 .new 文件,检查异常时间戳和非系统签名。
- 注册表清理 清理注册表
HKLM\Software\Intel 下的异常键值(如 Version),以及服务项 HKLM\SYSTEM\CurrentControlSet\Services\nvmini。注意,由于驱动具备注册表自恢复能力,清理前必须先进入安全模式或先卸载驱动,否则清理动作会被立即覆盖。
- 内核态专项排查 对
system32\drivers\ 目录做专项排查,核验 nvmini.sys、IsDrv118.sys、RsBoot.sys 是否存在,检查文件签名和哈希。使用内核调试工具或可信的 ARK(Anti-Rootkit)工具检查 SSDT 关键系统调用是否被篡改,以及 explorer.exe 中是否存在线程 APC 注入痕迹。
- 网络侧封禁 封禁
top.cn3721.org/c.asp,并回溯历史访问日志,排查是否存在其他设备的通信记录。
- 安全意识培训 开展全员安全意识培训,强调 U 盘使用规范,禁止随意插入来历不明的移动存储设备。对于必须使用的 U 盘,建议先通过终端安全软件扫描后再打开。
七、总结与防御建议
这个样本给我们的最大教训是:U 盘蠕虫并没有因为 Autorun.inf 被禁用而消失,它只是升级了。现在的 U 盘传播型恶意程序,不再满足于简单的文件复制,而是会结合内核驱动、注册表守护、进程拦截和 SSDT 钩子,在系统里构建一个多层次的驻留网络。如果只清理了用户态的文件,没有处理内核驱动,几小时后它又会重新出现,这就是很多师傅说的"杀不干净"的根因。
对于企业安全运营来说,有几点建议值得重视:
第一,终端防护不能只看用户态。 火绒在用户态拦截了 setup.exe,但如果样本已经释放了驱动,驱动的自恢复和进程拦截逻辑会在内核层持续对抗。所以终端安全产品必须具备内核态的异常行为检测能力,特别是对新增驱动服务、SSDT 变更、注册表守护线程的监控。
第二,U 盘管理不能仅靠自觉。 很多内网感染的起因就是同事之间借 U 盘拷贝文件。建议通过组策略或终端管理软件,统一禁用移动存储设备的自动运行,并对插入的 U 盘进行强制扫描,甚至考虑在关键岗位禁用 USB 存储端口。
第三,查杀后的验证比查杀本身更重要。 这个样本的驱动具备注册表自恢复能力,如果你只删除了文件、清除了注册表,但没有处理驱动和内核钩子,它很快就会重新建立驻留。所以应急处置必须包含"查杀-验证-复查"的闭环,验证环节要重点检查注册表、驱动目录和系统进程注入痕迹,必要时使用离线 WinPE 环境进行深度清理。
第四,安全运营交接期要重点关注历史告警。 这个样本和之前银狐的案例一样,都暴露出一个共同问题:前任服务商在查杀后没有做根因分析,导致样本虽然被拦截了,但传播机制和驻留组件仍然潜伏在环境中。新团队入驻后,一定要把过去 180 天的告警全部回溯一遍,找出那些"被杀了但没落盘"的断点事件。
附录:核心 IOC 汇总
文件 IOC
| 类型 |
值 |
说明 |
| 投递文件 |
setup.exe |
原始投递文件,40 KB,C 盘根目录常见落点 |
| 二阶段伪装名 |
linkinfo.dll |
由第一层释放器解压生成,调用导出序号 101 |
| U 盘落地文件 |
boot.exe |
U 盘传播副本 |
| U 盘落地文件 |
Autorun.inf |
自动运行配置,属性设为 7(只读/隐藏/系统) |
| 组件路径 |
%WINDIR%\AppPatch\AcLue.dll |
更新组件加载路径 |
| 更新临时文件 |
%WINDIR%\AppPatch\AcLue.dll.new |
热更新临时文件 |
| 驱动文件 |
%SystemRoot%\system32\drivers\nvmini.sys |
伪装成 NVIDIA 驱动的内核模块 |
| 相关驱动 |
%SystemRoot%\system32\drivers\IsDrv118.sys |
内核侧操作对象 |
| 相关驱动 |
%SystemRoot%\system32\drivers\RsBoot.sys |
文件映射修补对象 |
网络 IOC
主机 IOC
| 类型 |
值 |
说明 |
| 互斥体 |
PNP#DMUTEX#1#DL5 |
防重复运行,本地传播路径 |
| 互斥体 |
PNP#NETMUTEX#1#DL5 |
防重复运行,网络更新路径 |
| 注册表路径 |
HKLM\Software\Intel\Version |
保存组件版本和运行状态 |
| 服务注册表路径 |
HKLM\SYSTEM\CurrentControlSet\Services\nvmini |
驱动服务项,具备自恢复逻辑 |
| 驱动设备 |
\.\DL5CProc |
用户态与内核态协同设备 |
| 设备对象 |
\Device\DL5CProc |
内核态设备对象 |
| 符号链接 |
\DosDevices\DL5CProc |
用户态访问路径 |
| 同步事件 |
DL5CEvent / Global\DL5CEvent |
进程创建通知事件 |
| 隐藏窗口类/标题 |
lME |
二阶段模块消息窗口 |
| 监听目录 |
%SystemRoot%\drivers\ |
驱动目录变更监控 |
行为检测点
- 监控创建隐藏窗口并注册
RegisterDeviceNotificationA 的模块。
- 监控可移动磁盘根目录下同时出现
boot.exe 与 Autorun.inf 的行为。
- 监控对
%WINDIR%\AppPatch\AcLue.dll 和 .new 文件的读写、覆盖和动态加载。
- 监控
HKLM\Software\Intel\Version 的异常创建和写入。
- 监控创建互斥体
PNP#DMUTEX#1#DL5、PNP#NETMUTEX#1#DL5。
- 监控对
top.cn3721.org/c.asp 的 HTTP 访问。
- 监控创建或启动服务
nvmini,以及对 system32\drivers\nvmini.sys、IsDrv118.sys、RsBoot.sys 的写入与映射修改。
- 监控
\.\DL5CProc 设备打开、DL5CEvent/Global\DL5CEvent 事件对象访问与 0x25270860 控制码调用。
- 监控对新建进程执行"打开进程 -> 终止进程 -> 删除落地文件"的快速串联行为。
- 监控向
explorer.exe 执行 VirtualAllocEx + WriteProcessMemory + QueueUserAPC(LoadLibraryA) 的 DLL 注入链。
- 监控内核中对
ZwEnumerateKey、ZwDeleteKey、ZwDeleteValueKey、ZwLoadDriver 的异常钩挂或返回值篡改。
本文案例由Solar应急响应团队共同完成。
全文输出:州弟学安全
参与应急排查应急及内容输出:butt3rf1y、CHQ
逆向分析:CHQ
排版优化:超级油麦