最近在整理威胁情报时,又看到不少关于 BYOVD 的讨论。标题里的“Intel 漏洞驱动硬件 ID 欺骗工具”,说白了就是一组拿漏洞驱动当跳板、在内核态做数据篡改的工具。这类工具这两年很有热度,核心手法是 BYOVD——带漏洞的合法签名驱动(Bring Your Own Vulnerable Driver)。这篇文章我会从防御者和研究者的角度,把这类工具的工作原理、攻击链路、样本分析思路和检测方法拆开讲一遍。注意,我只讲原理和防御思路,不提供可以直接利用的样本或代码细节。了解攻击原理也不是为了让你去用它,而是为了在它出现时,你能看懂它、拦住它。
这篇文章适合正在做终端安全、反作弊、EDR 规则维护的朋友,也适合对 Windows 内核机制感兴趣的二进制安全学习者。看完之后,你应该能回答几个问题:为什么合法签名的驱动反而是大威胁?硬件 ID 欺骗为什么非要跑进内核里做?系统明明有驱动签名强制、有内核隔离,为什么还是被绕过?以及,我们到底该怎么防御、怎么排查。
1. 为什么 BYOVD 总能绕过杀软:信任链上的缺口
1.1 所谓“合法漏洞驱动”到底是怎么回事
Windows 从 Vista 开始要求内核驱动必须有签名,后来 64 位系统又引入了内核模式代码签名策略,再到 Win10 之后的驱动签名强制(DSE)和内存完整性(HVCI)。这一套组合拳的初衷很简单:不让未签名的恶意代码进入内核。
但这里有一个关键问题:一旦某个驱动被正式签名,它就拥有了内核世界的“长期通行证”。哪怕后来被发现存在严重漏洞,厂商发布了新版驱动,旧的、有漏洞的驱动文件也几乎不可能撤回。Windows 的驱动生态里事实上沉淀着大量旧版本驱动,它们有合法签名、有内核读写能力、有漏洞,而且永远不会再被更新。
这就是 BYOVD 类工具存在的根本原因。攻击者不需要写恶意驱动,不需要绕过签名校验,只要找到一个已经存在于受害主机上或者可以自行放入的合法漏洞驱动,然后加载它,借它的权限做自己想做的事。整个过程里,加载的是“合法”驱动,签名是真的,厂商信息是真的,但实际干的事是恶意的。
我用一个生活化的类比来解释:一个正规小区的门禁系统,员工卡本身是物业发的,合法有效。但如果你捡到一张离职员工没注销的卡,你就能合法地刷开大门,进去干坏事。门禁系统本身没有问题,问题在于“发出去的权限收不回来”。驱动签名就是这样一张长期有效、难以吊销的门禁卡。
这类漏洞驱动里,有硬件监控类驱动、外设管理类驱动、游戏反作弊驱动、磁盘工具驱动等。它们共同的特点是:为了完成正常功能,必须提供内核级的内存读写接口、物理内存映射能力或者驱动加载能力。厂商当初写这些功能是产品需要,但一旦被攻击者反过来利用,就成了完美的内核后门。
1.2 硬件 ID 欺骗为什么非要跑到内核里做
硬件 ID 欺骗这个事,放在用户态也能做,比如常见的改注册表、换 MAC 地址、HOOK API 返回假数据。但那些做法有一个共同弱点:只是“表面欺骗”。稍微有点检测能力的软件,直接调用底层的设备接口、WMI、ACPI 或者内核对象,就能拿到真实硬件信息,一对比就穿帮。
应用层软件拿硬件信息,走的路径是这样的:应用调用系统 API,API 查询设备管理器维护的硬件信息数据库,这个数据库的数据又来自设备驱动上报的总线信息、序列号、固件信息。如果攻击者只在应用层 HOOK API,那查询链路一旦深一层,伪造就失效了。
所以,讲究一点的硬件 ID 欺骗工具,会把操作下沉到内核态。手段无非几类:直接挂钩设备驱动的分发例程,篡改驱动返回的序列号缓冲;修改系统维护的设备信息对象;挂钩 Query 类内核函数,让所有上层查询路径都能拿到统一伪造的返回值。这样改完之后,不管用户态用什么姿势查硬件ID,看到的都是同一份伪造数据。
在内核态做身份层篡改的真正意图还不止绕检测。它更大的价值在于让“系统级软件”也信了。比如某些授权软件的加密逻辑绑定硬盘序列号,如果只在应用层改返回值,软件内部再交叉验证一下就露馅;但内核层改完,整个系统看到的序列号就是同一个假值,交叉验证也是通过假值对比假值,相当于整条链路都被污染了。
这就是为什么这类工具要费这么大力气做内核内存修改。它要的不是骗过某一个软件,而是骗过整个系统内所有基于硬件ID做判断的机制。
2. 攻击链拆解:从驱动投递到内核内存修改
2.1 一次完整攻击链的四个环节
分析这类工具的攻击链,我习惯把它拆成四个阶段:投递、加载、通信、篡改。下面逐段拆。
投递阶段,攻击者需要让漏洞驱动文件出现在目标机器上。常见方式是把驱动当成某个破解软件、游戏外挂、激活工具的附加载荷发出去。用户主动运行“激活工具”,驱动文件被释放到磁盘,这一步通常不会触发杀毒警报,因为驱动文件本身是正规厂商的原版文件,哈希是白的,签名是真的。
加载阶段,攻击者通过服务创建、驱动加载接口把驱动文件加载进内核。上有策略,下有对策。微软做了各种限制,但攻击者可以利用系统自带的一些加载机制、已经存在的易受攻击加载器,或者干脆利用测试签名模式等手段完成加载。最理想情况是服务创建成功、驱动正常启动,整个过程看起来就是一个普通驱动装载。EDR 如果没对驱动文件哈希做黑名单,这一步基本是隐身状态。
通信阶段,用户态的控制程序通过设备控制接口与驱动建立连接。漏洞驱动为了正常功能,必然暴露一套 IOCTL 接口。攻击者分析这套接口后,挑出读写内存、映射物理内存、修改 MSR 之类的功能,封装成自己控制程序的调用原语。这个阶段是攻击链里最容易被检测的一环,因为正常的用户态软件不会频繁打开内核驱动设备并发送控制码。
篡改阶段,控制程序利用驱动接口读写内核内存、修改关键结构、挂钩特定路径,最终实现硬件 ID 查询结果的统一伪造。这个阶段行为最重,但隐蔽性也最强,因为所有读写都是借助合法驱动的代码路径完成的,在内核里看到的操作来源是一个签了名的正规驱动。
2.2 驱动加载之后,内存修改动了哪些数据
这里需要点出“内存修改”的具体对象。很多人一听到内核内存修改就以为是要写系统内核的关键数据结构,其实这类工具最常见的目标是设备对象相关的数据缓冲。
以硬件 ID 查询逻辑为例。上层应用调用接口获取硬盘序列号时,内核里的存储驱动接收到查询请求,从设备固件和自身维护的数据结构里拼装序列号,然后通过 IOCTL 返回给上层。如果攻击者在驱动加载后,把存储设备对应的某个设备扩展结构里的序列号缓冲区直接改写,那么后续所有查询请求都会从缓冲区里读到这份伪造数据。更彻底的做法是直接挂钩设备对象的调度函数:在分发例程的入口保存原函数指针,设置新函数指针,在新函数里先调用原函数,再篡改返回缓冲。
这两种手段都不需要碰系统内核的公共结构,也不会引发数据执行保护异常。它们操作的是设备驱动私有的数据结构,逻辑上仍然是设备驱动自己在“正常工作”。这也是这类行为难以被传统安全产品捕捉的原因——内核里并没有出现恶意代码,只是数据被改成了攻击者想要的值。
如果工具还要做更深的“欺骗”,还可能涉及对查询请求的分流。比如某些硬件校验逻辑会先查固件版本再查序列号,攻击者可以同时篡改多个返回字段,确保校验链路的每一步拿到都是伪造数据。
2.3 规避检测:攻击者如何掩盖自身行为
既然要做防御,就得知道对手怎么藏。结合我研究过的样本,这类工具规避检测的思路大致可以归纳为三点。
第一是躲哈希黑名单。工具内置的驱动文件是正规厂商的旧版驱动,哈希值不在任何公开黑名单里,甚至在微软的易受攻击驱动清单发布之前,这类驱动的哈希根本不会被标记。
第二是躲行为检测。传统终端产品对内核行为的监控粒度有限。一个驱动被加载后,它是否发送了控制码、控制码是否指向了可疑的内核操作,这些行为很难在用户态全量关联分析。而内核态的监控又要考虑稳定性和性能,不可能对所有驱动调用做深度解析。于是攻击者利用“合法驱动 + 合法接口”的模式,成功混入正常驱动行为流。
第三是躲人工分析。如果安全分析师拿到一个驱动文件,发现它签名完整、厂商正规,第一反应往往不会把它当恶意样本。只有深入逆向它的 IOCTL 接口,或者对照已知漏洞驱动列表,才能确认它具备被滥用的能力。而这个“确认”过程需要专业能力加时间投入,在真实攻防里是很大的成本。
3. 研究视角下的样本分析流程
3.1 静态分析阶段:先别急着双击
拿到疑似 BYOVD 样本之后,我一般不会直接在一个有重要数据的环境里执行它。先做静态分析。
第一步是看数字签名。一个驱动如果签名链完整、时间戳新、证书有效,通常意味着它不是攻击者自制驱动。但这不代表没有风险,很多 BYOVD 工具用的恰恰是这种正规签名的驱动。所以签名只是分类依据,不能作为恶意判定依据。
第二步是看文件版本信息和编译时间。这里偶尔会有线索:如果驱动文件的公司名是某硬件厂商,但文件名、版本资源与已知产品对不上,或者版本号低得离谱,那它被拿来当漏洞驱动的概率就会显著增加。旧版本驱动往往没有修复已知漏洞,这是攻击者选择它的原因。
第三步,也是最关键的一步,是用结构查看工具分析驱动导入表和字符串信息。重点关注几类字符串:设备路径(比如包含 Device 的路径名)、控制设备名、版本信息、硬件设备关键字、错误日志关键字。这些字符串会直接暴露驱动提供的功能面。如果字符串里出现与硬件标识、序列号、物理内存映射相关的关键词,结合文件来源基本可以判定它的用途倾向。
第四步是查漏洞驱动知识库。现在业界有一些公开维护的易受攻击驱动列表,把驱动的哈希、文件名、漏洞类型做了整理。虽然不方便在这里提具体名单,但你可以去搜“易受攻击的驱动列表”这个关键词。把样本哈希丢进去比对,如果是已知明星驱动,那基本可以实锤了。
3.2 动态调试阶段:观察驱动与内核的交互
静态分析只能给出“这个驱动有高危能力”的结论,真正要确认攻击行为,还得动态观察。
我常用的环境是双机调试:宿主机装调试器,虚拟机或测试机作为目标系统,目标系统开启内核调试。测试机里放一个控制程序样本,然后用调试器监控加载路径。
第一步,给驱动加载下断点。当控制程序触发驱动加载时,观察驱动入口是否执行成功、是否有异常分支。如果驱动入口里存在一些自校验逻辑,它会主动拒绝在某些环境下工作。这种自校验对抗的是分析环境,本身也是恶意行为的一部分。
第二步,关注 IOCTL 分发例程。驱动加载成功后,控制程序会发送控制码。在分发例程上下断点,跟踪每一次设备控制请求进来时的输入缓冲和输出缓冲。重点看控制码对应的功能编号:哪些控制码会触发内存读写?哪些会读取或修改设备数据?哪些会调用内核导出函数做地址解析?
第三步,对比内存变化。在控制程序执行“欺骗”操作前后,用调试器读出目标设备对象相关的数据结构快照,对比差异。如果发现序列号缓冲区、设备标志位、回调指针发生了变化,就基本掌握了它的核心篡改区域。
动态分析过程中还有一个值得记录的细节:驱动退出时的行为。有些工具在完成任务后不会卸载驱动,而是把驱动留在系统里,方便后续持久化;有些则会搞自我清理。分析退出路径可以直接看到工具作者的工程习惯和持久化意图。
3.3 分析过程中的高频翻车点
这类样本分析翻车率不低,我把常见的坑整理一下。
第一个坑:驱动加载失败导致目标系统蓝屏。漏洞驱动本身是正常驱动,正常使用不会蓝屏。但攻击者写的控制程序在调用驱动接口时,可能传了不合理的参数,比如越界长度、空指针、非法地址,驱动里的漏洞就会在这种场景下触发,导致系统蓝屏。分析时一定要提前开好内存转储,蓝屏后直接从转储文件里找原因。
第二个坑:忽略了驱动的“单一实例”保护。部分驱动会检查自身是否已经被加载,如果发现重复加载会拒绝工作。研究时如果跑了两遍流程,第二遍驱动加载后控制程序发接口却毫无反应,先确认驱动是否处于活动状态。
第三个坑:HVCI 干扰。现在很多测试环境开启了内存完整性,漏洞驱动的某些操作会被 HVCI 拦截,导致行为观察不完整。做动态分析时,最好明确记录目标环境是否开启 HVCI,避免以后复现时行为对不上。
第四个坑:忽略驱动文件本身的自校验。有些工具会把驱动文件和自己的控制程序做成配套关系,控制程序启动时会校验驱动文件的哈希或嵌入的密钥。直接拿驱动出来单独分析没问题,但如果想脱离控制程序手动加载驱动,驱动会拒绝运行。遇到这种情况,别硬刚,回归控制程序本身,顺藤摸瓜。
4. 防御侧:如何把这条攻击路堵死
4.1 系统层面:驱动签名强制与 HVCI
单看驱动签名强制,BYOVD 确实是绕过了它——因为驱动签名本身合法,DSE 拦不住。所以防御不能只依赖 DSE。
真正有效的系统层面防线是内存完整性(HVCI)。HVCI 用虚拟化方式隔离内核代码完整性检查,禁止非签名代码进入内核,同时限制了内核内存的可写可执行权限。对于依赖“加载驱动后篡改内存”的 BYOVD 工具来说,HVCI 能拦住一部分物理内存映射和任意内核内存写操作。
但 HVCI 不是万能的。首先,部分旧驱动跟 HVCI 不兼容,系统为了兼容性默认不一定开启。其次,即使开启 HVCI,如果漏洞驱动本身拥有的权限就是写设备私有内存,HVCI 未必能识别出这是恶意篡改。所以 HVCI 适合当基础防线,不适合当唯一防线。
微软针对易受攻击驱动有一个不断更新的阻断清单,系统会阻止清单里的驱动加载。这个机制很实用,但它同样依赖更新。企业环境如果更新管理混乱,清单的覆盖率会大打折扣。建议在组策略或安全基线里,把易受攻击驱动阻断作为强制项。
4.2 产品层面:EDR 怎么发现异常驱动
杀毒软件扫描文件哈希只能发现已知恶意样本,对 BYOVD 这种“白驱动恶意利用”的检测,更应该关注行为而不是文件。
我梳理过一条有效的检测思路,主要看四个维度。
驱动加载行为:记录新驱动的文件名、文件路径、签名者、加载时间、加载发起进程。正常情况下,新驱动加载频率很低。如果一个激活工具进程创建了服务,随后加载了一个硬件厂商驱动,这个行为组合就值得关注。
控制码流量:控制程序与漏洞驱动通信时,会打开特定设备路径。检测规则可以把“某系统工具进程打开某设备路径 + 连续发送控制码”作为关联条件。很多正常软件不会直接打开内核驱动设备,这本身就具备异常特征。
驱动加载后的进程行为:驱动加载后,控制程序通常会读取硬件信息、修改系统属性、或者做自校验。注意到这些行为发生在驱动加载后的几秒内,而且发起者是低信誉进程,可以从中提取出强特征。
异常内存访问:这个维度对内核数据采集能力要求较高。如果安全产品有内核监控能力,可以观察设备对象分发例程是否被替换、有效缓冲区是否被频繁写入。没有内核监控能力的产品,也可以退而求其次,通过多路径硬件查询结果比对来发现问题——比如先走应用层 API 查一遍序列号,再走底层总线查询一遍,两次结果不一致,基本可以判定有内核层篡改行为。
4.3 运维层面:驱动基线管理
防御的最后一道关在运维侧。
我建议维护一份企业环境的驱动白名单:所有允许加载的内核驱动,记录文件名、版本号、哈希、签名者。白名单之外的驱动,一律视为可疑。技术在具体落地时并不复杂,不少终端管理软件都支持驱动 Hash 黑名单/白名单策略,只是多数企业根本没有启用。
另外,要对“旧版本驱动”有敏感度。很多锐捷网络环境、金融柜台系统、老旧终端,因为兼容性原因保留了成堆的旧驱动。这些驱动里面就可能躺着漏洞驱动。运维侧应定期盘点终端驱动清单,关闭不用的设备通道,卸载不兼容的旧驱动。尤其在重装系统、升级补丁之后,检查一遍驱动版本往往会排掉不少雷。
在处理这类事件时,我觉得还有个细节容易被忽略:漏洞驱动并不仅仅以“驱动文件”的形式存在。攻击者可以把它做成服务,开机自启,也可以直接在内存里加载不落盘。运维做驱动清单时,不能只看磁盘上的文件,还要看当前已加载的内核模块列表。部分终端工具可以查看内核模块,如果没有,用系统自带命令加 PowerShell 脚本也能拉出一份已加载驱动快照。
5. 常见问题排查与工具清单
5.1 排查驱动加载失败与兼容性问题的思路
研究中我经常收到同类咨询,这里列一个高频问题速查表。
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| 驱动服务创建成功但启动失败 | 签名被系统阻断 / 驱动不兼容当前系统版本 | 查系统事件日志,看是否出现易受攻击驱动阻断事件;再查代码完整性日志 |
| 控制程序打开设备句柄失败 | 驱动未成功加载或设备名不匹配 | 用设备管理器或内核对象查看工具确认设备是否存在 |
| 驱动加载后蓝屏 | 调用接口传入非法参数,触发驱动漏洞 | 开启内核转储,分析蓝屏文件,定位崩溃模块 |
| 执行篡改操作后查询结果未变化 | 目标设备对象不是预期对象,或篡改区域不对 | 对比多个硬件 ID 查询接口的差异,定位真正的查询路径 |
| 安全软件报毒但文件签名合法 | EDR 对行为命中的报警 | 查看报警详情,确认是行为规则命中还是特征命中 |
第一行“驱动被系统阻断”是目前最常见的现象。Windows 更新会把已知易受攻击驱动的哈希加进本地阻断库,加载时直接被拦。这是防御方的胜利,但也意味着攻击者会去找库里没有的新驱动。这是猫鼠游戏,防御侧必须持续更新知识库。
5.2 我常用的研究工具整理
涉及工具,我不在这里列商业软件全名,但你可以按下面的描述去找。它们全部是安全研究领域公开常见的工具。
- 文件信息查看工具:查看数字签名、文件版本、编译时间、导入表。
- 反汇编器:对驱动做静态逆向,分析 IOCTL 分发逻辑和漏洞触发点。
- 内核调试器:双机调试,动态跟踪加载路径、分发例程和内存写入。
- 进程与句柄分析工具:查看设备路径、进程打开了哪些内核设备对象、服务创建记录。
- 系统事件日志工具:查看代码完整性日志、内核事件日志、服务创建记录。
- 内存转储分析工具:蓝屏分析、内核堆栈还原。
这组工具组合可以覆盖从静态分析到动态调试的完整闭环。工具清单建议固定下来,定期练习双机调试环境搭建,不要等到事件发生了再临时研究。环境搭建本身也是防御能力建设的一部分。
6. 一点个人经验
在 mock 项目X的攻防仿真里,我拿一个改造过的驱动做了一遍完整的 BYOVD 流程,才真正体会到这事的严重性:漏洞驱动不是“有可能被利用”,而是“非常容易被利用”。因为签名机制给了它合法的入场券,行为监控又很难从内核层面看出异常,整个攻击过程在真实环境中的检出率低得让人不安。
我个人的体会是,防御这类攻击的关键不在于找到某一个“万能规则”,而在于把多重基础能力叠起来:系统基线、驱动清单、易受攻击驱动阻断库、行为监控和应急响应预案。每一层单独看起来都有缺口,但叠在一起,攻击者想神不知鬼不觉完成整个链条就会难很多。
最后分享一个小技巧。做检测规则时,别只盯着驱动文件,把“用户态控制程序打开设备路径后再调用系统 API 查询硬件信息”这个过程作为一个整体行为事件来看。真实研究中,我发现这种关联行为的特异性远高于单看驱动加载。先收集数据,再找规律,再落规则,这条思路在防御 BYOVD 类威胁时尤其好用。