Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect when a Module (DLL) is unloaded

Is there a way to progammatically detect when a module - specifically a DLL - has been unloaded from a process?

I don't have the DLL source, so I can't change it's DLL entry point. Nor can I poll if the DLL is currently loaded because the DLL may be unloaded and then reloaded between polling.

RESULTS:

I ended up using jimharks solution of detouring the dll entry point and catching DLL_PROCESS_DETACH. I found detouring FreeLibrary() to work as well but code must be added to detect when the module is actually unloaded or if the reference count is just being decreased. Necrolis' link about finding the reference count was handy for on method of doing so.

I should note that I had problems with MSDetours not actually unloading the module from memory if a detour existed within it.

like image 701
jay.lee Avatar asked Nov 22 '10 05:11

jay.lee


3 Answers

One very bad way(which was used by starcraft 2), is to make your program attach to itsself then monitor for the dll unload debug event(http://msdn.microsoft.com/en-us/library/ms679302(VS.85).aspx), else you'd either need to IAT hook FreeLibrary and FreeLibraryEx in the process or hotpatch the functions in kernel32 them monitor the names being passed and the global reference counts.

like image 59
Necrolis Avatar answered Oct 06 '22 01:10

Necrolis


Try using LdrRegisterDllNotification if you're on Vista or above. It does require using GetProcAddress to find the function address from ntdll.dll, but it's the proper way of doing it.

like image 26
wj32 Avatar answered Oct 06 '22 00:10

wj32


Maybe a less bad way then Necrolis's would be to use Microsoft Research's Detours package to hook the dll's entry point to watch for DLL_PROCESS_DETACH notifications.

You can find the entry point given an HMODULE (as returned by LoadLibrary) using this function:

#include <windows.h>
#include <DelayImp.h>


PVOID GetAddressOfEntryPoint(HMODULE hmod)
{
    PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)hmod;
    PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)((PBYTE)hmod + pidh->e_lfanew);
    PVOID pvEntry = (PBYTE)hmod + pinth->OptionalHeader.AddressOfEntryPoint;

    return pvEntry;
}

Your entrypoint replacement could take direct action or increment a counter that you check for in your main loop or where it's important to you. (And should almost certainly call the original entrypoint.)

UPDATE: Thanks to @LeoDavidson for pointing this out in the comments below. Detours 4.0 is now licensed using the liberal MIT License.

I hope this helps.

like image 22
jimhark Avatar answered Oct 06 '22 01:10

jimhark