使用清单的DLLredirect

我需要可靠地redirect应用程序查找特定的DLL。 使用app.exe.local方法不起作用,因为如果应用程序具有清单(embedded文件或单独文件),则会忽略本地文件。 所以我正在试图通过在清单中将DLL定义为私有程序集来执行DLLredirect。

我有一个testing应用程序,只需调用LoadDll.exe

LoadLibrary("C:\\EmptyDll.dll"); 

LoadDll.exe具有清单(作为单独的文件,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(NOT c:\)的Application文件夹包含带有embedded式清单的EmptyDll.dll。

 <?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。

如果您破坏了任何清单(例如,在EmptyDll.dll清单标识中更改版本号),则LoadDll.exe不会加载,因此清单文件正在被Windows读取和处理,但只是被忽略。

任何人有任何想法?

谢谢!

托比

所以看起来不可能使用manifest来将调用重定向到带有绝对路径的LoadLibrary。

经过大量的清单工作之后,似乎一旦过去了所有不良的文档清单实际上是非常简单的。

基本上当可执行文件被加载时,窗口收集所有使用标识和依赖元素链接的相关清单。 然后,为清单文件中包含的每个文件元素添加一个条目到激活上下文中:

 'name attribute of file element' -> 'absolute path of manifest file' + 'name attribute of file element' 

现在,当进行加载库调用时,它将在激活上下文映射中搜索与加载库的路径参数相匹配的键,然后执行具有该键的值的加载库。

因此,如果我的应用程序c:\ foo \ foo.exe对c:\ foo \ baa \ baa.manifest中的清单具有依赖关系,并且baa.manifest包含一个文件元素<file name="empty.dll"/>那么激活上下文将会有一个映射: "empty.dll" -> "c:\foo\baa\empty.dll"

因此,任何对LoadLibrary("empty.dll")调用都将被重定向到LoadLibrary("C:\foo\baa\empty.dll")

但是, LoadLibrary("c:\anotherpath\empty.dll")不会被重定向!

现在来证明我的观点是多么愚蠢简单的清单文件和激活上下文是。 如果baa.manifest的文件元素是<file name="c:\anotherpath\empty.dll"/>并且调用了LoadLibrary("C:\anotherpath\empty.dll") ,则LoadLibrary调用将被重定向到LoadLibrary("C:\foo\baa\C:\anotherpath\empty.dll") ,是的,格式不正确的路径…

文件元素确实有一个名为“loadFrom”的未公开的属性,它听起来像,它似乎是完美的解决这个问题。 使用loadFrom,我能够重定向绝对路径的loadlibrary调用,但它似乎以怪异的方式搞砸了可执行文件中的其他依赖项。 如果有人更了解“loadFrom”是如何工作的,我会非常感兴趣。

那么我到底是怎么解决我的问题的呢? 通过使用在道德黑客中描述的DLL Trojaning的非常笨手的方法。 基本上,你创建一个虚拟kernel32.dll重定向到原始的kenerl32.dll的所有调用,除了LoadLibrary调用,其中你放置自己的重定向逻辑。 然后在应用程序清单中,放置一个将kernel32.dll重定向到您的虚拟文件的文件元素。 乐趣。

所有这些都描述了我在Windows Xp Sp2上的实验。 为了获得额外的乐趣,我让人们相信在几乎所有的Windows版本中,清单行为都是不同的。

好的,你需要像这样设置它:

  • c:\apppath\testapp.exe – 您的测试应用程序exe文件
  • c:\apppath\testapp.exe.manifest – 潜在的嵌入式应用程序清单文件
  • c:\apppath\EmptyAssm\EmptyAssm.manifest – 描述您的新程序集的清单。
  • c:\apppath\EmptyAssm\empty.dll – 程序集dll
  • c:\apppath\EmptyAssm\empty.dll.2.manifest – dll中的嵌入式清单

所以,你有你的测试应用程序,其中包含一个应用程序清单:其中包含应用程序相关的程序集引用 – 包括您添加到您的自定义dll程序集。

应用程序文件夹的应用程序文件夹 assm子文件夹中,您具有“EmptyAssm”程序集的程序集清单,其中包含引用实际dll的文件节点“empty.dll”。

empty.dll嵌入自己的清单,包含它所需的任何公共或私人程序集上的相关程序集引用。

这是重要的一点:“EmptyAssm”程序集清单和“空白”dll清单可能有所不同。 (“EmptyAssm”)程序集的清单文件不能被嵌入,但是可能会共享dll清单名称,如果你选择通过dll的名称命名你的清单。

现在,当加载器加载你的EXE时,它加载你的EXE的清单,并将其添加到激活上下文中。 当处理EXE的导入表时,或者调用LoadLibrary,加载器首先在激活上下文中搜索具有匹配文件节点的程序集清单。 如果它找到一个匹配程序集,那么它会处理并从程序集位置(包含程序集.manifest的文件夹)加载dll,并且目前可能在dll中没有嵌入式清单,并且dll和清单具有相同的名称,重用相同的清单文件来设置DLL的激活上下文。

如果您希望将“emptyassm”清单和dll放在与应用程序文件夹不同的文件夹中,并且如果要定位Windows server 2008或Windows 7或更高版本,则可以为您的应用程序添加一个配置文件:

  • c:\apppath\testapp.exe.config – 应用程序配置文件

应用程序配置文件可以在assemblyBinding节点(配置文件看起来很像清单文件)下包含一个探测节点,并带有一个privatePath="some relative path" 在这种情况下,相对文件夹将被搜索组件。


我在这里的最后一个响应有一个示例文件,涵盖了从DLL创建程序集的过程,并从一个exe引用它: – 一种方法从中央存储库加载DLL


只是为了澄清:一个win32程序集是(最简单的)一个清单文件,描述程序集和一个dll。 在这个模型中,它们总是位于同一个文件夹中,因此清单的文件节点根本不能包含任何路径信息 – 只有dll的名称。

可以共享程序集 – 给他们一个强大的版本(和一些数字签名),并将其安装在Windows \ WinSxS中,或私有。

在5.1之前的Windows版本(Win XP)将不会搜索程序集,因为这项技术只是在XP中添加的。 Windows 5.1到6.0(XP和Vista)将只在具有激活激活上下文的对象的文件夹中搜索私有程序集: – 如果某个exe引用程序集,则包含该exe文件夹。 如果dll中的代码引用了一个程序集,则会搜索dll的文件夹。

如果你想将你的dll存储在由多个应用程序共享的私有位置(例如),你必须有Windows 7或更高版本的要求:

Windows版本6.1(或者称为Windows server 2008或Windows 7)和更高版本除了在模块文件夹之外,还将在应用程序配置文件中搜索指定为探测元素的privatePath元素的路径。 应用程序配置文件始终与exe或dll位于同一个文件夹中,并被命名为:

<exename>.exe.config<dllname>.dll.2.config

(原因是.2。有潜在的大量表现和配置作为资源嵌入,并且加载器保留资源id为1 … 15。当在磁盘上搜索配置文件的清单时,如果资源id嵌入的资源应该是1,id被省略,但是任何其他数字意味着它成为文件名的一部分)。

您可以通过使用Detours包装LoadLibrary来解决此问题。 您的LoadLibrary包装将能够识别加载您的DLL的尝试,并适当地重写路径。