检测注册表虚拟化

时间:2009-06-16 16:54:08

标签: windows-7 registry c#-2.0 virtualization uac

我有一套C#(v2)应用程序,我在Win7(以及较小程度上的Vista)中使用注册表虚拟化很困难。

我有一个共享的注册表配置区域,我的应用程序需要在HKLM \ Software \ Company中访问...在Vista之前,所有内容都只是根据需要写入并从该位置读取。

代码正确地检测到写入该注册表项的失败并且会适当地回退(写入HKCU而不是通知用户他们应用的设置只会影响当前用户)。

在Vista中,注册表虚拟化破坏了所有这一切,因为我们用于HKLM写入的访问检查将“成功”静默并虚拟化为HKCR \ VirtualStore \ Machine ...而不是。在这种情况下,用户会认为他们已经保存了机器范围的配置,而只是写入了虚拟商店。

可悲的是,即使尝试枚举HKLM reg键的权限,也会显式返回表明用户是否有权访问的结果。

当我们添加Vista支持时,我们使用的解决方法是执行对HKLM的探测写入...然后在HKCR \ VirtualStore \ Machine ...中检查相同的值并注意如果值为找到。

Win7似乎已经破坏了这一点(再次),因为针对显式虚拟位置(HKCR)的查询现在显示来自HKLM位置的合并结果,即使写入未被虚拟化。

有没有人有解决这个问题的建议?

约束:   - 我需要一个无需提升即可运行的解决方案(当我没有管理员级权限时,我将回退到HKCU中的每用户配置,但我需要能够可靠地检测到这种情况)。

  • 它需要使用v2 C#应用程序(我看到的C ++代码的一个选项是嵌入一个禁用.exe虚拟化的清单,但我无法在C#V2中看到它disable folder virtualization in windows)。

  • 它需要在没有“安装程序”的情况下工作(这排除了在我们需要REG FLAGS ...命令的注册表项上禁用虚拟化的能力。)

4 个答案:

答案 0 :(得分:10)

这是一个非常好的问题,+ 1(为什么它是社区维基,它值得分!)

一般来说,有一套规则(随着时间的推移会随着时间的推移而变化)控制UAC [以及隐含的注册表]虚拟化是否在起作用。

Registry Virtualization rulesets documentation in MSDN的一些显着部分是:

  1. [如jeffamaphone所说]如果清单设置了requestedPrivileges / requestedExecutionLevel,则关闭它。您似乎没有排除添加清单,所以,请您说明为什么这对您不起作用? (你说“我在C#V2中无法做到这一点” - 有一个Add Item选项可以添加应用程序清单文件,并且可以在VS2005中使用)
  2. 如果exe运行64位,则默认关闭
  3. 如果它不是一个交互式进程(例如服务,或者在IIS等中托管),它就会关闭
  4. 如果您无法影响上述任何一项(理想情况),并且您希望检测UAC虚拟化是否适用于当前上下文,请使用this answer to a what might at first not appeat to be a related question。 (显然你仍然需要决定它是否适用于你正在操作的特定密钥,这是一个移动目标,你显然不希望实现需要跟踪变更的代码,如果它可以完全避免 - 但是大多数情况下应该比较清楚。)

答案 1 :(得分:2)

根据this,您可以基于每个键启用/禁用虚拟化,但它会告诉您使用命令行工具。但必须有一种方法可以以编程方式进行。

通过在清单中设置requestedExecutionLevel,最简单的方法就是完全关闭应用中的虚拟化。您可以尝试使用highestAvailable,但这可能意味着您的应用始终以管理员身份运行。这似乎暗示只是将其设置为asInvoker将关闭虚拟化。请参阅also

答案 2 :(得分:0)

请注意,HKCR是虚拟商店本身,是HKLM\Software\ClassesHKCU\Software\Classes的组合。

最好的方法是不要让注册表虚拟化发生。首先检查用户是否在运行时被提升,然后您可以通知用户更改将仅在他们开始进行更改之前应用于当前用户。

通过首先检测您是否是高级管理员,您可以简单地避免在要进行虚拟化时写入HKLM。

示例:

private bool IsAdministrator
{
    get
    {
        WindowsIdentity wi = WindowsIdentity.GetCurrent();
        WindowsPrincipal wp = new WindowsPrincipal(wi);

        return wp.IsInRole(WindowsBuiltInRole.Administrator);
    }
}

注意:我不在C#中编码,示例是从问题How can I detect if my process is running UAC-elevated or not?取消

答案 3 :(得分:0)

我有一个类似的问题,并且清单的介绍解决了它。

我依赖注册表安全性来阻止(Win32)应用程序在以标准用户身份运行时在HKLM / Software / Wow6432Node中创建密钥,并且非常惊讶地看到它无论如何都成功,但没有密钥存在它是在这个新的VirtualStore区域下创建的。

当发现PE清单包含与安全性相关的信息时,注册表虚拟化将关闭。为了不要求提升权限,我的清单包含以下节点:

<trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
   <security>
      <requestedPrivileges>
         <requestedExecutionLevel level="asInvoker">
         </requestedExecutionLevel>
      </requestedPrivileges>
   </security>
</trustInfo>

要使可执行文件与Vista和XP兼容,显然TrustInfo部分中的每个节点都必须包含命名空间:

<ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
   <ms_asmv2:security>
      <ms_asmv2:requestedPrivileges>
         <ms_asmv2:requestedExecutionLevel level="asInvoker">
         </ms_asmv2:requestedExecutionLevel>
      </ms_asmv2:requestedPrivileges>
   </ms_asmv2:security>
</ms_asmv2:trustInfo>

一旦清单正确嵌入到我的.exe中(通过修改项目的相应属性,我花了几次尝试),程序最终失败了,就像我期待的那样。

对于托管代码,可以通过运行mt.exe工具将清单包含为构建后步骤。例如,如MSDN article

中所述
mt.exe –manifest YourFile.manifest –outputresource:YourApp.exe;#1

我更喜欢使用清单方法而不是使用reg.exe来修改注册表节点的标志,如this article中所述,因为这会使所有计算机上的行为保持一致。

希望有所帮助(即使在阅读了原始帖子的日期之后,我很确定问题早已解决了!)

阿尔贝托