【问题标题】:How to prevent a specific DLL from loading into my process如何防止特定的 DLL 加载到我的进程中
【发布时间】:2015-12-22 14:42:56
【问题描述】:

我想我已经对此进行了相当彻底的研究,但我还没有找到一个可以接受的答案。首先是粗略的介绍:Windows 8.1、Visual Studio 2013。不过,我认为这些并不重要。

问题如下。我正在编写的应用程序使用 A.dll。我们使用在 HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers 下安装了上下文菜单处理程序控件的第三方供应商产品(备份程序,但这并不重要)。假设它的路径是 c:\Program Files\Vendor\control.dll。

现在,问题是当我的程序打开一个文件选择器对话框(它是一个使用 QFileDialog 然后使用标准 Windows 的 Qt 程序)时,会加载此控件以提供上下文相关的右键单击功能。此控件依赖于不同版本的“A.dll”,当加载 control.dll 时,我的程序会立即崩溃。

我不需要这个额外的功能。我想做的是防止这个特定的 dll (control.dll) 在我的进程中加载​​。在面向对象的世界中,我会简单地重载 LoadLibrary(),检查这个特定的 DLL,然后调用标准的。然而这似乎并不可行。

有没有简单的方法可以做到这一点?

谢谢! 丹

【问题讨论】:

  • “简单”的方式来做到这一点?我确定没有 :( 由于您对 3-rd 方库几乎没有(或实际上没有)控制权,您不能告诉它“不加载”DLL。也许您可以伪造它?创建自己的存根 DLL并让注册表项指向它?
  • 您可以尝试使用其中一个挂钩库来挂钩您的进程中的LoadLibrary(),并在加载麻烦的 DLL 时使其失败。另一种选择是将文件选择器代码移动到单独的进程。不幸的是,这两种解决方案都不理想。
  • 所以,总而言之,你的程序使用了 A 和 B,而 B 使用了不同版本的 A。 [在同一过程中] 没有 2 个不同版本的 A。从长远来看,其他任何事情都会引起不必要的头痛。
  • @deviantfan:问题是(如果我对 OP 的理解正确的话)B 不是 OPs 软件使用的东西,而是碰巧的第三方产品(备份软件)安装在同一台计算机上。即使 B 从 OP 计算机中删除,任何安装了 B 的最终用户仍然会遇到同样的问题。即使 OP 升级/降级 A 以匹配 B 使用的版本,对于使用与 OP 不同版本的 B 的人来说,它可能仍然无法正常工作。
  • 在那种情况下...我不确定在现代版本的 Windows 中这是否发生了变化,但是“回到什么时候...”DLL 存在一个有趣的问题。如果已经加载了具有该名称的 DLL,Windows 将重用它,而不是尝试加载“正确”的。您可能想研究该选项。

标签: c++ qt winapi dll loadlibrary


【解决方案1】:

要防止vendor.dll 加载,您可以在以下Win32API 函数LoadLibraryLoadLibraryEx 上使用挂钩,它们负责动态加载DLL,也用于加载shell 扩展。该钩子实际上是LoadLibrary函数代码站点上的汇编代码,它将重定向(跳转)到您自己定义的函数。在此函数中,您可以拦截对正在加载的 vendor.dll 的任何调用并仅返回 0,这表示无法加载该库。

一些示例代码如何使用MinHook library

HMODULE WINAPI LoadLibraryA_check(_In_ LPCTSTR lpFileName)
{
  if (isInWhiteList(lpFileName))
    return loadLibraryA_Original(lpFileName);
  else 
  {
    // Pretend that the module was not found by returning
    // 126 (0x7E): "The specified module could not be found."
    SetLastError(ERROR_MOD_NOT_FOUND);         
    return NULL;
  }
}

bool installWhitelistFilter()
{
  // Initialize MinHook.
  if (MH_Initialize() != MH_OK)
    return false;

  if (MH_CreateHook(&LoadLibraryA, &LoadLibraryA_check, 
      reinterpret_cast<LPVOID*>(&loadLibraryA_Original)) != MH_OK)
    return false;

  if (MH_EnableHook(&LoadLibraryA) != MH_OK)
    return false;

  // same for LoadLibraryW, LoadLibraryExW, LoadLibraryExA

  return true;
}

【讨论】:

    【解决方案2】:

    在这种情况下,您将启动一个标准的 Windows 打开文件对话框,该对话框在内部托管 Windows 资源管理器作为其 UI 的一部分,并且资源管理器加载外壳扩展 DLL。为了防止这种情况,您必须:

    1. 直接调用GetOpenFileName() API,通过省略OFN_EXPLORER 标志选择使用旧式对话框而不是较新的资源管理器式对话框(较新的IFileOpenDialog API 不支持此选项) .旧式对话框不支持 Shell 扩展(但它也有过时的外观)。

    2. 根本不要使用标准的“打开文件”对话框。让你自己拥有。

    另一种选择是让 Explorer 正常工作,但创建并注册您自己的 shim DLL 作为有问题的 Shell 扩展的替代品。让 shim 检查调用进程是否为explorer.exe。如果是这样,则加载并将所有操作委托给原始扩展,否则什么也不做。看 How To Disable Shell Extension In FileOpen Dialog.

    另一种选择可能是为有问题的 Shell 扩展创建并行程序集清单,并让该清单明确说明要加载的 DLL,因此扩展加载它自己的 DLL 版本,而不是您的应用程序的版本正在使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-15
      • 1970-01-01
      • 2011-07-08
      • 1970-01-01
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 2015-11-27
      相关资源
      最近更新 更多