Posts Tagged 'SXS'

The hidden danger of forgetting to specify %SystemRoot% in a custom environment block

When spawning a process using CreateProcess and friends, the child process usually inherits the environment (i.e. all environment variables) of the spawning process. Of course, this behavior can be overridden by creating a custom environment block and passing it to the lpEnvironment parameter of CreateProcess.

While the MSDN documentation on CreateProcess does contain a remark saying that current directory information (=C: and friends) should be included in such a custom environment block, it does not mention the importance of SystemRoot.

The SystemRoot environment variable usually contains the path c:\windows — the path that is also accessible using the GetWindowsDirectory function. This environment variable, as it turns out, is not only handy for scripting purposes — it is, in fact, essential for the proper operation of many libraries.

For very simple programs, forgetting to include SystemRoot in a custom environment block usually goes unnoticed — even an empty environment block works just fine. In case of more complex applications, however, the omission of this variable can quickly lead to errors — on Vista, the most common error that can be tracked back to a missing SystemRoot variable is SXS failing to find/load basic system libraries.

Now that we have Windows 7, SystemRoot seems to have become even more important: Now it is not only SXS that requires SystemRoot to be specified properly, but also CryptoAPI.

In my particular case, I was experiencing a 0x80090006 (“Invalid Signature”, NTE_BAD_SIGNATURE) error whenever the child process attempted to call CoGetObject to retrieve a pointer to a DCOM object. While this error occured on Windows 7, the same code worked fine on Windows Vista and XP.

Given this more than general error message, it seemed anything but clear to me what the problem was, so I attached a debugger to the child process (using gflags/Image File Execution Options). Once I did that, I got the following messages in my debug output output:

CryptAcquireContext: CheckSignatureInFile failed at cryptapi.c line 5198
CryptAcquireContext: Failed to read registry signature value at cryptapi.c line 873

I set a breakpoint on CryptAcquireContextW and looked at the stack trace:

0:000> k
ChildEBP RetAddr  
0008f8a4 75760a4f ole32!CRandomNumberGenerator::Initialize+0x2e
0008f8b0 75760769 ole32!CRandomNumberGenerator::GenerateRandomNumber+0xd
0008f8e8 757609cf ole32!CStdMarshal::AddIPIDEntry+0x48
0008f93c 75766aae ole32!CStdMarshal::MarshalServerIPID+0x5a
0008f994 75767519 ole32!CStdMarshal::MarshalObjRef+0xb9
0008f9c8 7576778e ole32!MarshalInternalObjRef+0x8c
0008fa4c 757676ba ole32!CRemoteUnknown::CRemoteUnknown+0x3b
0008fa8c 7576754a ole32!CComApartment::InitRemoting+0x19c
0008fa98 7586d83e ole32!CComApartment::StartServer+0x13
0008faa8 757652b3 ole32!InitChannelIfNecessary+0x1e
0008fb20 757fc046 ole32!CoUnmarshalInterface+0x38
0008fb34 757fd3d5 ole32!CObjrefMoniker::Load+0x26
0008fb70 7573cb7f ole32!CObjrefMonikerFactory::ParseDisplayName+0x16f
0008fbbc 7573caae ole32!FindClassMoniker+0x8b
0008fbf4 75789dc7 ole32!MkParseDisplayName+0xbb
0008fc3c 6954ce84 ole32!CoGetObject+0x82

Quite obviously, COM, trying to unmarshal an interface, needed a random number and attempted to use CryptoAPI for this purpose. Looking at the paramters of CryptAcquireContext, I saw that the Microsoft Strong Cryptographic Provider was attempted to be loaded — one of the standard Windows CSPs — so everything seemed normal.

Guided by the message Failed to read registry signature, I switched to Process Monitor to see which registry key was being queried: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Defaults\Provider\Microsoft Strong Cryptographic Provider.

Taking a look at this key in regedit, it did not take long before spotting SystemRoot as the culprit:

Looking at file system activity in Process Monitor proved this:

Process Monitor

Interestingly, on Windows Vista, all Image Path values in the CSP registry keys do not use SystemRoot — they just contain the file name and rely on the library path in order to locate the libraries at runtime. This explains why my code worked fine on Vista.

(While making this change, the developer seemed to forget to change the value’s type from REG_SZ to REG_EXPAND_SZ though :) )

Bottom Line 1: Always, always include SystemRoot when passing a custom environment block to CreateProcess.

Bottom Line 2: The case also shows how a seemingly trivial change in Windows (using an absolute path rather then just a file name in the CSP registry key) can lead to an application incompatibility.


How to use manifests with build.exe

As of Windows Vista, basically all applications require a manifest in order to at least declare UAC compliance. Visual Studio has builtin support for creating and embedding manifests, so when using VS to build applications, using manifests is straightforward. However, when building a user mode application with the WDK and build.exe, things are a little different. Looking at the WDK documentation, manifests remain unmentioned — both in the context of UAC and SXS. Judging from documentation, it seems that the WDK does not provide any support for embedding manifests — which would mean that you are left with having to poke with the makefiles in order to invoke mt somewhere.

Looking at, however, reveals that there are plenty of manifest-related rules and as it turns out, there indeed is support for manifests. On lines 1866 to 1925 (WDK 6000), even contains a short documentation about the usage of manifests — so whether manifest support being unmentioned in the official docs is intentional or not is not quite clear. However, using the information in, it is straightforward to get build.exe to embed manifests in a binary.

To embed a manifest, first create the manifest file and name it myapp.manifest. In the SOURCES file, include these lines:


That’s it.

In order not to have to provide a separate manifest file for different processor builds, there is some preprocessing taking place before the manifest is embedded. The following macros are available for use in the manifest:

  • SXS_ASSEMBLY_VERSION (set in SOURCES, defaults to
  • SXS_ASSEMBLY_LANGUAGE (set in SOURCES, LCID or 0000 for neutral)
  • SXS_PROCESSOR_ARCHITECTURE (set automatically)

When using these macros, note that they will be replaced by quoted text — as a consequence, you have to use them — a bit unintuitively — as follows (Note the missing quotes!):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <assemblyIdentity version=SXS_ASSEMBLY_VERSION
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <requestedExecutionLevel level="asInvoker" 

After preprocessing, the file is embedded into the binary as follows:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!--  Copyright (c) Microsoft Corporation --> 
  <assemblyIdentity version="" 
     name="MyApp" /> 
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
      <requestedExecutionLevel level="asInvoker" 
        uiAccess="false" /> 


About me

Johannes Passing, M.Sc., living in Berlin, Germany.

Besides his consulting work, Johannes mainly focusses on Win32, COM, and NT kernel mode development, along with Java and .Net. He also is the author of cfix, a C/C++ unit testing framework for Win32 and NT kernel mode, Visual Assert, a Visual Studio Unit Testing-AddIn, and NTrace, a dynamic function boundary tracing toolkit for Windows NT/x86 kernel/user mode code.

Contact Johannes: jpassing (at) acm org

Johannes' GPG fingerprint is BBB1 1769 B82D CD07 D90A 57E8 9FE1 D441 F7A0 1BB1.

LinkedIn Profile
Xing Profile
Github Profile