views:

67

answers:

2

How do you properly unload a DLL from all processes when the system-wide hook that loaded them gets unloaded?

From MSDN:

You can release a global hook procedure by using UnhookWindowsHookEx, but this function does not free the DLL containing the hook procedure. This is because global hook procedures are called in the process context of every application in the desktop, causing an implicit call to the LoadLibrary function for all of those processes. Because a call to the FreeLibrary function cannot be made for another process, there is then no way to free the DLL. The system eventually frees the DLL after all processes explicitly linked to the DLL have either terminated or called FreeLibrary and all processes that called the hook procedure have resumed processing outside the DLL.

So what I am looking for, is a method to detect when the hook is unhooked, and then call FreeLibrary from all the processes that were hooked. Are there any other ways to cause instant unloading of a DLL when the hook is unloaded?

A: 

In general you should use global windows hooking if FreeLibrary is not a required be called. If you do want to do this you can use DLL injection (see for example http://www.codeproject.com/KB/threads/winspy.aspx and http://www.codeproject.com/KB/system/hooksys.aspx) with respect of CreateRemoteThread and LoadLibrary technique. In the case you can do what you want in the remote process. You can combine both techniques.

If you want call FreeLibrary only to do an update of the DLL you can do this in another way. Every DLL which is loaded could be renamed (in cmd.exe for example) to a temporary name and you can call MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT flag. Then you can already copy and use new version of the DLL. The old one DLL will be deleted at the next reboot of computer.

Oleg
Are you saying that an already loaded DLL can be renamed on the fly? Or that my new version of a DLL should take the place of the old only after a reboot?
Vegard Larsen
Yes any loaded DLL can be renamed on the fly. Just try this. It is very old trick existing since Windows NT 3.1. Some modern Setups like Windows Installer used this by the way. You have in the most cases an advantage if you move and rename old DLL (which can be in use) in a temp directory with the temp name and copy a new version of DLL in the new location. Programs which loaded old DLL can continue running, but you can use a new DLL whithout waiting for reboot. The only problem which can exist if you have many DLL which can be dynamically loaded and in the wost case you can have a mix of DLLs
Oleg
Could you explain in why you need to unload the DLL in your case?
Oleg
Moving the DLL would solve a problem during installation of the application, since the DLL might be loaded into other applications at that time. Still, I believe it should be possible to make other programs unload the DLL properly, as it is causing trouble in some strange places (rather unreproducible, I'm afraid).
Vegard Larsen
Of cause it is possible. With DLL injection. Last years I use more often DLL injection as hooking. Typically one need inject selected processes and not all. Moreover hooking work together with user32.dll and only on one windows station. With DLL injection technique one can inject DLL also in console applications and just in any process on any windows station (also winlogon.exe or some system processes). After doing required action one can call FreeLibrary. One can use this techniqu to call FreeLibrary on in all processes which loaded your DLL. So all is possible.
Oleg
I need to inject into all processes that produce windows, so I believe hooking is the appropriate method. See http://maxto.net/ (the software that I am trying to fix a bug in). So I think DLL injection into only some processes is out of the question at the moment.
Vegard Larsen
Then you can do DLL injection to call FreeLibrary only after calling of `UnhookWindowsHookEx`. You should 1) call `UnhookWindowsHookEx` then 2) enumerate all processes and find out which from there has your DLL loaded. At the end 3) use DLL injection to call one time FreeLibrary inside all of this processes. Do you have expirience with DLL Injection? Or you have problem with finding out the address of DLL inside of other processes (parameter of FreeLibrary)?
Oleg