Getting around the manifest check in the C Runtime DLL
Tuesday, September 23rd, 2008Today’s article is again about my “archnemesis”, the Visual Studio 2005/2008 CRT. As I mentioned in a previous article, this CRT will refuse to load if it’s not loaded with a manifest, and today I document how it checks that, and then, how to bypass it. This can be very useful, for example, to get MSVCR80.DLL to load under WINE.
The core of the manifest checking is in the _check_manifest function, which is located in crtlib.c in the CRT source. As the name suggests, this code is only linked in when compiling a DLL version of the CRT.
Here is what the code does:
- First, it checks for the presence of the
FindActCtxSectionStringWfunction inKERNEL32.DLL. If this step fails (i.e.GetProcAddressreturnsNULL), then it assumes that the OS it’s running on does not support Fusion, and returns with success. - Then, it checks if both of
MSCOREE.DLLandPGORT90.DLLare loaded in the process’ address space, and if yes, assumes it was loaded for instrumentation and returns success. - It then retrieves the path of where it was loaded and of the
system32directory. - When the paths are retrieved, it checks explicitly that it wasn’t loaded from
system32. If it was loaded from there, it immediately returns a failure. - Then, it checks the current activation context with
FindActCtxSectionStringto check if it was referenced in the manifest. If that isn’t the case, it returns a failure. - It then makes sure it was loaded from under the
WinSxSfolder in the Windows directory by doing a string compare of that path and its own path. If that is the case, it returns with success. - This last check happens only if the previous check failed. It will try to find a file called
Microsoft.VC80.CRT.manifest(orMicrosoft.VC80.DebugCRT.manifestif it’s the debug version) in the same folder from which it was loaded, and if found, will return success. - If it comes here, it assumes that it was wrongfully loaded and returns a failure.
Note that over the course of these checks, it uses multiple fixed-size string buffers. The one that is used to retrive the path of the Windows and the system32 directories is MAX_PATH in size, whereas the others are 8000 characters in size. If any of these buffers overflow at any time, it will just bail out of the checks and return success.
Also, WINE does have an implementation of activation contexts, found here (KERNEL32 wrappers) and here (actual implementation in NTDLL). Except for some reason, it fails to go grab MSVCR80.DLL from the WinSxS directory, instead returning with status 0xc0000135. It’s not that the functionality is not there however, as a quick look into WINE’s source (in loader.c to be exact) shows a neat little function called find_actctx_dll that gets called from find_dll_file.
So, now that you understand how it works, the solution to bypass it becomes very simple.
You can take the long route and recompile your own version of the CRT with the _check_manifest function dummyfied. A quick look at some installed apps on my computer shows that a few apps do it. Firefox has its MOZCRT19.DLL and Winamp has NSCRT.DLL, although the latter is an older version of the CRT.
The previous solution is quite complicated for such a simple detail. Also, if you wish to redistribute the DLL with your application, you have to name it something else than MSVCR80.DLL. So you still have to redistribute it even if you got rid of the manifest check.
Follow me here for a much quickier-and-dirtier hack. Basically, you just have to patch 5 bytes in the DLL file to disable the manifest checking. Disclaimer: I don’t think the EULA allows you to do that, and it would not be a good idea to redistribute those patched DLLs. Do it at your own risk.
I have tested with versions 8.0.50727.1433 and 8.0.50727.3053 of MSVCR80.DLL and it worked well. After that, I was able to drop them into my system32 directory in a WINE install and they would work flawlessly. So, you need to patch the following bytes at the following file offset:
00001D76 -> B8 01 00 00 00 C3
This effectively turns the content of the _check_manifest function into nothing more than a return TRUE.
I hope that this goes to show again that using manifests for the CRT was a really bad idea. It just pushes more people to either statically link to it, compile their own or try to find another way to get over that restriction, all of which are not really beneficial in the long term. It defeats the purpose of DLLs, which was to share code between processes.
