-1

我编写了一个全局挂钩,它使用SetWindowsHookEx挂钩WH_GETMESSAGE、WH_CALLWNDPROC 和 WH_CALLWNDPROCRET。
钩子 dll 在钩子进程中创建一个新线程,除其他外,该线程检查进程的音频状态并调用IAudioSessionManager2::GetSessionEnumerator()

现在有趣的部分是,我从钩子主机调用了UnhookWindowsHookEx()并且在我的 dll 的工作线程运行对IAudioSessionManager2::GetSessionEnumerator()的调用期间。该调用位于同一个线程的调用堆栈中,其中调用了带有 DLL_PROCESS_DETACH 的 DllMain。我认为原因是GetSessionEnumerator()在某处调用GetMessage()函数,而后者是可重入的。不幸的是,我记不清了,但我想我在调用堆栈中看到了。

但是有很多重要的事情我想知道并且仍然不清楚。所以这里有我的相关问题:

  1. 是否可以随时调用带有 DLL_PROCESS_DETACH 的 DllMain,即使是在运行当前正在卸载的 dll 中的函数的线程中?
  2. 当 DllMain DLL_PROCESS_DETACH 退出时,堆栈上的函数会发生什么?调用堆栈上的函数中的代码最终会执行吗?
  3. 如果这些功能不退出怎么办?dll什么时候卸载?
  4. DllMain DLL_PROCESS_DETACH 是否可以在 WH_GETMESSAGE、WH_CALLWNDPROC 和 WH_CALLWNDPROCRET 挂钩的回调期间被类似地调用?我知道并且已经通过实验证实,有时,虽然不是太频繁,但这些函数是可重入的,所以对这些函数的调用可以在上一次调用仍在同一个堆栈中运行的时间内注入,但我不知道是否也调用DllMain 可以以类似的方式注入。
  5. 何时可以在线程中准确调用 DllMain - 是否有一些特定的 Windows API 函数需要调用,而这又可能导致 DllMain DLL_PROCESS_DETACH 调用,或者它可能发生在任何指令中?
  6. 如果 DllMain DLL_PROCESS_DETACH 调用可以随时“注入”并且调用堆栈上的函数不再执行,那么我如何知道调用堆栈上的函数在哪里被中断?所以我可以在 DllMain 内部释放一些由函数在堆栈上分配的句柄或资源。
  7. 有什么方法可以暂时阻止/推迟对 DllMain DLL_PROCESS_DETACH 的调用?如果调用/中断发生在同一个堆栈中,锁显然没有帮助。

不幸的是,我可能无法通过实验解决这些问题,因为我已经在多台计算机上运行了几个月的挂钩(以及取消挂钩)代码,然后在取消挂钩期间发生 DllMain 的这种情况。尽管由于某种原因,它同时出现了四个不同的程序......


另外请有足够声誉的人喜欢合并标签“reentrant”和“reentrancy”吗?

4

1 回答 1

0

因此,感谢Hans,我现在知道关于第 (4) 点的 DllMain DLL_PROCESS_DETACH 不会通过钩子程序重入。

关于钩子创建的线程,我的日志文件当前表明,如果 DllMain DLL_PROCESS_DETACH 被注入到该线程的堆栈中,那么该线程确实将在 DllMain 退出后终止并且不会运行完成。这应该回答第(2)和(3)点。问题本身含蓄地回答了第 (1) 点。

但是为了解决钩子创建的那个线程的问题,我假设可以通过调用来防止 DllMain DLL_PROCESS_DETACH

GetModuleHandleEx
(
    GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
    (LPCTSTR)DllMain,
    &hModule_thread
)

在线程终止调用之前

FreeLibraryAndExitThread(hModule_thread, 0)

因此,使用GetModuleHandleEx应该回答第 (7) 点,这反过来又使所有其他点无关紧要。当然,我必须使用一些IPC来触发挂钩进程中的线程终止。

剩下的有趣问题是第 (5) 点,但这只是出于好奇:
“何时可以在线程中调用 DllMain DLL_PROCESS_DETACH - 是否有一些特定的 Windows API 函数需要调用,而这又可能导致DllMain DLL_PROCESS_DETACH 调用,或者它可以在任何指令中发生吗?”

于 2013-11-29T06:33:05.967 回答