使用清单的 DLL 重定向
我需要可靠地重定向查找特定 DLL 的应用程序.使用 app.exe.local 方法不起作用,因为如果应用程序具有清单(嵌入或单独的文件),则会忽略本地文件.所以我试图通过将 DLL 定义为清单中的私有程序集来进行 DLL 重定向.
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.
我有一个测试应用程序 LoadDll.exe,它只是调用
I have a test application, LoadDll.exe which simply calls
LoadLibrary("C:\EmptyDll.dll");
LoadDll.exe 有清单(作为一个单独的文件,LoadDll.exe.manifest)
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>
包含 LoadDll.exe(不是 c:)的 Application 文件夹包含带有嵌入清单的 EmptyDll.dll.
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>
但是,LoadDll.exe 会继续加载 C:EmptyDll.dll,而不是应用程序文件夹中的 EmptyDll.dll.
However, LoadDll.exe goes ahead and loads C:EmptyDll.dll, and not the EmptyDll.dll in the application folder.
如果您破坏任一清单(例如更改 EmptyDll.dll 清单标识中的版本号),LoadDll.exe 不会加载,因此清单文件正在被 Windows 读取和处理,但只是被忽略.
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.
有人有什么想法吗?
谢谢!
托比
推荐答案
因此似乎不可能使用清单将调用重定向到具有绝对路径的 LoadLibrary.
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.
基本上,当加载可执行文件时,windows 会收集所有使用标识和依赖项元素链接的相关清单.然后对于清单文件中包含的每个文件元素,它会在激活上下文中添加一个条目:
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.
因此,如果我的应用程序 c:foofoo.exe 依赖于 c:fooaaaa.manifest 中的清单,并且 baa.manifest 包含一个文件元素 <file name="empty.dll"/>
,那么激活上下文就会有一个映射:"empty.dll" ->"c:fooaaempty.dll"
So if my application c:foofoo.exe has a dependency to the manifest in c:fooaaaa.manifest, and baa.manifest contains a file element <file name="empty.dll"/>
, then the activation context will have a mapping: "empty.dll" -> "c:fooaaempty.dll"
因此,对 LoadLibrary("empty.dll")
的任何调用都将被重定向到 LoadLibrary("C:fooaaempty.dll")
.
So any calls to LoadLibrary("empty.dll")
will be redirected to LoadLibrary("C:fooaaempty.dll")
.
但是,LoadLibrary("c:anotherpathempty.dll")
不会被重定向!
However, LoadLibrary("c:anotherpathempty.dll")
Will not be redirected!
现在来证明我的观点,即清单文件和激活上下文是多么的愚蠢.如果 baa.manifest 的文件元素是 <file name="c:anotherpathempty.dll"/>
并且你创建了一个 LoadLibrary("C:anotherpathempty.dll")
调用,LoadLibrary 调用将被重定向到 LoadLibrary("C:fooaaC:anotherpathempty.dll")
,是的,格式错误的路径...
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:anotherpathempty.dll"/>
and you made a LoadLibrary("C:anotherpathempty.dll")
call, the LoadLibrary call will be redirected to LoadLibrary("C:fooaaC:anotherpathempty.dll")
, yes, a malformed path...
file 元素确实有一个未记录的属性,称为loadFrom",它的功能听起来很像,而且似乎可以完美地解决这个问题.使用 loadFrom,我能够重定向绝对路径 loadlibrary 调用,但它似乎以奇怪的方式搞砸了可执行文件中的其他依赖项.如果有人更了解loadFrom"的工作原理,我会非常感兴趣.
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.
那我最后是怎么解决我的问题的呢?通过使用 道德黑客.基本上,您创建了一个虚拟的 kernel32.dll,它将所有调用重定向到原始的 kenerl32.dll,除了 LoadLibrary 调用,您可以在其中放置自己的重定向逻辑.然后在应用程序清单中,放置一个文件元素,将 kernel32.dll 重定向到您的虚拟对象.有趣.
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.
所有这些都描述了我在 Windows Xp Sp2 上的实验.为了更有趣,我相信清单在几乎每个版本的 Windows 上都有不同的表现.
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.
相关文章