Side-by-side components the other way
Important This article contains information about modifying the registry. Before you modify the registry, make sure to back it up and make sure that you understand how to restore the registry if a problem occurs. For information about how to back up, restore, and edit the registry, click the following article number to view the article in the Microsoft Knowledge Base:
256986 Description of the Microsoft Windows Registry
Abstract
Ever wanted to run some legacy Access 97 application side by side with the latest Microsoft Office suite? Or ever wondered why you cannot install different versions of some applications at the same time on your machine? Then the following will be interesting for you, because in this article I will present a method on how to virtualize the Windows registry on an application (process) basis. You can do it with AppShadow.
By this means you could host multiple versions of otherwise mutual exclusive applications or components on the same machine at the same time. Moreover you can circumvent shortcomings in applications that are normally not meant to be run in a Terminal Server environment.
In order to get the most out of this article some know-how about
- Windows Terminal Server
- Windows DLLs
- Windows API programming
is absolutely recommended. If you do not like changing system settings or are not sure what you are doing please stop reading and do not waste your time reading this article.
Background
When running in a Terminal Server environment, every user receives its own copy of user specific registry settings (where one normally has full access, KEY_ALL_ACCESS). These settings reside in a hive called HKEY_CURRENT_USER (HKCU for short, physically stored in "%USERPROFiLE%ntuser.dat"). To ease the propagation of changes Windows implements a mechanism called "Shadowing" (from which I borrowed the name AppShadow). The shadow registry is a special registry tree that can be seen as a layer on top of the user’s settings. Each entry in the shadow area corresponds to an entry in HKCU:
Picture: Mapping between shadow area and HKCU
Click to show picture
Every time a user requests a key or value from its HKCU, Windows looks into the "shadow registry" or "shadow area" first if there is a (newer) entry. If available, this entry will be copied to the user’s location – eventually overwriting existing older entries. To determine if entries in the shadow area are newer than those already present in HKCU Windows compares the last write time (a FILETIME structure) of both keys. For some information about editing the access time on registry keys see RegTimeStamp. The shadow area is currently defined at the following registry key: HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionTerminal ServerInstall
Machine wide settings are kept in a different area, HKEY_LOCAL_MACHINE (HKLM). Applications can define settings that are global for all users. Normally, only privileged users such as "Administrators" can change entries in this hive. Other users such as "Authenticated Users" have only read permissions, KEY_READ, on these keys. Within HKLM under the key called SOFTWARE (physically stored in "%SYSTEMROOT%system32configsoftware") there is a subkey called Classes that can be referred to as HKEY_CLASSES_ROOT (HKCR).
Picture: Mapping between HKLMSOFTWAREClasses and HKCR
Click to show picture
In this area, system-wide registrations of components are kept (CLSIDs, ProgIds, TypeLibs and Interfaces) and among others, file associations for all users. As HKCR is a global instance it means that once, for example, a file association is defined in this place, every user on that machine has the same program that handles this association.
Beginning with Windows 2000 the operating systems tries to ease the implications of one single HKCR branch and introduces user specific software registration. From now on, every user has a private Classes key that maps transparently over HKCR, referred to as HKEY_USER_CLASSES (HKUC).
Picture: Mapping between HKCUSOFTWAREClasses and HKUC
Click to show picture
These settings are saved in a file called UsrClass.dat. The file resides in a non-roaming area of your profile: CSIDL_LOCALAPPDATA. So all changes you make are lost after you log off. Everytime a registry call to HKCR is made, the system tries to look in HKUC first. The calling application is normally unaware of this behaviour. By utilizing this feature, every user can have his different file association for documents, for example. Entries in HKUC alyways have precedence over entries in HKCR. But these settings affect all applications throughout the session. Competing applications that defines values in the same area may produce unpredictable results or simply complain that the application is not installed properly.
Though applications can seamlessly read from HKUC when actually opening keys in HKCR, they may still fail when trying to write or register components in HKCR as of insufficient (write) permissions. These requests are not remapped to HKUC! This is a major annoyance as many developers (or maybe just syntactical coders?) still open resources with KEY_ALL_ACCESS permissions while really only read access is allthey really want. (You can use Regmon from Sysinternals to see how applications open registry keys.
If you would like to know more about the registry in a Terminal Server environment, please have a look at Brian Madden’s web site:
- How Applications use the Registry in Terminal Server Environments (Part 1 of 3)
- How Applications use the Registry in Terminal Server Environments (Part 2 of 3)
Or have a look at these documents
Registry virtualization
If every process had its private copy of required registry keys and values along with all the permissions it needed to open these resources, world peace would come probably closer – at least for the average administrator or system integrator…
So what we are trying to do is the following: We build a special area of registry keys just like the "shadow area". Every time our application looks up some values, we look in that area first and see if there are values that could be returned to the application. This can be done by redirecting the registry interface of Windows:
From a Win32 programmers perspective, all registry access is implemented via the ADVAPI32 interface. ADVAPI32.DLL is a well known system DLL that is mapped into your program if it makes calls to security and registry functions. In order to virtualize the registry for arbitrary processes, we must somehow replace or redirect calls to the original ADVAPI32.DLL to our library that can redirect calls to our shadow area. So we would supply a DLL with the same name that has the same exports as the original DLL and place it into the programs directory so that our library is called before the original DLL. Unfortunately, Windows treats ADVAPI32 as a special "well known" library and thus prefers loading the real library instead of ours.
DLL redirection to the rescue!
Windows 2003 Luckily there is a feature known as "DLL redirection" within Windows 2003 that instructs the Windows Loader to search libraries in the application directory first. Just as we want it! This works by adding a special folder called APPNAME.EXE.LOCAL into the program directory and copying our library into that folder (if we wanted to redirect Winword we would replace APPNAME.EXE.LOCAL with WINDORD.EXE.LOCAL).
Picture: DLL redirection with Windows 2003
Click to show picture
By doing this our library is called before the original library and has a chance to get loaded.
Note For more information about the load mechanism in Windows, I recommend to read Matt Pietrek‘s articles about PE images (in the MSJ series "Under the Hood") or to have a look at What Goes On Inside Windows 2000: Solving the Mysteries of the Loader.
Windows 2000 Windows 2000 only supports a redirection file (for Winword it would be "WINWORD.EXE.LOCAL"). In that case, the library has to be put into the application directory – possibly affecting other applications as well.
Picture: DLL redirection with Windows 2000
Click to show picture
Apart from that, we have to tell Windows 2000 to treat ADVAPI32 as an ordinary library excluding it from KnownDLLs. So we use RegEdt32.Exe to add a value to the following entry: "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerExcludeFromKnownDlls" (REG_MULTI_SZ). You have to reboot until changes take effect.
Picture: ExcludeFromKnownDlls
Click to show picture
The export table
Finally being loaded as ADVAPI32, the only thing left is to check every registry access (function call) and to see if it should get a special "treatment". If we want to redirect the registry access to somewhere else, we do it – otherwise we just leave the call as it is and do what the real library would have done anyway. For this to happen, our library has to export the same function names as the original DLL (as I mentioned earlier). By using DumpBin.Exe with the /EXPORTS switch from the Platform SDK, for example, we can build our own export table.
Warning But be careful: Between different operating systems, the export table changes (specificially the ordinals)! That’s why we need a different version for every operating system we support (Windows 2000, Windows XP, Windows 2003).
NTFS hardlinks come in handy
After having made up what to do, we finally would like to call the original ADVAPI32.DLL from the system’s directory to redirect the registry call made by the application. But there is a problem: We told Windows we wanted a DLL redirection. So when we try to load the original library from the system directory, Windows first tries to load the library from the application directory. As this is our library, we end up in loop loading us again and again until the stack is exhausted and the loader terminates the application. What an unpleasant surprise!
Though one possible solution would be to make a copy of the original DLL and name it to something else. But every time a new update is installed on the system that copy would have to be updated as well (and you know – there are a lot of latest and greatest fixes around these days)…
This is the place where we use an NTFS hardlink, a concept that UNIX knows for a long time: a hardlink is like an alias or pointer to a different file. Every time you open the hardlink, the system opens the real file instead.
Instead of loading ADVAPI32.DLL we load our NTFS hardlink ADVAPI32.DF that we created in "%SYSTEMROOT%system32". By doing this, we avoid the naming collision and also have only a single copy of the original DLL on the system!
Note As a trade off, the program runs only on NTFS partitions but that should be no real restriction.
Implementation details
Like the shadow area from Windows we need a place where to store the virtual HKLM and HKCU settings for the applications that we want to redirect. The main place where everything starts is:
HKEY_LOCAL_MACHINESOFTWAREd-fensAppShadow
For every program you want redirection to occur, you define a mapping as seen in the picture. In this example, we define a mapping for Microsoft Access 97 Runtime (MSACCESS.EXE, full path "C:/DATEV/PROGRAMM/QSELZK97/Office/MSACCESS.EXE").
Note All "" characters have to be replaced with "/" characters!
Within the key is a REG_SZ "Index" pointing to the location where all shadow registry settings should be kept. In this case, it points to the "Access97Runtime" key below "Registry" (see the red arrow). There you have to define 2 keys: "HKLM", and "HKCU". These keys will be the application’s new HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER keys. HKCR and HKUC are consequently defined at "SOFTWAREClasses" in their respective branches. If no keys are defined, no redirection occurs.
Note You always have to define both entries (HKLM, HKCR and HKCU, HKUC) together to activate redirection. If you omit HKCR (that is the SOFTWAREClasses branch below our virtual HKLM), for example, HKLMSOFTWAREClasses and HKCR would point to different places and unpredictable results could occur. Thanks to Thomas Lehrer for clarifications on this one.
Picture: Redirected HKLM
Click to show picture
Picture: Redirected HKCU
Click to show picture
HKCU remapping
If you want to remap HKCU entries as well, AppShadow will copy all entries below "HKEY_LOCAL_MACHINESOFTWAREd-fensAppShadowRegistrySaperion-DMSHKCU" to "HKEY_CURRENT_USERSoftwared-fensAppShadowRegistrySaperion-DMSHKCU" on application startup , because the user must have write access to these keys.
Role based redirection
Picture: Role based redirection
Click to show picture
When defining access permissions on the Appname registry key, you can control for which users redirection should be active. In the shown example, you can see that only "Saperion-DMSUsers" should get a redirection of registry keys.
Per user HKLM redirection
If redirecting HKLM per process is still not enough for you might consider using the "private HKLM" feature. This is useful if application store user specific settings in HKLM (like Netscape 4 or Cashier4Windows) and you want them to separate. To enable this feature you must create the following registry key (in the same path where you create the "Index" REG_SZ):
PerUserHKLM REG_DOWRD 0x00000001
Upon start AppShadow checks if HKLM is not already defined in "HKEY_CURRENT_USERSOFTWAREd-fensAppShadowRegistry’IndexName’" and then copies all keys from "HKEY_LOCAL_MACHINESOFTWAREd-fensAppShadowRegistry’IndexName’" to this location with security set to KEY_ALL_ACCESS. If HKLM is already defined in "HKEY_CURRENT_USERSOFTWAREd-fensAppShadowRegistry’IndexName’" no keys are copied. By this you can deploy a set of individual registry keys per policy to your users.
What went wrong?
In case the redirection does not work as expected, AppShadow has built-in logging that you can use to trouble-shoot the error. Every registry call is logged via OutputDebugString(), so all you need is a debug monitor like DebugView from Sysinternals and off you go! This certainly degrades system performance, so make sure you only log when really needed!
Note When trying to log a program from a different Terminal Server session, keep in mind that the kernel objects namespace is separated. Use my OutputDebugString redirector, for example, to redirect the debug stream.
Checklist
Here is a list that you can use for checking in case something does not work as you want it:
- Setup redirection parameters in "HKLMSOFTWAREd-fensAppShadow"
- The correct version of ADVAPI32.DLL for the targeted operating system
- A redirection file APPNAME.EXE.LOCAL when running on Windows 2000
- ADVAPI32.DLL in the same directory of the program you want to redirect when running on Windows 2000
- ADVAPI32.dll put in ExcludeFromKnownDlls when running on Windows 2000 (with reboot)
- A redirection folder APPNAME.EXE.LOCAL when running on Windows 2003 or Windows XP
- ADVAPI32.DLL in a subfolder APPNAME.EXE.LOCAL of the program you want to redirect when running on Windows 2003 or Windows XP
- The correct version of ADVAPI32.DLL for the targeted operating system
- An NTFS hardlink "%SYSTEMROOT%system32ADVAPI32.DF" pointing to "%SYSTEMROOT%system32ADVAPI32.dll"
- What is logged via OutputDebugString? Does AppShadow tell you whether DLLs and exports could be loaded?
Which registry settings are needed for redirection?
Tough question. It depends on the application you want to redirect. A good thing could be to use an installation monitor that tracks changes in your registry. Import these settings into the AppShadow entry for your application and test it. Sometimes it will suffice to trace with Regmon to see what the application is doing.
Some final words
I believe that the features presented in this article should be made available by the operating system! Microsoft talks a lot about server virtualization and scalability. This would really add a benefit to Microsoft Terminal Services!
I know that some people would hesitate to use tools like AppShadow because of support or stability concerns. I do not say that this program is free of bugs but the whole mechanism is implemented in user mode. There is no reason to fear that this could crash your operating system! But, of course, I cannot take any responsibility if something works not as you expect.
When I came up with the idea for AppShadow my customer faced a problem that questioned the success of the whole project. When I first presented the workaround, he was not too pleased. But as it seemed to be the only viable option we had, he gave it a try. In the near future we discovered that we could "integrate" other misbehaving applications as well on our Terminal Servers that would not have been possible otherwise. Test and see for yourself. And of course, leave me a note if you have questions or suggestions (please mail to AppShadow at d-fens dot net).
Source: AppShadow
0 thoughts on “AppShadow: Side-by-side components the other way”
Hi gunnalag, thank you for replicating my article about AppShadow on your website. Though I originally wrote that tool back in 2003 I would be happy that you reference my name and where you copied it from. Otherwise it looks a little bit like IP fraud. Thank you very much! Regards, Ronald
Hi Ronald Rink,
Its great to hear from you in this regard. The purpose I copy the article contents is to ensure they are searchable faster to end users/myself, and we retain the valuable content should the actual article become unavailable.