DLL redirection using manifests
c++, dll, manifest, windows
Solution
So it seems its impossible to redirect calls to `LoadLibrary` with absolute paths using manifests.
After a lot of playing around with manifests, it seems that once you get past all the bad documentation manifests are actually stupidly simple.
Basically when the executable is loaded Windows collects all the related manifests that are linked using the identity and dependency elements. Then for each file element contained in the manifest files, it adds an entry into the activation context:
'name attribute of file element' -> 'absolute path of manifest file' + 'name attribute of file element'
Now when a load library call is made, it searches the activation context map for a key that matches the path argument of load library, and then calls `Loadlibrary` with the value for that key.
So if my application `c:\foo\foo.exe` has a dependency on the manifest in `c:\foo\baa\baa.manifest`, and `baa.manifest` contains a file element `<file name="empty.dll"/>`, then the activation context will have the mapping: `"empty.dll" -> "c:\foo\baa\empty.dll"`
So any calls to `LoadLibrary("empty.dll")` will be redirected to `LoadLibrary("C:\foo\baa\empty.dll")`.
However, `LoadLibrary("c:\anotherpath\empty.dll")` Will not be redirected!
Now to prove my point of how stupidly simple manifest files and activation contexts are. If the file element of baa.manifest was `<file name="c:\anotherpath\empty.dll"/>` and you made a `LoadLibrary("C:\anotherpath\empty.dll")` call, the LoadLibrary call will be redirected to `LoadLibrary("C:\foo\baa\C:\anotherpath\empty.dll")`, yes, a malformed path...
The file element does have an undocumented attribute called "loadFrom", which does what it sounds like, and seems like its perfect to solve this problem. Using loadFrom, I was able to redirect an absolute path loadlibrary call, but it seemed to screw up other dependencies in the executable in weird ways. If someone knows more about how "loadFrom" works I would be very interested.
So how did I solve my problem in the end? By using an incredibly heavy handed approach of DLL Trojaning described at Ethical Hacker. Basically you create a dummy kernel32.dll that redirects all calls to the original kenerl32.dll, except for the LoadLibrary calls, in which you place your own redirection logic. Then in the applications manifest, you place a file element that redirects the kernel32.dll to your dummy. Fun.
All this describes my experiments on Windows Xp Sp2. For extra fun I'm led to believe manifests behave differently on almost every version of Windows.
Problem
I need to reliably redirect an applications look up of a specific DLL. Using the app.exe.local approach does not work because local files are ignored if the application has a manifest (embedded or separate file). So I am trying to do DLL redirection by defining the DLL as a private assembly in the manifests. I have a test application, LoadDll.exe which simply calls ``` LoadLibrary("C:\\EmptyDll.dll"); ``` The LoadDll.exe has the manifest (as a separate file, LoadDll.exe.manifest) ``` <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.1" processorArchitecture="x86" name="LoadDll" type="win32" /> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="EmptyDll" version="1.0.0.1" processorArchitecture="x86" /> </dependentAssembly> </dependency> </assembly> ``` The Application folder containing LoadDll.exe (NOT c:\) contains the EmptyDll.dll with the embedded manifest. ``` <?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <assemblyIdentity type="win32" name="EmptyDll" version="1.0.0.1" processorArchitecture="x86" /> </assembly> ``` However, LoadDll.exe goes ahead and loads C:\EmptyDll.dll, and not the EmptyDll.dll in the application folder. If you break either manifest (e.g. change the version number in the EmptyDll.dll manifest identity), LoadDll.exe does not load, so the manifest files are being read and processed by windows, but just ignored. Anyone got any ideas? Thanks! Toby