更新记录(仅首版,2026年08月22日 发布)
- 首次发布
引用本文(DOI(已登记存档): 10.5281/zenodo.22176889)
以下 DOI 指向先前登记的存档,内容可能与当前正文不同。引用当前正文时,请使用本页网址。
Go Komura(2026)。《Windows 虚拟化的深层(第 2 回)── 连内核也读不到的内存:VBS、HVCI 与 Credential Guard 的机制》。小村软件有限公司。 https://comcomponent.com/zh-CN/blog/windows-virtualization-internals-vbs-hvci-credential-guard/
- DOI(已登记存档)
- 10.5281/zenodo.22176889
- DOI(上次登记版本)
- 10.5281/zenodo.22176890
连管理员权限和内核都读不到的秘密,Windows 究竟放在哪里? 第 2 回就从这个问题出发,来看 VBS、HVCI 与 Credential Guard 的机制。
在以往的 Windows 上,攻击者以管理员身份加载内核驱动程序、转储 LSASS 进程的内存,就能偷走密码哈希和 Kerberos 票据,并用它们横向移动到别的机器。
在 Credential Guard 正在运行的 Windows 11 上,受保护的域凭据哈希不会放在普通内核找得到的地方。在满足 Enterprise、Education 等许可证要求与硬件要求的设备上,从 22H2 起这项保护默认启用。1 要求与实际的运行状态是两回事,所以并不等于「没在运行时的危险」已经消失。
第 1 回看到的是主机 Windows 运行在虚拟机监控程序之上的根分区里这一结构。本文要追的,是在同一个分区内部再画出的另一条边界线。
「Windows 虚拟化的深层」全 3 回
同一个 Windows 虚拟机监控程序,按基础 → 安全隔离 → 轻量虚拟机的应用的顺序来看。
| 回 | 核心问题 |
|---|---|
| 第 1 回:虚拟机监控程序与分区 | 主机 Windows 究竟在哪里运行 |
| 第 2 回:VBS、HVCI 与 Credential Guard(本文) | 连内核也读不到的秘密放在哪里 |
| 第 3 回:WSL2、Windows Sandbox 与容器 | 保持隔离的同时,为什么还能做得这么轻 |
本文的前提
| 项目 | 内容 |
|---|---|
| 目标读者 | 想弄清内核隔离、内存完整性与 Credential Guard 究竟是什么的开发者与运维人员 |
| 前提环境 | x64 的 Windows 10/11 或现行 Windows Server。关于环与 SLAT 的说明以 x64 为前提,Arm64 用的是异常级别等另一套机制 |
| 前提知识 | 第 1 回的分区与 SLAT 概念 |
| 难度与范围 | 中级。不是配置手册,而是讲解安全功能的结构 |
本文的读法
| 想了解的内容 | 阅读的小节 |
|---|---|
| 为什么需要比内核更强的隔离,以及如何实现 | 第 2 节:传统模型的极限 → 第 3 节:VSM、VTL 与 SLAT |
| HVCI 与 Credential Guard 各自保护什么 | 第 4 节:代码完整性 → 第 5 节:凭据与保护范围 |
| 怎样把设置画面和实际运行状态分开来读 | 第 6 节:确认方法 → 第 7 节:误读 |
1. 先说结论
Windows 追加了 VTL(虚拟信任级别)这一条特权的轴,并把秘密放在 VTL1。在 VTL0 运行的普通内核读不到 VTL1 的内存。守住这条边界的不是内核自己,而是握着 SLAT 转换表的虚拟机监控程序。
这就是基于虚拟化的安全性(VBS)的骨架。VBS 用虚拟机监控程序造出隔离环境,把安全功能收容其中。它的设计前提是:即便内核被攻陷,隔离环境依然安全。2
flowchart TB
accTitle: VBS 造出的两个世界
accDescr: 同一个分区里有 VTL0 和 VTL1,VTL0 中是普通内核与应用,VTL1 中是安全内核与被隔离的安全功能,边界由虚拟机监控程序守护
subgraph vtl0 ["VTL0(普通世界)"]
apps["应用(环 3)"]
ntk["NT 内核与驱动程序(环 0)"]
end
subgraph vtl1 ["VTL1(被隔离的世界)"]
ium["被隔离的安全功能"]
sk["安全内核"]
end
hv["虚拟机监控程序(用 SLAT 强制边界)"] --- vtl0
hv --- vtl1
ntk -.->|无法读取| ium
图1:一个 Windows 里存在两个世界,VTL0 的内核无法访问 VTL1 的内存。
要点在于,这并不是「另外起了一台虚拟机」。VTL0 与 VTL1 位于同一个分区、同一个 Windows 的内部。下面就依次来看这个划分是如何实现的。
图中实线表示始终成立的关系,虚线表示带条件的关系(成立条件写在详情页各关系的说明中)。关系的完整列表(共 22 条,附依据与确信度)以及主要概念的定义,汇总在知识地图详情页(日文)。数据:JSON-LD / Turtle
2. 环模型的极限 ── 守护的一方和被守护的一方处在同一高度
以往 Windows 的安全性,建立在环(特权级别)这道阶梯之上。用户模式(环 3)由内核模式(环 0)守护。那么环 0 由谁来守——没有人守得了。因为环 0 就是最高特权。
这个结构有两处根子上的弱点。
- 内核并非铁板一块。 环 0 上运行的不只有 Windows 本体,还有大量第三方驱动程序。其中任何一个存在漏洞,攻击者就能拿到环 0 的代码执行权。
- 从环 0 什么都看得见。 像 LSASS 这样的用户模式进程再怎么自我防护,对掌握了内核的攻击者来说内存都是随便读的。因为保护属性和页表本来就由内核自己管理。
flowchart TB
accTitle: 传统环模型下凭据被窃取的路径
accDescr: 通过有漏洞的驱动程序拿下环 0 的攻击者,可以用内核的全部权限读取 LSASS 进程的内存,取得密码哈希
mal["攻击者的代码"] -->|利用有漏洞的驱动程序| r0["拿下环 0"]
r0 --> readall["能读取全部物理内存"]
readall --> lsass["从 LSASS 的内存取得哈希"]
lsass --> lateral["用于横向移动到别的机器"]
图2:守护的一方(内核)和被守护的一方(秘密)处在同一高度,所以环 0 一旦失守就全盘皆输,这是根子上的弱点。
也就是说,需要的是「比环 0 更高的位置」。第 1 回里,这个位置已经出场过了。虚拟机监控程序以高于内核的特权运行,并在很早的阶段独占 CPU 的内存访问权限控制(SLAT)。虚拟机监控程序守护的隔离区域,对来自环 0(管理程序模式)的操作系统软件的访问同样是受保护的。3
3. VSM 与 VTL ── 给特权再加一条轴
本节按提供隔离的功能组(VSM)→ 隔离的级别(VTL)→ 强制边界的机制(SLAT)→ 在其中运行的代码的顺序来梳理。名字相似,但并不是同一样东西。
3.1. 虚拟信任级别(VTL)
提供这种隔离的虚拟机监控程序功能组,称为 VSM(虚拟安全模式)。VSM 是 Device Guard、Credential Guard、虚拟 TPM 等的基础。3
VSM 的核心概念是 VTL(Virtual Trust Level:虚拟信任级别)。要点如下。3
- VTL 是分层的,编号越大特权越高。VTL0 最低,VTL1 的特权高于 VTL0。
- 架构上定义了最多 16 个级别,但目前实现的是 VTL0 与 VTL1 这两个。
- 每个 VTL 拥有各自独立的内存访问保护。这些保护由虚拟机监控程序针对分区的物理地址空间管理,因此分区内的系统软件无法更改。
- 虚拟处理器在每个 VTL 上拥有各自的寄存器状态与中断机制,低 VTL 窥视不到高 VTL 的状态。
flowchart TB
accTitle: 构成 VTL 隔离的三项独立
accDescr: 每个 VTL 的内存访问保护、虚拟处理器的寄存器状态和中断机制都各自独立,低 VTL 碰不到高 VTL 的任何一项
vtl["每个 VTL 各自独立的东西"] --> m1["内存访问保护"]
vtl --> m2["虚拟处理器的寄存器状态"]
vtl --> m3["中断机制"]
m1 -.-> rule["低 VTL 碰不到高 VTL"]
m2 -.-> rule
m3 -.-> rule
图3:不只是内存,连 CPU 的状态和中断都做成另一个世界,才是不留窥视孔的三件套。
如果说环(0 与 3)是划分「操作系统与应用」的轴,那么 VTL 就是划分「普通世界与隔离世界」的第二条轴。两条轴彼此正交,VTL1 内部同样有内核模式和用户模式。
flowchart TB
accTitle: 环与 VTL 两条轴造出的四个区域
accDescr: 环这条轴划分内核模式与用户模式,VTL 这条轴划分普通世界与隔离世界,组合起来形成普通应用、NT 内核、IUM 的 Trustlet、安全内核这四个区域
subgraph ax0 ["VTL0(普通世界)"]
a0["环 3:普通应用"]
k0["环 0:NT 内核与驱动程序"]
end
subgraph ax1 ["VTL1(隔离世界)"]
a1["环 3:IUM(Trustlet)"]
k1["环 0:安全内核"]
end
a0 --- k0
a1 --- k1
k0 ~~~ a1
图4:特权的轴变成了两条,「是不是内核」和「是不是隔离世界」成了两个不同的问题。
3.2. 边界的实体是 SLAT
第 1 回讲过,把客户机物理地址(GPA)映射到实际 RAM(SPA)的第二级转换表——SLAT——握在虚拟机监控程序手里。VSM 用的正是这一性质。VTL 的隔离,是利用 Hyper-V 虚拟机监控程序与 SLAT 造出来的。4
当 VTL1 声明「这块内存不给 VTL0 看」时,虚拟机监控程序就会从 VTL0 用的转换表中撤掉对该页的访问权限。此后即便 VTL0 的内核去碰那个地址,也会在 CPU 的地址转换阶段被拒绝。内核怎么改自己的页表都是白费。
因为页表(GVA→GPA)虽然归内核所有,但再往后的转换(GPA→SPA)以及最终的访问权限,归虚拟机监控程序所有。
flowchart TB
accTitle: 从 VTL0 访问 VTL1 内存被拒绝的流程
accDescr: VTL0 的内核想读 VTL1 的内存时,即便通过了自己的页表,也会被 SLAT 的访问保护拒绝,控制权转到虚拟机监控程序
try["VTL0 的内核试图读取 VTL1 的页"] --> pt["内核自己的页表可以通过"]
pt --> slat{"SLAT 的访问保护允许吗?"}
slat -->|没有许可| deny["虚拟机监控程序介入并拒绝访问"]
slat -->|有许可| ok["普通的内存访问"]
deny -.-> point["由内核改不了的一层来守护"]
图5:防壁位于内核之外,而 SLAT 的保护无法被分区内的软件更改。
内存系列第 1 回写过「VAD、PTE 与保护属性决定访问能否通过」。在 VBS 环境中可以这样理解:全部通过之后,还有 SLAT 这道关卡在等着。
3.3. 安全内核与 IUM
在 VTL1 中运行的不是普通的 NT 内核,而是一个称为安全内核的小内核。VTL1 的用户模式称为 IUM(Isolated User Mode:隔离用户模式),在其中运行的程序称为 Trustlet(受信任的进程)。4
Trustlet 并不像普通进程那样什么都能做。大多数系统调用会封送到 VTL0 一侧的 NT 内核,委托它来处理。4 VTL1 不是「什么都能做的上位世界」,而是被刻意造得很小的保管秘密的金库。能带进库内的代码越少,攻击面就越小。
flowchart TB
accTitle: Trustlet 的系统调用流程
accDescr: VTL1 的 Trustlet 不自行处理大多数系统调用,而是封送给 VTL0 的 NT 内核,只接收结果,从而把 VTL1 保持得很小
tl["Trustlet(VTL1 的 IUM)"] --> sc{"需要系统调用"}
sc -->|多数情况| mar["委托给 VTL0 的 NT 内核"]
mar --> res["只接收结果"]
res -.-> small["VTL1 一侧保持得小,攻击面随之减少"]
图6:金库不自备设备,杂事一律往外委托,只专心守住秘密。
4. HVCI ── 在金库里验证内核的代码完整性
关于 HVCI 要抓住两点:验证在哪里进行,以及验证之后允许内存做什么。下面依次来看它的保护,以及对驱动程序兼容性的影响。
4.1. 验证的到底是什么
建立在 VBS 之上的代表性功能,第一个是内存完整性——HVCI(由虚拟机监控程序保护的代码完整性)。Windows 有一套代码完整性机制,会在启动前检查内核模式的驱动程序和二进制文件,不让未签名或不受信任的东西加载。HVCI 把这项验证放到 VBS 的隔离环境中执行。2
把验证逻辑本身搬到 VTL1 的理由,正是第 2 节说的那个弱点。验证代码若在 VTL0 的内核里,掌握了内核的攻击者就能把验证掉包。放在 VTL1,掉包的手就伸不过来了。
flowchart TB
accTitle: 验证代码放在哪里带来的差别
accDescr: 验证代码若在 VTL0 的内核里,内核一被拿下就会失效,若在 VTL1 则连拿下内核的攻击者也伸不到手,验证得以保全
atk["拿下内核的攻击者"] --> q{"代码完整性的验证在哪里?"}
q -->|"VTL0 的内核里(传统)"| bad["验证逻辑可以被掉包"]
q -->|"VTL1 的隔离环境(HVCI)"| good["掉包的手伸不过来"]
bad --> res1["未签名的代码可能在内核里执行"]
good --> res2["内核被攻陷之后验证依然有效"]
图7:不要把检查站放在有可能被攻破的那一侧内部——验证逻辑的这次搬家,就是 HVCI 的本质。
4.2. 可执行页的规则
HVCI 的效果不止于「启动时的检查」,它也对内核内存的分配施加约束。5
- 内核的页只有通过代码完整性验证之后才变为可执行。
- 可执行的页不会同时可写(即所谓的 W^X)。
这两条凑齐之后,即便用缓冲区溢出之类的漏洞改写了内核内存,也无法把改写的内容投入执行。因为可执行的页改不了,而改得动的页执行不了。5 执行许可最终的依据在 SLAT 一侧的执行权限,而这是 VTL0 的内核操作不了的。
flowchart TB
accTitle: HVCI 环境中内核页变为可执行的过程
accDescr: 驱动程序的加载请求在 VBS 的隔离环境中接受代码完整性验证,通过就允许成为可执行且不可写的页,不通过则被阻止并记入 CodeIntegrity 日志
load["内核代码的加载与执行请求"] --> verify{"在隔离环境中做代码完整性验证"}
verify -->|通过| exec["允许为可执行页(不可写)"]
verify -->|不通过| block["加载被阻止"]
block --> log["记入 CodeIntegrity 运行日志(事件 ID 3087)"]
exec -.-> wx["可写的页仍然不可执行"]
图8:不让执行和写入两立的这条规则,其验证在 VTL1 一侧进行,VTL0 的内核推翻不了。
顺着攻击者的视角走一遍,就能看清这条规则是怎么起作用的。
flowchart TB
accTitle: HVCI 环境中代码注入失败的流程
accDescr: 即便用漏洞改写了内核内存,写得进去的页不可执行,而可执行的页本来就改不了,因此注入的代码无法投入执行
inj["试图用漏洞在内核内存里做手脚"] --> which{"要下手的是哪一种页?"}
which -->|可写的页| wok["改写会成功"]
which -->|可执行的页| xfail["根本改写不了"]
wok --> nx["但那个页不可执行"]
nx --> dead["注入的代码无法投入执行"]
xfail --> dead
图9:从哪个入口进去都是死路一条——让可写的页和可执行的页不相交,意义就在这里。
4.3. 驱动程序兼容性这一代价
这条规则会和旧设计的驱动程序冲突。在运行时改写自己的代码、没有签名、要求既可执行又可写的内存——这样的驱动程序在 HVCI 环境中加载不了。
被阻止这件事,可以在事件查看器的 Applications and Services Logs\Microsoft\Windows\CodeIntegrity\Operational(有代表性的是事件 ID 3087)中确认。6
「一启用内存完整性外设就不工作了」这类麻烦,多数情况下真身就是它。处理的正路是更新到支持 HVCI 的驱动程序版本,而关闭内存完整性等于把这层保护整个交出去,应当当作最后手段。
如果你是从驱动程序开发这一侧参与这类验证,也可以参考筛选器驱动程序的文章(「Windows 的微筛选器驱动程序」)。
flowchart TB
accTitle: 内存完整性导致外设不工作时的排查
accDescr: 用 CodeIntegrity 运行日志定位被阻止的驱动程序,正路是更新到支持 HVCI 的版本,没有对应版本就向厂商提出要求,关闭功能是不做成长期设置的最后手段
sym["启用内存完整性后设备不工作"] --> log2["用 CodeIntegrity 日志定位阻止的来源"]
log2 --> upd{"有支持 HVCI 的驱动程序版本吗?"}
upd -->|有| fix2["更新后保持启用并解决"]
upd -->|没有| ask2["向厂商要求提供对应版本"]
ask2 -.-> temp["关闭是不做成长期设置的最后手段"]
图10:最先该看的不是设置画面而是日志,阻止的元凶由事件 ID 3087 来告诉你。
5. Credential Guard ── 哈希在 LSAIso 里面
HVCI 守的是内核的代码完整性,而 Credential Guard 守的是凭据。把受理认证的窗口和秘密的保管场所分开来想,结构与防守范围就串起来了。
5.1. LSASS 与 LSAIso
建立在 VBS 之上的第二个代表性功能,就是开头那个谜题的答案:Credential Guard。
以往的 Windows 把 NTLM 哈希和 Kerberos 的各类票据保存在 LSA 进程(lsass.exe)的内存里。启用 Credential Guard 之后,其中受保护的秘密——域凭据的 NTLM 哈希、Kerberos 的 TGT(票据授予票据)等——的保管,就移交给 LSAIso.exe——运行在 VTL1 的 IUM 中的 Trustlet。7
- lsass.exe(VTL0)照旧作为认证处理的窗口运行。
- 秘密的实体由 LSAIso.exe(VTL1)持有,VTL0 访问不到。
- 两者通过 RPC(远程过程调用)通信。
- LSAIso 完全不承载设备驱动程序,只收容必需的最小限度的已签名二进制文件。签名由 VBS 信任的证书验证。7
flowchart TB
accTitle: 启用 Credential Guard 时凭据的放置方式
accDescr: VTL0 的 lsass 作为认证窗口用 RPC 与 VTL1 的 LSAIso 通信,受保护的域凭据哈希和 TGT 的实体由 LSAIso 持有,因此在 VTL0 拿到管理员权限的攻击者转储 lsass 也得不到实体
subgraph v0 ["VTL0"]
lsassP["lsass.exe(认证的窗口)"]
att["攻击者(管理员权限)"]
end
subgraph v1 ["VTL1"]
iso["LSAIso.exe(秘密的保险库)"]
end
lsassP <-->|RPC| iso
att -->|内存转储| lsassP
att -.->|够不到| iso
图11:窗口和保险库被分开了,所以就算转储 lsass,受保护的域凭据哈希的实体也已经不在那里。
默认启用的条件
从 Windows 11 版本 22H2 起,在满足许可证要求(Enterprise E3/E5、Education A3/A5)与硬件要求的设备上,VBS 与 Credential Guard 默认启用。在 Pro 等版本上 Credential Guard 不会自动启用(也有例外,比如过去在符合条件的许可证下启用过的终端被降级的情形)。1
这种凭据保护并不是什么额外产品的话题,而是对应版本的现行 Windows 的标准状态。
flowchart TB
accTitle: 从登录到认证的凭据流动
accDescr: 登录之后秘密的实体保管在 VTL1 的 LSAIso 里,每当需要认证时 VTL0 的 lsass 用 RPC 委托运算,受保护的长期秘密本身不会返回,只有认证处理的结果回到 VTL0
signin["用户登录"] --> front["lsass 作为窗口处理"]
front --> store["秘密的实体保管到 LSAIso"]
auth["之后的认证请求"] --> front
front -->|用 RPC 委托运算| store
store -->|返回处理结果(不返回秘密)| front
图12:受保护的长期秘密本身不会离开保险库,回到 VTL0 的是票据等认证处理的结果。
5.2. 准确地知道哪些不受保护
受保护的凭据
Credential Guard 不是万能的盾。受保护的是域凭据的 NTLM 哈希、Kerberos 的 TGT(票据授予票据),以及作为域凭据保存的内容。
不在保护范围内的东西
下面这些不在范围内。8
- Kerberos 的服务票据(TGT 受保护)
- 本地账户与 Microsoft 账户的凭据
- 键盘记录器在输入时的窃取,以及物理攻击
- 走 NTLMv1、MS-CHAPv2、Digest、CredSSP 这些路径的凭据
- 自行管理凭据的第三方软件内部
除了保护范围,还要确认认证的兼容性
另外,启用 Credential Guard 之后 NTLMv1 和 Kerberos 的无约束委派等将不能再用,因此依赖旧式认证的业务系统需要先确认兼容性。8 不是「启用就完事」,而是把防守范围的内外摸清楚,再用别的措施补上剩下的部分——这才是实务中正确的用法。
flowchart TB
accTitle: Credential Guard 的防守范围
accDescr: 域的 NTLM 哈希与 TGT、已保存的域凭据受保护,而服务票据、本地账户、键盘记录器、物理攻击、应用自行保存的凭据都不在保护范围内
scope{"那个秘密在防守范围的哪一侧?"} --> inA["域的 NTLM 哈希与 TGT"]
scope --> outA["服务票据或本地账户"]
inA --> prot["由 LSAIso 保护"]
outA --> unprot["不受保护(需要别的措施)"]
unprot -.-> outB["按键输入、物理攻击、应用自行保存也不在范围内"]
图13:防守范围划得很清楚,线外的部分要靠多因素认证和应用一侧的设计来补。
6. 用自己的眼睛确认
VBS 与各项功能的运行状态,可以在手边确认。要把 VBS 这个基础的状态,和跑在它上面的服务的状态分开来读。
6.1. 用 PowerShell 确认 VBS 与正在运行的服务
Get-CimInstance -Namespace root/Microsoft/Windows/DeviceGuard `
-ClassName Win32_DeviceGuard |
Select-Object VirtualizationBasedSecurityStatus,
SecurityServicesConfigured,
SecurityServicesRunning
读法如下。9
VirtualizationBasedSecurityStatus为 2,表示 VBS 已启用且正在运行。SecurityServicesRunning中含有 1 就是 Credential Guard、含有 2 就是内存完整性(HVCI)正在运行。
6.2. 把 msinfo32 和设置画面分开来读
若要用图形界面确认运行状态,就看 msinfo32 的「基于虚拟化的安全性」栏(正在运行的服务里会列出「虚拟机监控程序强制的代码完整性」等)。
Windows 安全应用里「设备安全性 > 内核隔离」下的「内存完整性」开关,映出来的是设置,在刚启用后等待重启期间,或者启动时出现兼容性问题、HVCI 实际并未运行期间,它也可能看起来是开着的,因此是否正在运行要用 msinfo32 或 Win32_DeviceGuard 的 SecurityServicesRunning 来判断。6
6.3. 不要只凭进程在不在就断定它在运行
任务管理器的详细信息选项卡里也有痕迹。在 VBS 运行的机器上,能看到一个叫「安全系统」(Secure System)的进程。LsaIso.exe 是隔离 LSA 的服务被托管在 VTL1 时才出现的进程,在只启用了 HVCI 的配置下通常不会出现。
不过进程在不在终究只是痕迹,Credential Guard 是否在运行,还是要用前面说的 SecurityServicesRunning(是否含有 1)来判断。两者都是对应着 VTL1 那个世界、从 VTL0 看得见的窗口。
flowchart TB
accTitle: VBS 相关功能的运行确认步骤
accDescr: 用 Win32_DeviceGuard 的查询确认 VBS 是否在运行,再从 SecurityServicesRunning 的值判断 Credential Guard 与 HVCI 是否在运行,驱动程序问题则看 CodeIntegrity 日志
q0["查询 Win32_DeviceGuard"] --> q1{"VBS 的 Status 是 2 吗?"}
q1 -->|否| off["VBS 未运行(确认要求与设置)"]
q1 -->|是| q2{"SecurityServicesRunning 的值是?"}
q2 -->|含有 1| cg["Credential Guard 正在运行"]
q2 -->|含有 2| hvciR["内存完整性(HVCI)正在运行"]
hvciR -.-> ev["驱动程序问题看 CodeIntegrity 日志(3087)"]
图14:状态确认按 VBS 本体、其上的各项服务、出问题时的日志这三个阶段推进。
7. 实务中要避开的三种误读
7.1. 「守住管理员权限就够了。VBS 是服务器那边的事」
Credential Guard 防的是管理员权限被夺走之后的损害扩大(哈希被带走以及横向移动)。也就是说,VBS 是以已被侵入为前提的纵深防御中的一层,恰恰在客户端 PC 上最见效。既然在满足要求的 Windows 11 上默认启用已是标准,那么正确的姿态就不是「跟我们没关系」,而是「按它已经在运行来管理兼容性」。
flowchart TB
accTitle: 入侵的阶段与 VBS 生效的位置
accDescr: 初始入侵由多因素认证和培训等别的措施承担,权限提升之后的内核代码注入由 HVCI 挡住,受保护域秘密的窃取与横向移动由 Credential Guard 挡住,但保护范围之外的秘密不在其列
s1["初始入侵(钓鱼等)"] --> s2["权限提升"]
s2 --> s3["向内核注入代码"]
s3 --> s4["受保护域秘密的窃取与横向移动"]
s1 -.-> d1["由 MFA、培训、EDR 承担"]
s3 -.-> d2["HVCI 在这里挡住"]
s4 -.-> d3["Credential Guard 挡住(仅限保护对象)"]
图15:VBS 不是「不让人进来」的技术,而是守在不同阶段的「进来了也别让他赢」的技术。
7.2. 「内存完整性一出问题,关掉就好」
关掉当然一时能用,但那等于把针对内核代码注入的防壁整个拆掉。正路是先用 CodeIntegrity 日志定位被阻止的驱动程序,再应用厂商的更新版本。就算为了验证而临时关闭,也建议不要把它固定成长期设置。
7.3. 「有了 Credential Guard 密码就不会被偷」
这是把防守范围混为一谈的过度自信。服务票据、本地账户、按键输入本身、应用自行保存的凭据都不在范围内。8 针对钓鱼和键盘记录器需要另外的措施(多因素认证、Windows Hello、重新审视应用一侧的凭据管理)。
8. 总结
- VBS 用虚拟机监控程序造出隔离环境,在内核可能被攻陷的前提下守护安全功能。2
- 隔离的单位是 VTL,目前实现了 VTL0(普通世界)与 VTL1(安全内核与 IUM)这两个级别。3
- 边界的实体是 SLAT 的内存访问保护,分区内的软件——包括内核——都无法更改。3
- HVCI 在隔离环境中做代码完整性验证,强制「验证通过前不可执行」「可执行的页不可写」。5 代价是需要管理驱动程序兼容性。6
- Credential Guard 把域凭据的 NTLM 哈希与 TGT 隔离到 VTL1 的 LSAIso。从 Windows 11 22H2 起,在满足许可证要求(Enterprise、Education)与硬件要求的设备上默认启用(请与运行状态的确认一起使用)。71
- 运行状态可以用
Win32_DeviceGuard的 SecurityServicesRunning(1=Credential Guard、2=HVCI)确认。9
接下来是第 3 回「几秒就能启动的虚拟机 ── WSL2、Windows Sandbox 与容器」。
到这里为止,我们都是从「隔离有多强」这一侧看虚拟化。最终回反过来,从「有多轻」这一侧,追一追舍掉了完整虚拟机重量的轻量虚拟机们究竟在哪里省了工。
相关文章
- Windows 虚拟化的深层(第 1 回)── 你的 Windows 究竟在哪里运行:虚拟机监控程序与分区
- Windows 内存的深层(第 1 回)── 虚拟地址变成物理 RAM 的瞬间:页错误的全过程
- Windows 的微筛选器驱动程序
- Windows 的错误码体系 ── Win32、HRESULT 与 NTSTATUS
相关咨询领域
小村软件有限责任公司承接 Windows 应用与安全功能的兼容性调查、驱动程序引起的故障分析,以及内部 PC 环境的技术验证。
参考链接
-
Microsoft Learn, Credential Guard overview. 关于从 Windows 11 版本 22H2 起,在满足许可证要求与硬件、软件要求且未被显式禁用的设备上 Credential Guard 默认启用;符合条件的版本与许可证是 Enterprise(E3/E5)与 Education(A3/A5),Pro 不在范围内;以及 Pro 上曾在符合条件的许可证下启用过的终端,在降级之后仍可能属于默认启用的对象。 ↩ ↩2 ↩3
-
Microsoft Learn, Virtualization-based Security (VBS). 关于 VBS 用硬件虚拟化与 Windows 虚拟机监控程序造出隔离环境,并在内核可能被攻陷的前提下把它当作操作系统的信任起点;内存完整性在该隔离环境中执行内核模式的代码完整性验证;以及 SLAT 是 VBS 的必要条件。 ↩ ↩2 ↩3
-
Microsoft Learn, Virtual Secure Mode. 关于 VSM 是 Device Guard、Credential Guard、虚拟 TPM 等的基础;对隔离区域的访问只经由虚拟机监控程序控制,即便面对环 0 的操作系统软件也受保护;VTL 是分层的,最多 16 级中实现了 2 级;以及每个 VTL 的内存访问保护无法被分区内的系统软件更改。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Isolated User Mode (IUM) Processes. 关于 VSM 利用 Hyper-V 虚拟机监控程序与 SLAT 造出 VTL;安全内核与 IUM 在 VTL1 中运行;Trustlet 把系统调用封送给 VTL0 的内核;以及 LSAIso 在 VTL1 中运行并经由 RPC 与 lsass 通信。 ↩ ↩2 ↩3
-
Microsoft Learn, Memory integrity and virtualization-based security. 关于内存完整性(HVCI)在隔离环境中执行代码完整性验证,以及内核内存页只有在通过验证之后才变为可执行、可执行页不会变为可写。 ↩ ↩2 ↩3
-
Microsoft Learn, Memory integrity and VBS enablement. 关于在兼容硬件上全新安装 Windows 11 时内存完整性默认启用;在 msinfo32 与 Windows 安全应用中确认状态;以及可以用 CodeIntegrity 运行日志的事件 ID 3087 确认被阻止的驱动程序。 ↩ ↩2 ↩3
-
Microsoft Learn, How Credential Guard works. 关于启用 Credential Guard 时 LSA 与隔离 LSA 进程(LSAIso.exe)通信来保管秘密;保管的数据受 VBS 保护,操作系统的其余部分无法访问;以及隔离 LSA 进程不承载设备驱动程序,只收容通过签名验证的最小限度的二进制文件。 ↩ ↩2 ↩3
-
Microsoft Learn, Credential Guard protection limits. 关于服务票据、本地账户、键盘记录器、物理攻击等不在 Credential Guard 的保护范围内;TGT 受保护而服务票据不受保护;以及启用之后 NTLMv1 与无约束委派将不能使用。 ↩ ↩2 ↩3
-
Microsoft Learn, Enable virtualization-based protection of code integrity. 关于用 Win32_DeviceGuard 类确认 VBS 与内存完整性状态的方法,以及 SecurityServicesRunning 各个值的含义(1 是 Credential Guard,2 是内存完整性)。 ↩ ↩2
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
关掉内存完整性(HVCI)会变快吗 ── 含义、步骤与判断
Windows 安全中心「内核隔离」里的内存完整性(HVCI)到底在做什么,关掉它真的会变快吗。本文面向入门读者,梳理可能变快的条件与不会变的条件、关闭的步骤与恢复方法、如何确认真的关掉了,以及什么情况下可以关。
Windows 虚拟化的深层(第3回) ── 数秒即可启动的虚拟机:WSL2、Windows Sandbox 与容器为何这么轻
WSL2 和 Windows Sandbox 为什么几秒就能启动、还这么轻?本文从动态基础映像、直接映射、内存的动态分配一直讲到 Hyper-V 隔离容器,逐层拆解其机制。
Windows 虚拟化的深层(第 1 回)── 你的 Windows 究竟运行在哪里:虚拟机监控程序与分区
启用 Hyper-V 之后,主机 Windows 自身会作为根分区运行在虚拟机监控程序之上。本文从 VT-x、SLAT、VMBus 的职责讲起,说清虚拟化的底层基础。
为什么“剩余1秒”迟迟不结束?── 进度条与剩余时间的工作原理
剩余1秒持续很久、卡在99%、一直显示准备中,分别是怎么回事?从进度的分母、速度预测、最后的处理步骤和界面更新逐一解释,并提供同一任务不同进度显示的交互演示。
Windows 共享文件夹为什么时好时坏——排查 Kerberos、NTLM 与凭据问题
通过症状和日志排查 Windows 共享文件夹时而能访问、时而无法访问的问题。说明 IP 与名称的差异、仅应用失败、空密码、1219、重启及 SMB 签名的检查步骤,以及每项结果能证明什么。
相关主题
与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。
Windows 技术主题
汇整 KomuraSoft LLC 关于 Windows 开发、故障调查与既有资产活用文章的主题中心。
常见问题
汇总了咨询这一主题时常见的问题。
- VBS(基于虚拟化的安全性)和内核隔离是同一回事吗?
- 严格说来是两回事。VBS 是用虚拟机监控程序造出隔离环境的基础技术,而 Windows 安全应用里的「内核隔离」是把建立在 VBS 之上的多项保护归到一起的画面名称。其中的代表是「内存完整性」,指的是 HVCI(由虚拟机监控程序保护的代码完整性)。各项服务的运行状态要通过查询 Win32_DeviceGuard 确认,而不是看画面显示。
- VTL1 的内存,用管理员权限或内核驱动程序真的读不到吗?
- 读不到。每个 VTL 的内存访问保护由虚拟机监控程序针对分区的物理地址空间管理,分区内运行的软件无法更改。即便是在内核(环 0)运行的代码,也不被允许从 VTL0 访问 VTL1 的内存。
- 为什么启用内存完整性(HVCI)后驱动程序会不工作?
- 在 HVCI 环境中,内核的页只有通过完整性验证之后才变为可执行,而且不允许写入可执行页。未签名的驱动程序,以及改写可执行内存的旧设计驱动程序,无法满足这一约束,加载会被阻止。被阻止的记录可以在 CodeIntegrity 运行日志(事件 ID 3087 等)中确认。
- Credential Guard 保护什么,不保护什么?
- 它在隔离环境中保护域凭据的 NTLM 密码哈希、Kerberos 的 TGT,以及应用作为域凭据保存的内容。另一方面,Kerberos 的服务票据、本地账户与 Microsoft 账户的凭据、键盘记录器在输入时的窃取以及物理攻击,都不在保护范围内。
- 在哪里可以确认 VBS 是否在运行?
- 看 msinfo32 的「基于虚拟化的安全性」栏,或者用 PowerShell 查询 root/Microsoft/Windows/DeviceGuard 命名空间的 Win32_DeviceGuard 类。若 SecurityServicesRunning 中含有 1,表示 Credential Guard 正在运行;含有 2 则表示内存完整性(HVCI)正在运行。