Выгрузка DLL из всех процессов после отсоединения глобальной ловушки CBT
Как правильно выгружать DLL из всех процессов, когда общесистемный хук, который их загружал, выгружается?
Из MSDN:
Вы можете освободить глобальную подключаемую процедуру с помощью UnhookWindowsHookEx, но эта функция не освобождает DLL, содержащую подключаемую процедуру. Это происходит потому, что глобальные подключаемые процедуры вызываются в контексте процесса каждого приложения на рабочем столе, вызывая неявный вызов функции LoadLibrary для всех этих процессов. Поскольку вызов функции FreeLibrary не может быть выполнен для другого процесса, тогда нет способа освободить DLL. Система в конечном счете освобождает DLL после того, как все процессы, явно связанные с DLL, либо завершены, либо вызвали FreeLibrary, и все процессы, которые вызвали подключаемую процедуру, возобновили обработку вне DLL.
Итак, что я ищу, так это метод определения, когда крюк отцеплен, и затем вызов FreeLibrary
от всех процессов, которые были подключены. Есть ли другие способы вызвать мгновенную выгрузку DLL, когда хук выгружен?
2 ответа
Хук DLL выгружаются в своем цикле сообщений. Принуждение их к передаче в цикле сообщений помогает выгрузить их.
Добавьте это после вашего UnhookWindowsHookEx, чтобы заставить все циклы сообщений просыпаться:
DWORD dwResult;
SendMessageTimeout(HWND_BROADCAST, WM_NULL, 0, 0, SMTO_ABORTIFHUNG|SMTO_NOTIMEOUTIFNOTHUNG, 1000, &dwResult);
Однако время от времени у меня все еще есть проблема. Я не знаю, откуда это. Я предполагаю, что заблокированный процесс может помешать dll выгружаться, но у меня нет никаких доказательств этого.
В общем, вы должны использовать глобальный перехват окон, если FreeLibrary
не требуется называться. Если вы хотите сделать это, вы можете использовать DLL-инъекцию (см., Например, http://www.codeproject.com/KB/threads/winspy.aspx и http://www.codeproject.com/KB/system/hooksys.aspx) в отношении CreateRemoteThread
а также LoadLibrary
техника. В случае, если вы можете делать то, что вы хотите в удаленном процессе. Вы можете комбинировать обе техники.
Если вы хотите позвонить FreeLibrary
только для обновления DLL вы можете сделать это по-другому. Каждая загруженная DLL может быть переименована (например, в cmd.exe) во временное имя, и вы можете вызвать MoveFileEx
с MOVEFILE_DELAY_UNTIL_REBOOT
флаг. Тогда вы уже можете скопировать и использовать новую версию DLL. Старая DLL будет удалена при следующей перезагрузке компьютера.