10.1.24 Registry virtualization:为什么容器里的应用明明以为自己在写 HKCU / HKLM,Configuration Manager 实际看到的却是 \Registr

张开发
2026/6/14 17:09:51 15 分钟阅读
10.1.24 Registry virtualization:为什么容器里的应用明明以为自己在写 HKCU / HKLM,Configuration Manager 实际看到的却是 \Registr
个人主页杨利杰YJlio❄️个人专栏《Sysinternals实战教程》 《Windows PowerShell 实战》 《WINDOWS教程》 《IOS教程》《微信助手》 《锤子助手》 《Python》 《Kali Linux》《那些年未解决的Windows疑难杂症》让复杂的事情更简单让重复的工作自动化《Windows Internals》10.1.24 Registry virtualization为什么容器里的应用明明以为自己在写 HKCU / HKLMConfiguration Manager 实际看到的却是 \Registry\WC...《Windows Internals》10.1.24 Registry virtualization为什么容器里的应用明明以为自己在写 HKCU / HKLMConfiguration Manager 实际看到的却是 \Registry\WCGUID...1. 先说结论Registry virtualization 本质上是“给容器应用一套假的入口给系统一套真的落点”2. 为什么 Windows 需要 registry virtualization因为容器不能真的直接改宿主机那棵全局注册表3. 两个关键词先记住Namespace redirection 与 Registry merging3.1 Namespace redirection3.2 Registry merging4. \Registry\WC 到底是什么为什么容器场景里它这么关键5. 应用到底是怎么被“悄悄改道”的关键在 VReg 的 registry callback5.1 为什么这件事特别关键6. 书里那个最经典的例子为什么应用以为自己在写 HKCU系统实际却写进了 \Registry\WC\GUID...7. differencing hive 为什么是容器注册表的另一半灵魂7.1 为什么这特别像现代容器层8. Configuration Manager 读取 differencing hive 时到底先看哪一层8.1 为什么这个规则特别重要9. Thumbstone key 是什么为什么它能让基础层里的 key “看起来不存在”10. 从桌面支持和系统学习视角这一节到底有什么现实价值10.1 它帮我真正理解“应用看到的路径”和“系统处理的路径”可以完全不同10.2 它帮我理解现代打包应用为什么经常“不改老代码也能跑进隔离环境”10.3 它帮我理解 differencing hive 为什么像“注册表 overlay”10.4 它帮我理解为什么有些场景下只看宿主机 HKCU / HKLM 根本解释不了应用行为11. 最容易误解的 6 个点我帮你一次理顺11.1 误区一registry virtualization 就是“多一份容器注册表副本”11.2 误区二应用必须改代码才能适配容器注册表11.3 误区三\Registry\WC 只是个普通字符串前缀11.4 误区四differencing hive 只能“加东西”不能“减东西”11.5 误区五基础层里有数据应用就一定能看到11.6 误区六容器里的注册表虚拟化只是应用层框架的小把戏12. 我的学习理解这一节真正教会我的是“虚拟化的本质不是复制世界而是重写入口与视图”13. 总结提升下一篇预告《Windows Internals》10.1.24 Registry virtualization为什么容器里的应用明明以为自己在写 HKCU / HKLMConfiguration Manager 实际看到的却是 \Registry\WC…学到10.1.24 Registry virtualization这一节时我觉得它和前面的Registry filtering、Application hives、namespace、differencing hives几乎是完全串起来的。因为很多人第一次接触容器里的注册表时都会有一个很强的直觉应用调用的是HKCU\Software\...那它写进去的就应该还是宿主机的HKCU\Software\...但书里给出的事实并不是这样。Windows 10 Anniversary UpdateRS1开始引入了registry virtualization这套能力由Configuration Manager和VReg driver共同提供核心能力分成两类namespace redirection和registry merging。其中VReg 会在容器里把\Registry\WC作为虚拟化 hive 的挂载根当容器化应用发起注册表 I/O 时VReg 的 registry callback 会拦截请求把原本的虚拟路径替换成宿主机上的真实路径再转交给 Configuration Manager 继续处理。更关键的是书里直接举了一个例子某个 Centennial 应用看起来是在创建HKCU\Software\Microsoft\AppA但 Configuration Manager 真正看到并创建成功的其实是\Registry\WC\GUIDuser_sid\Software\Microsoft\AppA而应用本身几乎感觉不到差异。所以这篇文章我就专门把10.1.24 Registry virtualization讲透。这一节最核心的一句话就是容器里的应用“以为”自己在写 HKCU / HKLM本质上只是写了一个虚拟命名空间入口真正落地时VReg 和 Configuration Manager 会把它重定向到\Registry\WC\GUID...这类容器专属路径必要时再叠加 differencing hive 与 base layer 的合并视图。1. 先说结论Registry virtualization 本质上是“给容器应用一套假的入口给系统一套真的落点”如果只用一句话总结这一节我会这样说Registry virtualization 的核心不是把注册表“复制一份”给容器而是给容器应用保留熟悉的 HKCU / HKLM 视图再由底层把这些访问重定向到\Registry\WC和 differencing hive 上。书里明确说registry virtualization 从 Windows 10 RS1 开始支持Argon和Helium容器这套机制由Configuration Manager和VReg driver共同提供两大核心服务分别是Namespace redirectionRegistry merging这意味着容器注册表并不是简单的“权限隔离”而是命名空间先改道数据视图再合并。2. 为什么 Windows 需要 registry virtualization因为容器不能真的直接改宿主机那棵全局注册表这个问题特别值得先想清楚。如果没有 virtualization那么容器里的应用一旦真写宿主机的HKCUHKLMHKLM\Software\Classes那容器隔离基本就失去意义了。书里给出的做法非常明确VReg 会在容器场景下提供namespace redirection允许把一个“虚拟 key”的内容定向到宿主机上的真实 key或者定向到一个differencing hive里的 key而 differencing hive 又会被 merge 到宿主机某个 root key 上。这说明 Windows 的目标不是禁止应用继续使用熟悉的注册表路径而是让应用继续“以为”自己在用熟悉路径同时把真正写入行为导向容器私有层。所以 registry virtualization 解决的不是“能不能访问注册表”而是“访问注册表时到底写到哪一层”。3. 两个关键词先记住Namespace redirection 与 Registry merging这一节最好先把这两个核心词吃透。3.1 Namespace redirection书里明确写到应用可以把一个virtual key的内容重定向到宿主机上的真实 key也可以把 virtual key 重定向到 differencing hive 里的 key。也就是说路径本身先被“改道”。3.2 Registry merging书里又接着说differencing hives 会被解释成base hive 的差异集合base hive 是Base Layer它提供的是Immutable registry viewdifferencing hive 里的键可以是新增也可以是减去后者就是thumbstone keys。也就是说真正给应用返回结果时并不只是“去某个地方读”而是先看差异层再看基础层最后把结果合成一份看起来统一的注册表视图。所以容器注册表不是“一个位置”而是“重定向路径 差异层 基础层”三者共同产生的视图。4.\Registry\WC到底是什么为什么容器场景里它这么关键这一节最值得硬记的路径就是\Registry\WC书里说得非常清楚Configuration Manager 在 phase 1 初始化时会创建VRegDriver device object同时创建VRegConfigurationContext object type用来表示属于容器的Silo context当应用初始化 namespace redirection 时VReg 会先创建一个 namespace node把容器里的\Registry\WCroot key重映射到宿主机上的 key而\Registry\WCroot key就是专门为mount 所有虚拟化 hive准备的。这句话特别重要因为它说明在容器场景里注册表已经不再只是\Registry\Machine和\Registry\User的世界\Registry\WC是 Windows 给容器注册表专门准备出来的新根。这其实和前面 namespace 那一节完全能接上普通应用路径会进入\Registry\Machine/\Registry\UserApplication hive 会进\Registry\A\GUID容器虚拟化 hive 则会挂到\Registry\WC。5. 应用到底是怎么被“悄悄改道”的关键在 VReg 的 registry callback这部分和上一节 Registry filtering 是正好接起来的。书里明确说VReg driver is a registry filter driver它使用的是registry callbacks mechanism在第一次初始化 namespace redirection 时VReg 会注册自己的主回调例程类似CmRegisterCallbackEx之后容器进程发出的每一次 registry I/O都会先被这个 VReg 回调拦住。这就意味着应用不是在“调用某个容器版注册表 API”而是在走原有注册表 API 时被底层 callback 机制悄悄重写了路径。这正是“不改应用代码也能插手”的最标准例子。5.1 为什么这件事特别关键因为它说明容器注册表虚拟化的切入点不在应用层而在内核注册表操作链上。也就是说应用照常调用RegCreateKeyExRegOpenKeyExRegSetValueEx但真正到 Configuration Manager 前VReg 先把它改道了。所以 registry virtualization 的入口不是新 API而是老 API 新 callback。6. 书里那个最经典的例子为什么应用以为自己在写 HKCU系统实际却写进了\Registry\WC\GUID...这一段是整节最值得直接记住的内容。书里给出的场景非常具体某个 Centennial 应用所在的现代应用框架已经为它设置了多个 namespace redirection其中有一个 redirection node把HKCU映射到了宿主机上的\Registry\WC\GUIDuser_sid某一时刻应用想在HKCU\Software\Microsoft下面创建一个新 keyAppA当进程调用RegCreateKeyEx时VReg callback 会拦截请求然后从 job 的 configuration context 中查找最接近当前路径的 namespace node找到以后就把原来虚拟路径的父部分替换成宿主机上的真实 parent host key name再把改写后的请求转交给 Configuration Manager。书里随后直接给出结论在这个例子里Configuration Manager 真正看到并成功创建的是\Registry\WC\GUIDuser_sid\Software\Microsoft\AppA而容器化应用本身几乎感觉不到差别从它的视角看这个 key 仍然像是在宿主机 HKCU 里。这几乎就是这节的题眼。应用调用 RegCreateKeyEx: HKCU\\Software\\Microsoft\\AppAVReg callback 拦截从 silo configuration context 找到最接近的 namespace node把虚拟父路径替换成 host key改写为 \\Registry\\WC\\user_sid\\Software\\Microsoft\\AppAConfiguration Manager 继续正常处理应用侧几乎感觉不到差异这说明应用看见的是“虚拟命名空间”Configuration Manager 处理的却是“容器专属真实命名空间”。7. differencing hive 为什么是容器注册表的另一半灵魂如果只有 namespace redirection这套机制还不完整。因为“改道”只解决了路径去哪没解决“如何在不破坏基础层的前提下覆盖它”。这时候differencing hive就出来了。书里明确说differencing hives 使用1.6格式应用可以把 differencing hive 挂载到系统全局或某个 silo 容器里挂载时需要提供base key也叫 base layerdifferencing hive 路径mount point最终 mount point 上看到的是differencing hive 数据 base layer 数据的 merge 结果。7.1 为什么这特别像现代容器层因为它的思路和容器镜像层特别像base layer只读基础层differencing layer可写差异层最终视图两层叠加的合成视图这就让容器里的应用能做到看上去在写系统注册表实际只改了自己的差异层没有直接污染宿主机基础层。所以容器注册表不是“复制一份完整注册表”而更像“基础层 覆盖层”的联合视图。8. Configuration Manager 读取 differencing hive 时到底先看哪一层这一段书里写得非常清楚而且特别适合直接变成排障思维。它说当请求命中 mount point 或其子路径时Configuration Manager 会知道对应的 KCB 代表的是 differencing hive于是解析过程会先从 differencing hive 开始如果在 differencing hive 里找到了 subkey 或数据就直接返回那里的内容如果没找到才重新从 base hive 开始解析。这就意味着差异层优先基础层兜底。这是一条特别重要的规则。8.1 为什么这个规则特别重要因为它决定了容器里应用“看见什么”。如果差异层里已经有某个 key/value那应用看到的就是差异层版本只有差异层里没有才会回退到 base layer。所以以后你遇到容器里“这个值明明基础层有但应用看到的不是那个”的场景就应该第一反应想到是不是 differencing hive 已经覆盖掉了。9. Thumbstone key 是什么为什么它能让基础层里的 key “看起来不存在”这一节里还有一个特别值得记住的词thumbstone key书里明确说differencing hive 里的 key 不只是“新增”也可以表示“删除”这种表示删除语义的就是thumbstone keys当 Configuration Manager 在 differencing hive 里碰到 thumbstone key 时它会把目标 key 隐藏起来并返回no data 或 error即使这个 key 在 base hive 里原本是存在的。这点特别有力量因为它说明差异层不仅能盖住基础层的“新内容”还能盖住基础层的“旧内容”。也就是说容器里应用“看不到某个 key”并不一定说明基础层真的没有可能只是差异层明确标记“这个 key 被删除了”。所以 thumbstone key 的本质是“逻辑删除覆盖”不是物理删除基础层数据。10. 从桌面支持和系统学习视角这一节到底有什么现实价值很多人会觉得容器注册表离桌面支持很远。其实不远我觉得至少有 4 个现实价值。10.1 它帮我真正理解“应用看到的路径”和“系统处理的路径”可以完全不同这件事前面 symbolic link、namespace、filtering 已经铺垫过很多次。到了 virtualization这种“表里不一”达到了更极致的程度应用觉得自己在 HKCU / HKLMConfiguration Manager 实际看到的是\Registry\WC\GUID...。10.2 它帮我理解现代打包应用为什么经常“不改老代码也能跑进隔离环境”因为系统根本没有逼应用换注册表 API而是用底层 callback namespace redirection 把旧代码接进新命名空间。10.3 它帮我理解 differencing hive 为什么像“注册表 overlay”这和容器镜像层的思路非常像先看覆盖层没有再看基础层遇到 thumbstone 就把基础层隐藏掉。10.4 它帮我理解为什么有些场景下只看宿主机 HKCU / HKLM 根本解释不了应用行为因为应用真正命中的可能是\Registry\WCdifferencing hivebase layer 合并视图这时候如果还只盯着 Regedit 里的传统根键就很容易误判。11. 最容易误解的 6 个点我帮你一次理顺11.1 误区一registry virtualization 就是“多一份容器注册表副本”不对。它更准确地说是namespace redirection registry merging。11.2 误区二应用必须改代码才能适配容器注册表不对。VReg callback 正是为了在不改应用代码的前提下拦截并改写路径。11.3 误区三\Registry\WC只是个普通字符串前缀不对。它是为 silo 容器虚拟化 hive 挂载专门准备的 root key。11.4 误区四differencing hive 只能“加东西”不能“减东西”不对。它既能表示新增也能通过 thumbstone key 表示逻辑删除。11.5 误区五基础层里有数据应用就一定能看到不对。如果差异层已经有同名数据或 thumbstoneConfiguration Manager 会优先按差异层解释。11.6 误区六容器里的注册表虚拟化只是应用层框架的小把戏也不对。书里明确说这套能力是由Configuration Manager和VReg driver在内核级共同提供的。12. 我的学习理解这一节真正教会我的是“虚拟化的本质不是复制世界而是重写入口与视图”我觉得10.1.24 Registry virtualization最厉害的地方不是让我多记一个\Registry\WC而是让我真正意识到Windows 做虚拟化并不一定要复制一整套真实世界出来。它完全可以用另外一种更聪明的方式保留应用熟悉的入口在底层重写命名空间再用 differencing hive 和 base layer 拼出最终视图。这其实是一种非常典型的 Windows 工程风格不强迫上层改思维模型而是在下层重写解释规则。所以这一节我最想记住的一句话就是容器注册表虚拟化不是“再造一个 HKCU/HKLM”而是“保留原入口改写真实落点”。13. 总结提升如果让我用一句话总结《Windows Internals》10.1.24 Registry virtualization我会这样说容器里的应用之所以明明以为自己在写 HKCU / HKLM而 Configuration Manager 实际看到的却是\Registry\WC\GUID...本质上是因为 Windows 在底层用 VReg 的 registry callback 机制对注册表路径做了 namespace redirection再借 differencing hive 和 base layer merging 生成最终视图应用保留的是熟悉入口系统真正控制的是命名空间和差异层。这篇最值得记住的 9 个结论是Windows 10 RS1 引入了 registry virtualization用于 Argon 和 Helium 容器。这套能力由 Configuration Manager 和 VReg driver 共同提供。核心能力分成 namespace redirection 和 registry merging。\Registry\WC是为 silo 容器挂载虚拟化 hive 准备的 root key。VReg 是 registry filter driver会注册 registry callback 来拦截并改写容器进程发出的注册表 I/O。书里的例子表明应用以为自己创建的是HKCU\Software\Microsoft\AppAConfiguration Manager 实际创建的却是\Registry\WC\GUIDuser_sid\Software\Microsoft\AppA。differencing hive 会与 base layer 合并Configuration Manager 解析时会优先看 differencing hive再回退到 base hive。thumbstone key 用来表示“删除基础层中的 key”即使 base hive 里原本存在也会被隐藏。registry virtualization 的本质不是复制注册表而是重定向入口、叠加差异层并给应用返回一个看起来仍然熟悉的逻辑视图。我觉得这一节最值得沉淀成自己一句话的理解就是应用看到的是“虚拟入口”Configuration Manager 处理的是“真实容器命名空间”中间那层把两者接起来的就是 VReg 的路径重写和 differencing hive 的视图合成。下一篇预告《Windows Internals》10.1.25 Reliability为什么注册表不是“写进去就完了”而是从 base block 序列号、增量日志到恢复流程都在围绕“崩溃后还能回来”做设计》recoverable statebase block 两个 sequence numberhive logincremental loggingReconcilercrash recovery全部串起来。返回顶部

更多文章