Пробую организовать простой перехват АПИ через Detours. Метод внедрения - глобальный хук. Все перехватывается, но снятие хука и перехвата проходит как-то странно: Иногда, библиотека хука не выгружается из некоторых процессов. Причем глюк может быть, а может и не быть. Установка хука и перехвата выглядет так: Код (Text): static LRESULT CALLBACK msghook(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(hook, nCode, wParam, lParam); } int setMyHook() { hook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)msghook,hInstance,0); if(!hook) return 13; return 0; } int clearMyHook() { BOOL unhooked = UnhookWindowsHookEx(hook); return 0; } BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { (void)hinst; (void)reserved; if (dwReason == DLL_PROCESS_ATTACH) { hInstance = hinst; DetourRestoreAfterWith(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)Real_connect, ConnectIntercepted); DetourTransactionCommit(); GetConfigPath(); } else if (dwReason == DLL_PROCESS_DETACH) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)Real_connect, ConnectIntercepted); DetourTransactionCommit(); } return TRUE; } Работаю со всем этим из-под сервиса, но такое поведение наблюдалось и в обычных приложениях... Кто-нибудь знает как обеспечить полную выгрузку всех копий Длл с хуком?
У меня с Detours были проблемы и посеръезнее. А почему ты используешь именно Detours? Решение проблемы: Из вышесказанного следует что нужно заставить процесс выполнить FreeLibrary, попробуй заюзать CreateRemoteThread который выгрузит библиотеку.
Begemot Можно попробовать самовыгрузку. Т.е. после снятия хука контроллирующая прога посылает какой-нибудь сигнал (SetEvent, например), а DLL сама вызывает в FreeLibrary. Но тут есть тонкости. Во-первых, может потребоваться несколько вызовов FreeLibrary, т.к. не факт, что LoadLibrary для этой длл вызвана 1 раз, во-вторых, последний вызов должен быть не FreeLibrary, а FreeLibraryAndExitThread.
im1111 Единственное что удалось найти, да и прога уже закончена... А можно подробнее? Если можно, с примером... green Не понял, сколько раз она может быть вызвана, это же хук? Я имею ввиду: Длл подгружается системой во все процессы с оконным интерфейсом, сам процесс не особо об этом в курсе, т.е. и LoadLibrary вызываться не должно...процессом....=>одного FreeLibrary на процесс должно быть достаточно?
Begemot Я не знаю, как реализованы глобальные хуки, но предполагаю, что используется стандартный механизм загрузки длл. Думаю, что при вызове SetWindowsHookEx выставляется какой-то глобальный "hook pending" флаг, который проверяется соответствующим кодом каждого процесса (в данном случае где-то в ф-ции GetMessage), который при необходимости подгружает нужную длл. Скорее всего LoadLibrary вызывается 1 раз (в каждом процессе), но полной уверенности нет, надо пробовать...
green Ты не мог бы на коде показать реализацию предложенного метода(SetEvent)? Буду крайне благодарен
Begemot Извини с примером сложновато, но идея такая: создать в удалленном процессе тред который выгрузит твою библиотеку. Данная АПИ должна с этим справится, единственная проблема в том что она присутствует начиная NT по XP/2003.
Begemot В деталях это примерно так: В управляющей проге: 1. создаёшь (CreateEvent) именованный (ну, скажем, "HookCleaner") event с ручным управлением, , начальное состояние - nonsignaled (хотя пофиг). 2. перед установкой хука (SetWindowsHookEx), устанавливаешь этот event в nonsignaled состояние (SetEvent). после снятия хука (UnhookWindowsHookEx) устанавливаешь этот event в signaled состояние (SetEvent). В хуковой DLL (в DllMain): 1. по DLL_PROCESS_ATTACH: 1.1. открываешь event "HookCleaner" (OpenEvent) 1.2. cоздаёшь поток (CreateThread), который: 1.2.1. ожидает этот event (WaitForSingleObject) 1.2.2. выгружает DLL (FreeLibraryAndExitThread) 2. по DLL_PROCESS_DETACH: 2.1. закрываешь event "HookCleaner" (CloseHandle).
Не помогло. Сделал так. В Длл: Код (Text): ..... ..... HANDLE hGlobalEvent; DWORD dll_exit_thread_id; .... .... static LRESULT CALLBACK msghook(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(hook, nCode, wParam, lParam); } int setMyHook() { hook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)msghook,hInstance,0); if(!hook) return 13; return 0; } int clearMyHook() { BOOL unhooked = UnhookWindowsHookEx(hook); return 0; } DWORD WINAPI dll_exit_thread(LPVOID param) { HMODULE h; DWORD dwWaitResult; dwWaitResult = WaitForSingleObject(hGlobalEvent, INFINITE); if (dwWaitResult==WAIT_OBJECT_0) { h=GetModuleHandle("fire.dll"); FreeLibraryAndExitThread(h,0); } return 0; } BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { (void)hinst; (void)reserved; HANDLE h; if (dwReason == DLL_PROCESS_ATTACH) { hInstance = hinst; DetourRestoreAfterWith(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)Real_connect, ConnectIntercepted); DetourTransactionCommit(); GetConfigPath(); hGlobalEvent=OpenEvent(EVENT_ALL_ACCESS, FALSE, "StopFire"); h=CreateThread(0,0xfffff,dll_exit_thread,0,0,&dll_exit_thread_id); } else if (dwReason == DLL_PROCESS_DETACH) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)Real_connect, ConnectIntercepted); DetourTransactionCommit(); } return TRUE; } В управляющем сервисе: Код (Text): namespace Work { .......... .......... void Hook(); void UnHook(); HANDLE hGlobalWriteEvent; .......... .......... } .......... .......... void Work::Hook() { if (hLibInst) { LPFNCINT clearMyHook = (LPFNCINT)GetProcAddress(hLibInst, "clearMyHook"); if (clearMyHook) { clearMyHook(); } FreeLibrary(hLibInst); } hLibInst = LoadLibrary(_T("fire.dll")); if(hLibInst) { hGlobalWriteEvent = CreateEvent( NULL, // no security attributes TRUE, // manual-reset event FALSE, // initial state is signaled "StopFire" // object name ); ResetEvent(hGlobalWriteEvent); LPFNCINT setMyHook = (LPFNCINT)GetProcAddress(hLibInst, "setMyHook"); if (!setMyHook) FreeLibrary(hLibInst); setMyHook(); } } void Work::UnHook() { if (!hLibInst) { hLibInst = LoadLibrary(_T("fire.dll")); } SetEvent(hGlobalWriteEvent); LPFNCINT clearMyHook = (LPFNCINT)GetProcAddress(hLibInst, "clearMyHook"); clearMyHook(); FreeLibrary(hLibInst); } Результат нулевой, где я ошибся?
Begemot Ты проверил, что весь код ф-ции dll_exit_thread выполняется без ошибок (я имею ввиду возвращаемые значения вызываемых апишных ф-ций)? Если да, то, видимо, всё-таки счётчик ссылок на DLL > 1. Попробуй (только для эксперимента - это ненадёжно) вместо Код (Text): FreeLibraryAndExitThread(h, 0); делать Код (Text): while (FreeLibrary(h));
Как-то все непонятно. Оставшиеся Длл могут все-таки выгрузиться, но значительно позже... Нет, не приводит, но в контексте вышесказанного
Begemot Странно... Не знаю тогда, в чём может быть дело... надо ковыряться, сейчас нет на это времени, извини --- Подключись к процессу, в котором наблюдается особо длительная задержка с выгрузкой длл (или длл вообще не выгружается), убедись, что нормально отработала dll_exit_thread. Если DLL_PROCESS_DETACH не приходит, посмотри кол. ссылок на ДЛЛ в базе загрузчика (PEB::LoaderData). В крайнем случае пройдись пошагово по FreeLibrary... В общем, искать надо, чего там не так...