Visual C++ - 覆盖从 DLL 导入的函数?
Posted
技术标签:
【中文标题】Visual C++ - 覆盖从 DLL 导入的函数?【英文标题】:Visual C++ - overriding a function imported from a DLL? 【发布时间】:2012-03-05 12:15:30 【问题描述】:我正在尝试覆盖 kernel32.dll 中的特定函数。是否有可能在静态库中重新定义该函数并强制可执行文件使用静态库中的函数?我想不同的链接可能会成为一个问题。
可以用我自己的自定义 DLL 覆盖它。但是问题是 DLL 本身需要链接到 kernel32.dll,所以它忽略了我对该函数的定义。
编辑:我让它与我自己的 DLL 一起工作。在构建它时,需要禁用链接时间代码生成。静态链接被覆盖的函数怎么样?
【问题讨论】:
我很犹豫将标题更改为“...从 KERNEL32.DLL 导入”。垫片 DLL 可以是一种解决方案,但 Kernel32.DLL 是一个特殊的 DLL:它是您必须链接的一个 DLL。 【参考方案1】:是的,这不是什么大问题。函数被定义为__dllimport
,但这并没有指定它们是从哪个 DLL 导入的。链接器只是选择提供它们的第一个导入库。所以,。先通过你的图书馆。在 MSVC 中,您需要禁用“包含标准库”,因为它们位于自定义库之前。
【讨论】:
我现在首先传递我自己的 DLL,它按预期工作。但是,在构建该 DLL 时,我不得不禁用 LTCG,因为否则链接器似乎在我的模块之前处理 kernel32.lib(我想知道是否有一种方法可以使用 LTCG 并且仍然能够构建 DLL)。知道是否有办法使用静态库进行覆盖吗?而不必构建自己的 DLL。 静态库尚未链接,因此它无法链接到 Kernel32.DLL 或您的覆盖。 我无法进行静态覆盖的唯一原因是,因为导入是使用 __declspec(dllimport) 完成的。是否可以让 __declspec(dllimport) 也查找不在 DLL 中的函数? @NFRCR:你刚刚告诉链接器“不要费心在我现在提供的部分(目标文件 + 静态库)中寻找这个名称,这是一个 DLL 导入”然后想说“在静态库中查找此名称”。这充其量只是片状。 我一直在调查这个。如果您使用 __declspec(dllexport)(导出函数的可执行文件)重新定义该函数,则可以覆盖您自己的目标文件中的 DLL 函数。然而,CRT 似乎忽略了它,仍然链接到 kernel32.dll。我终于制作了可执行文件以自导入该功能。 CRT 链接到它,但可执行文件的行为出乎意料。【参考方案2】:如果我对您的理解正确,您需要 kernel32.dll 中的 Windows API 函数的自定义行为。如果是这样,您需要连接到 Windows API。一种方法是使用Detours。我自己没有尝试过,但这里有一个 CodeProject 文章的链接 - http://www.codeproject.com/Articles/30140/API-Hooking-with-MS-Detours。
【讨论】:
【参考方案3】:如果你的应用已经存在且无法修改,那么
您可以编写代理 dll。 IE。制作自己的dll,称为kernel32.dll,放入应用程序目录,并让您的代理dll提供所有功能应用程序的需求。当然,您的自定义 dll 应该将所有未覆盖的调用重定向到原始 kernel32.dll - 通过使用 LoadLibrary 加载原始 dll。
因为 LoadLibrary 是由 kernel32 提供的,并且您正在代理 kernel32,所以很可能您必须将代理 dll 命名为 kernel33.dll 并修补原始 exe 并使其加载 kernel33 而不是 kernel32。
整个过程都很痛苦,要成功,您至少应该熟悉 cli(命令行界面 - windows 上的 cmd.exe)和 dumpbin 实用程序。 This 过时的教程可以让你入门。
您也可以尝试使用 dll 注入或类似技术。还有一个我没用过的"Detours" 库(不知道如果我可以制作代理dll,我为什么还要费心)。
如果您可以访问您的应用程序的源代码,并且只有程序的特定部分需要不同的例程...
然后只需使用您想要的任何名称(例如,myLoadLibrary
)创建自定义例程。然后制作一个使用#define
的标题来重新定义您的例程。 IE。类似#define LoadLibrary myLoadLibrary
。在您需要覆盖的每个文件中包含该标题,并确保它包含在<windows.h>
之后。
【讨论】:
这行不通。 “您的自定义 dll 应该重定向所有调用它......通过使用 LoadLibrary 加载原始 [Kernel32.dll]”。那是先有鸡还是先有蛋的问题:LoadLibrary
来自Kernel32.dll,所以不能用来加载Kernel32.dll
函数重命名没问题;这是第一个不起作用的建议。
@MSalters:“您必须将代理 dll 命名为 kernel33.dll”。看起来你错过了那部分。
不,我没有。您的代理“kernel33”DLL 将如何调用 LoadLibraryW("kernel32.dll");
?它不能。要调用LoadLibraryW
,kernel32.dll 必须已经加载。重命名任何一个 DLL 都不会解决此问题 - 鸡与蛋的问题是由于内容,而不是名称。以上是关于Visual C++ - 覆盖从 DLL 导入的函数?的主要内容,如果未能解决你的问题,请参考以下文章
从 Visual Basic 调用 C++ dll 类 [重复]
Visual C++:从 DLL 调用时 XGBoost 不起作用