Using VirtualRegistry to Redirect Registry Keys on Windows Vista

I posted earlier on using VirtualRegistry to provide version lies when an application is looking for the version of the operating system in the registry instead of using one of the GetVersion APIs. I could go on and on about all of the other command line arguments that do interesting things, but that is actually the subject of a forthcoming update to the help file itself, so I'm going to focus on the interesting ones here.

Probably the most interesting one is the command line argument that allows you to redirect any one key to any other key. Why is this one so compelling? Because it can resolve almost every issue you could possibly come across.

You see, the rest of the command line arguments do specific fixes. They can pretend that certain keys exist, and that they have certain values. They can redirect registry keys to other places. But you have to get lucky and happen to find one that is redirecting the keys you need to a place that works for you. In the case of version lies, this is something that comes up quite a lot, and you can completely re-use that. There are command line arguments around various versions of DirectX and codecs, all of which either redirect or pretend.

But redirection can be a form of pretending. If you want the version to say 5.0, but it says 6.0, if you know the command line NT50 that's a very effective way to do that. But, what if you didn't know this command line (which until recently is probably the case)? What if there is an existing command line for a problem you have, but you don't happen to know that one, and I haven't talked about that yet? You can achieve the same effect using redirection.

For installation, I simply repackage the application so I create a new key that contains the value 5.0. I redirect the key I'm looking for, say HKEY_LOCAL_MACHINESoftwareMicrosoftWindows NTCurrent Version, to HKEY_LOCAL_MACHINESoftwareMy CompanyVendorAppNt Current Version, and then populate that key with the value of 5.0. I then redirect to this new key, and voila - I get the same version lie.

Yes, it requires me to drop a key, but you can see that I can create whatever I need, and use redirection both for redirecting to user-writeable locations as well as lying about existing values (which don't need to be user-writeable necessarily).

That being said, what's the command line to use?


If you have multiple keys to redirect from and to, then you can just chain them together, separating each with the caret (^) symbol.

With this fix, there should be almost no registry issue you can't resolve somehow, as long as you don't limit your thinking on what a redirect is supposed to do. Remember, you can always repackage if you need to add some new values to redirect to.

Now, I mentioned earlier that you can resolve almost any issue that you could possibly run across. Why didn't I just say every issue?

Partially because I doubt that my own creativity can rival the combined creativity of the rest of the software developers in the world for coming up with registry issues that could cause problems in terms of application compatibility.

Also, there is a limitation to how much you can redirect. In fact, the sheer scope and power of what you can do with VirtualRegistry is not completely exposed because of one simple limitation: the number of characters the Windows Shim Infrastructure supports in a command line argument. It's simply not long enough. So, the developers on the Windows team would implement the things they needed in code (no limitation there) and assign a name to it that was nice and short, this name either being the name of the application or component, or the nature of the problem.

You may bump into the same thing, if you have a host of keys to redirect. In which case, then you may want to browse the forthcoming documentation to see if perhaps an existing command line argument will cause the keys you need redirected or lied about. Personally, I haven't experienced this problem with a customer, but it could potentially happen.

Nonetheless, you can take this incredibly powerful shim, and this incredibly flexible command line argument, and resolve a host of registry-related issues on Windows Vista.

Comments (16)

  1. Sean says:

    I own a DV6000 With the nean to

  2. I figured this day would come, and to be honest, I’m a little bit surprised it took as long as it did

  3. Shruti says:

    hi Chris,

    I have a doubt on Vista Registry, I had tried to search for ‘machine wide common registry hive location where all "Standard Users" can read/write to’ however I was not able to come to a conclusion.


  4. Tenchuu says:


    I’m still having problems with the Syntax, I’ve seen that it should work with these Parameters:

    ADDREDIRECT(HKLMSoftwareWhatever^HKCUSoftwareWhatever) but it doesn’t work in my case.

    I’m trying to fake the Timezone Registry Key with this, so I change the parameter to:


    I’m testing it with an application which reads the StandardName Key and it always uses the original one. Therefore it’s not redirected.

    Am I doing something wrong?

  5. cjacks says:

    Hi Tenchuu,

    What OS are you using this on? If you capture the interaction with process monitor, what is the stack when you’re reading this key?



  6. Tenchuu says:

    Hi Chris,

    I’m using this currently on a XPSP2 machine for testing purposes, but it’s planned to run on a 2K3 machine.

    This key: HKLMSystemCurrentControlSetControlTimeZoneInformationStandardName

    This stack:

    "0","ntoskrnl.exe","ntoskrnl.exe + 0x806b","0x804df06b","C:WINDOWSsystem32ntoskrnl.exe"

    "1","advapi32.dll","advapi32.dll + 0x7054","0x77dd7054","C:WINDOWSsystem32advapi32.dll"

    "2","AcLayers.dll","AcLayers.dll + 0x2cc20","0x715bcc20","C:WINDOWSAppPatchAcLayers.dll"

    "3","AcLayers.dll","AcLayers.dll + 0x2cf73","0x715bcf73","C:WINDOWSAppPatchAcLayers.dll"


    "5",""," + 0x2a5538","0x79365538",""



  7. cjacks says:

    Hi Tenchuu,

    The ADDREDIRECT command line argument is new for Windows Vista – it’s not there in XPSP2 or Server 2003. Also, as a general practice, you should make the shim database on the platform you intend to deploy to, as CompatAdmin just offers you the shims on the system it’s running on, and there could be differences between operating systems.



  8. John says:

    Hi Chris,

    I am working with an application that will only work if the end user has Full Control of the following registry key:


    In my environment, end users may only have read access to all keys under CurrentControlSet, so I created a shim that would redirect this key to:

    [HKEY_LOCAL_MACHINESoftwareSrvRedirectServicesSrvName], which I added ahead of time.

    In my environment, end users may have full rights to keys under HKEY_LOCAL_MACHINESoftware, so I thought this would be a good location, and even if they didn’t, Vista registry virtualization could handle it.

    The shim I used was VirtualRegistry, and here is the command line:


    I also tried:


    Neither worked, and I was wondering if you had any ideas why not?



  9. I’ve written about the perils of non-deterministic finalization before: It is a guaranteed way to get

  10. cjacks says:

    John –

    Which OS are you using? Does they key you’re redirecting to exist?

    You should be able to see everything that’s happening in Process Monitor, since shims happen in user mode and it runs in kmode it isn’t fooled by our trickery…


  11. John says:

    Hey Chris,

    I am running Windows Vista Enterprise SP1, and the key I am redirecting to does exist – I set it up as such before I created the shim.  Using Process Monitor, I am able to see that the key I am attempting to redirect is still showing ACCESS DENIED, even after installing the shim.

    Another interesting thing – I set up logging to see if there were any clues there, and when I run the program and the exe is invoked, no log for the shim is created.  However, as a test to be sure I had my syntax correct, I built a dummy VirtualRegistry shim for a different application altogether (that didn’t even really need a shim) and the shim worked perfectly and the log showed success.  This redirection was from HKLMsoftware, not HKLMsystem – could this be the cause? Any other ideas?



  12. cjacks says:

    Hi John,

    What’s the stack on the ACCESS DENIED in ProcMon?


  13. John says:

    Thanks Chris,

    Here are the stack details:

    0 ntkrnlpa.exe ntkrnlpa.exe + 0x2578d5 0x820638d5 C:Windowssystem32ntkrnlpa.exe

    1 ntkrnlpa.exe ntkrnlpa.exe + 0x2140a5 0x820200a5 C:Windowssystem32ntkrnlpa.exe

    2 ntkrnlpa.exe ntkrnlpa.exe + 0x2462ff 0x820522ff C:Windowssystem32ntkrnlpa.exe

    3 ntkrnlpa.exe ntkrnlpa.exe + 0x21dfea 0x82029fea C:Windowssystem32ntkrnlpa.exe

    4 ntkrnlpa.exe ntkrnlpa.exe + 0x1e7a83 0x81ff3a83 C:Windowssystem32ntkrnlpa.exe

    5 ntkrnlpa.exe ntkrnlpa.exe + 0x1e7b53 0x81ff3b53 C:Windowssystem32ntkrnlpa.exe

    6 ntkrnlpa.exe ntkrnlpa.exe + 0x57a7a 0x81e63a7a C:Windowssystem32ntkrnlpa.exe

    7 ntdll.dll ntdll.dll + 0x58054 0x779f8054 C:WindowsSystem32ntdll.dll

    8 <unknown> 0x768dbf26 0x768dbf26

    9 <unknown> 0x768dbc91 0x768dbc91

    10 <unknown> 0x768dbd08 0x768dbd08

    11 win32k.sys win32k.sys + 0xd860f 0x8156860f C:WindowsSystem32win32k.sys

    12 win32k.sys win32k.sys + 0xd854f 0x8156854f C:WindowsSystem32win32k.sys

    13 win32k.sys win32k.sys + 0xd74a7 0x815674a7 C:WindowsSystem32win32k.sys

    14 win32k.sys win32k.sys + 0x92778 0x81522778 C:WindowsSystem32win32k.sys

    15 win32k.sys win32k.sys + 0x866ed 0x815166ed C:WindowsSystem32win32k.sys

    16 win32k.sys win32k.sys + 0xad674 0x8153d674 C:WindowsSystem32win32k.sys

    17 ntkrnlpa.exe ntkrnlpa.exe + 0x57a7a 0x81e63a7a C:Windowssystem32ntkrnlpa.exe

    18 <unknown> 0x76d38871 0x76d38871

    19 <unknown> 0x76d34ab8 0x76d34ab8

    20 <unknown> 0x76d40afa 0x76d40afa

    21 <unknown> 0x76d64b0b 0x76d64b0b

    22 <unknown> 0x76d64c0b 0x76d64c0b

    23 <unknown> 0x76d547f2 0x76d547f2

    24 <unknown> 0x76d42d2b 0x76d42d2b

    25 <unknown> 0x76d3f8d2 0x76d3f8d2

    26 <unknown> 0x76d3f794 0x76d3f794

    27 <unknown> 0x76d406f6 0x76d406f6

    28 <unknown> 0x76d4ba01 0x76d4ba01

    29 <unknown> 0x1001fa28 0x1001fa28

    30 <unknown> 0x1001feed 0x1001feed

    31 <unknown> 0x1001f012 0x1001f012

    32 <unknown> 0x1001f22d 0x1001f22d

    33 <unknown> 0x76d3f8d2 0x76d3f8d2

    34 <unknown> 0x76d3f794 0x76d3f794

    35 <unknown> 0x76d40008 0x76d40008

    36 <unknown> 0x76d40060 0x76d40060

    37 <unknown> 0x76d2af07 0x76d2af0

    38 <unknown> 0x76d417e4 0x76d417e4

    Here are the event details:

    Class: Registry

    Operation: RegOpenkey


    Path: HKLMSystemCurrentControlSetServicesGzTpParam

    Desired Access: Read/Write, Write DAC



  14. cjacks says:

    Wow. That is the most unhelpful stack I have ever seen. It doesn’t even have the API in question showing up in the stack. My guess is that you don’t have symbols set up for this guy, which would be helpful.

    Here’s what I’m going for: by default, we exclude all files in system32 from the shim enginge. That means that if the caller of the API is in system32, the shim won’t be applied. I was trying to see who the caller was. Most frequently, this is the case when using VB6 or earlier code, since it goes through the VB runtime, and that lives in system32 (and, hence, isn’t shimmed). The solution is to just add that module to the include list.

    If you want to do a quick test to see if that’s the problem, go into the paramters of the VirtualRegistry shim, and add * to the included modules – that’ll get everything. If that fixes it, that’s the problem (and hence it’d be worth your time to sort out which module is actually calling it, because include * can really be a drag on perf for the app).

    Oh, and just so you know, this is ACCESS DENIED on HKLMSystemCurrentControlSetServicesGzTpParam – did you copy/paste this or type it? Because there’s an extra between CurrentControl and Set.



  15. John says:


    With your help I have now got it working.  I did as you suggested:  I added the * to get all the modules and my shim started working right away.  Then, knowing my command line was correct, I was able to use Process Monitor to determine which specific module I needed.  I’ve replaced the * with that module and now everything is working great.

    Thanks again for your help with this one.  I know I’ll have a bunch more to do just like this so the education is extremely valuable.

    Great site!



Skip to main content