这似乎与我一直认为是DLL的默认行为相矛盾,那就是先从本地应用程序目录加载,如果没有从PATH环境variables加载。 但是,对于像ntdll或kernel32这样的DLL,Windows似乎总是首先检查System32。 这是预期的行为? 可以被覆盖吗?
(我意识到,压倒性的这将是不好的做法,但是想知道这是否真的有可能,为了科学!)
Windows中的KnownDLLs功能可以帮助加载常见DLL,但也会强制列表中的所有DLL从system32加载。
最重要的是,kernel32.dll和ntdll.dll在大多数Windows版本中都有特殊的处理,并且在CreateProcess的早期加载,因为usermode进程的实际入口点位于其中一个模块中。
您可以使用.local和清单重定向来覆盖其中的一些。
经过更多的研究,我发现某些DLL(如kernel32.dll或user32.dll)不能被正常覆盖的原因是因为它们是已知的DLL – Windows有一个像这样的常用DLL列表,它们自动默认为System32版本,而比首先检查应用程序的文件夹的默认行为。
如果你想要解决这个问题,比如做一个代理DLL,你需要在application目录中包含两个文件: applicationName.exe.local和applicationName.exe.manifest ,其中applicationName是你的EXE文件的名字。
这些需要是清单文件的内容:
<?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.0" name="redirector" type="win32" /> <file name="kernel32.dll" /> </assembly>
assemblyIdentity标签旨在提供有关您的应用程序的版本号和名称的信息,但我们基本上可以忽略它。 重要的部分是指定一个文件在本地加载的文件标签。 将kernel32.dll
替换为您想在本地加载的DLL。
此外,Windows只刷新.manifest文件的内容重新启动时,或者当EXE文件被修改,所以你可以在一些十六进制编辑器中打开EXE文件,删除第一个字符,并将其添加回来,并保存…等。刷新清单文件。 如果你清单文件似乎被忽略,这样做。