DLL redirection using manifests

WearyMonkey picture WearyMonkey · Jan 20, 2010 · Viewed 24.6k times · Source

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

Answer

WearyMonkey picture WearyMonkey · Jan 26, 2010

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 does the loadlibrary with the value for that key.

So if my application c:\foo\foo.exe has a dependency to 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 a 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.