Detecting registry virtualization

2019-03-09 19:29发布

I have a set of C# (v2) apps and I am struggling with registry virtualization in Win7 (and to a lesser extent Vista).

I have a shared registry configuration area that my applications need to access in HKLM\Software\Company... Prior to Vista, everything was just written to and read from that location as needed.

The code appropriately detected failures to write to that registry key and would fall back appropriately (writing to HKCU instead and notifying the user that the settings they had applied would only affect the current user).

In Vista, registry virtualization broke all of this because the access check we were using for the HKLM write would "succeed" silently and virtualize to HKCR\VirtualStore\Machine... instead. In this case, the user would think that they had saved machine-wide configuration, but had instead only written to the virtual store.

Sadly, even attempting to enumerate the permissions on the HKLM reg key explicitly returns results indicating that the user has access whether they do or not.

When we added Vista support, the workaround we used was to perform a probe write to HKLM... and then check in HKCR\VirtualStore\Machine... for the same value and note that virtualization had occurred if the value was found.

Win7 seems to have broken this (again) because queries against the explicit virtual location (HKCR) now show merged results from the HKLM location even if the write was not virtualized.

Does anyone have any suggestions for working around this?

Constraints: - I need a solution that works without requiring elevation (when I don't have administrator level permissions I will fallback to a per-user configuration in HKCU but I need to be able to detect this case reliably).

  • It needs to work with a v2 C# app (One option I have seen for C++ code is to embed a manifest which disables virtualization for the .exe but I haven't been able to do that in C# V2 see disable folder virtualization in windows).

  • It needs to work without an "installer" (this precludes the ability to disable virtualization on the registry key that we need ala the REG FLAGS... command).

4条回答
男人必须洒脱
2楼-- · 2019-03-09 19:57

I had a similar problem and the introduction of a manifest solved it.

I was relying on the registry security to prevent the (Win32) application from creating keys in the HKLM/Software/Wow6432Node when running as standard user, and was quite surprised to see that it was succeceding regardless, but no key was present and it was created instead under this new VirtualStore area.

The registry virtualization is switched off when the PE manifest is found to contain information related to the security. To not require elevation of privileges my manifest contains the following node:

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

For the executable to be compatible with Vista and XP, apparently each node in the TrustInfo section must contain the namespace:

<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>

Once the manifest was correctly embedded in my .exe (it took me a couple of attempts by modifying the appropriate properties of the project), the program was at last failing as I was expecting.

For managed code, the manifest can be included as a post-build step by running the mt.exe tool. For instance, as reported in the MSDN article

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

I prefer using the manifest approach rather than modifying the flags of the registry nodes using reg.exe as explained in this article as this makes the behaviour consistent on all machines.

Hope that helps (even if, after having read the date of the original posting, I'm pretty sure the problem has been solved long ago!!)

Alberto

查看更多
男人必须洒脱
3楼-- · 2019-03-09 20:00

You can enable / disable virtualization on a per key basis, according to this, but it tells you to use a command line tool. But there must be a way to do it programmatically.

It might be easiest just to turn off virtualization in your app completely by setting requestedExecutionLevel in your manifest. You can try highestAvailable, but that might mean your app always runs as Administrator. It seems to imply just setting it to asInvoker will turn off virtualization. See also.

查看更多
够拽才男人
4楼-- · 2019-03-09 20:02

Note that HKCR is a virtualized store itself, a combination of HKLM\Software\Classes and HKCU\Software\Classes.

The best approach would be to not even let the registry virtualization take place. Firstly check to see the user is is elevated at runtime and then you can notify the user that changes will only be applied to the current user before they even start making changes.

By detecting if you are an elevated administrator in the first place you can simply avoid writing to HKLM when it's going to be virtualized.

Example:

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

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

Note: I don't code in C#, example is lifted from question How can I detect if my process is running UAC-elevated or not?

查看更多
叼着烟拽天下
5楼-- · 2019-03-09 20:07

This is an excellently put question, +1 (Why is it community wiki, it deserves points!)

In general, there are a set of rules (which [as you've run into] will vary over time) which control whether UAC [and thus implicitly Registry] virtualization are in play.

Some salient parts of the Registry Virtualization rulesets documentation in MSDN are:

  1. [as jeffamaphone says] if the manifest has a requestedPrivileges/requestedExecutionLevel set, it's turned off. You dont seem to have ruled out adding a manifest, so can you please indicate why this won't work for you? (You say "I haven't been able to do that in C# V2" - there is an Add Item option to add an application manifest file, and that's available in VS2005)
  2. if the exe is running 64 bit, its off by default
  3. if it's not an interactive process (such as a service, or hosted in IIS etc.), it's off

If you're not in a position to influence any of the above, which is the ideal, and you thus want to detect whether UAC virtualisation applies in the current context, use this answer to a what might at first not appeat to be a related question. (Obviously you'd still need to decide whether it applies to the specific key you're operating on, which is a moving target which you obviously wouldnt want to implement code that needs to track changes if it can at all be avoided - but in most cases it should be relatively clear.)

查看更多
登录 后发表回答