【问题标题】:Detect the unloading of DLLs检测 DLL 的卸载
【发布时间】:2015-11-24 03:37:53
【问题描述】:

我有特殊要求,我相信没有别的办法, 即:检测DLL的卸载。我用谷歌搜索并发现 a four-years old SO 关于这个。我选择了相同的 解决方案:钩FreeLibrary

当代码进入MyFreeLibrary时,我会钩住 以相同的方式指定模块(inline-hook)。而在 MyEntryPoint,我先调用原来的入口点,然后 检查 reason 参数 - 如果值等于 DLL_PROCESS_DETACH,表示这个DLL的清理工作是 刚刚完成,它将从地址空间中卸载。 在这一点上,我有机会做我的工作。它有效。

就这样吗?不幸的是,它还没有完成。一个非常重要的 事情被忽略了:依赖。

例如,a.dll 链接到 b.dllc.dll。当你加载 a.dllb.dllc.dll 将首先被加载(被初始化)。这 是因为b.dllc.dll都列在了导入表中 a.dll,它们是 a.dll 的依赖项。同样,当您卸载 a.dllb.dllc.dll 如果它们的引用也可能被卸载 计数减少到零。我不知道关于如何 loader 找出 DLL 的依赖关系并卸载它们, MSDN 页面 FreeLibrary 没谈过这个,我很高兴 明白这一点,但我没有找到相关信息。

所以主要的问题是如何检测依赖的卸载 一个DLL模块。我希望有同样的机会做我的工作。

一个可能的解决方案可能是导入表,找出 DLL 的依赖关系从其导入表中,并找出 来自其导入表的依赖项的依赖项等, 找出所有的依赖关系,钩住所有的入口点,我没有 知道,这听起来很疯狂,我需要一些建议。

【问题讨论】:

  • 我不确定挂钩入口点是否能可靠地工作 - 据我所知,DLL 不一定要有入口点。
  • @HarryJohnston 我忘了。想了很久怎么解决,一直没有找到答案。也许这是一种错误的方式。 LdrDllNotification 可以工作,它已记录在案,但不幸的是 Windows XP 不支持它,并且 MSDN 表示“此功能可能会在不另行通知的情况下从 Windows 更改或删除”,尽管不太可能。
  • 您必须确切知道何时卸载 DLL,还是可以稍微延迟?一种选择是定期枚举模块,然后在您看到一个或多个已卸载时采取行动。
  • @joshpoley 是的,在实际从地址空间卸载之前但在未初始化 (DLL_PROCESS_DETACH) 之后。

标签: c++ windows dll loadlibrary


【解决方案1】:

我为旧的 SO 问题提供了答案。你现在写:

而在MyEntryPoint中,我会先调用原来的入口点,然后检查reason参数——如果值等于DLL_PROCESS_DETACH,则表示这个DLL的清理工作刚刚完成,即将从地址空间。

你发现这不是真的。但是最简单的解决方法是什么?如果找到原因是 DLL_PROCESS_DETACH 后,你测试 hModule 是否仍然有效怎么办?见:

How can I tell if a Windows module handle is still valid?

您可以跳过挂钩 DLL 入口点,不检查 DLL_PROCESS_DETACH 并始终只测试 hModule 是否仍然有效。这让我意识到,最好在调用原始 FreeLibrary 之前检查 hModule 是否有效,然后再测试有效到无效的转换:

if (moduleWasValid && !moduleStillValid)
{
    // process module unloaded
}

我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多