Отключение набора хуков с помощью SetWindowsHookEx несколько раз приводит к сбою перехваченного процесса

Я пытаюсь перехватить события клавиатуры и мыши целевого приложения. Я следовал за вопросом SO Как подключить внешний процесс с помощью SetWindowsHookEx и WH_KEYBOARD, и перехватчики устанавливаются и удаляются правильно с первого раза. Однако после того, как я удаляю ловушку один раз, а затем устанавливаю ее снова, попытка удалить ловушку во второй раз приводит к сбою целевого приложения. Цель ловушки - отслеживать время простоя приложения, чтобы я мог выполнять некоторые задачи во время простоя приложения. Я прошу прощения за длину вопроса, но я попытался указать все детали, которые могут помочь Спасибо

Мне нужно иметь возможность устанавливать и удалять зацепки на основе команд меню со значком в системном трее. У меня есть консольное приложение [HookApp], которое вызывает методы установки и удаления в DLL [HookDLL]. Консольное приложение также создает окно для обработки событий меню. Я использую поток окна, чтобы фактически установить и удалить хуки, потому что тот же поток, который установил хук, должен удалить его. Консоль и окно должны быть невидимыми. Должен быть виден только значок на панели задач и соответствующее меню. Я запускаю приложение для перехвата из командной строки с параметрами i. ProcessId целевого процесса ii. Название процесса iii. Время простоя [в секундах] - Время простоя перед запуском действия в DLL Мне интересно, ответственен ли таймер, который я запускаю в HookProcs, за сбой.

Журналы средства просмотра событий Имя ошибочного приложения: notepad.exe, версия: 10.0.17134.1, отметка времени: 0x9d4727c2 Имя ошибочного модуля: HookDLL_x64.dll_unloaded, версия: 0.0.0.0, отметка времени: 0x5c31aabd Код исключения: 0xc0000005 Смещение ошибки: 0x00000000000ba505 Ошибка процесса: 0x2bac

Код исключения, похоже, предполагает нарушение доступа к памяти.

Я попробовал следующее I. Вызовите API SendMessageTimeout с помощью HWND_BROADCAST из HookApp b. Вызовите API SendMessageTimeout с HWND_BROADCAST из HookDLL на основе выгрузки DLL из всех процессов после отсоединения глобальной ловушки CBT

II. а. вызовите FreeLibraryAndExitThread API в методе DLLMain для DLL_PROCESS_DETACH AND DLL_THREAD_DETACH - вместе и по отдельности на основе http://www.rohitab.com/discuss/topic/42505-unloading-dll-crashes-exe/

III. Сделали консоль HookApp и окно видимыми и скрытыми, чтобы увидеть, имеет ли это какое-то значение

Внутривенно Не удалось попробовать следующее из-за 64-битной архитектуры https://www.unknowncheats.me/forum/programming-for-beginners/73377-unload-injected-dll-thread-process.html

Другие ссылки, на которые я ссылался. В некоторых программах происходит сбой при отсоединении с помощью UnhookWindowsHookEx () b. Как правильно использовать SetWindowsHookEx & CallNextHookEx c. Выгрузка внедренной DLL d. FreeLibraryAndExitThread завершает работу программы при выгрузке внедренной DLL

//Code in the DLL
extern "C" __declspec(dllexport) void install(unsigned long threadID,int _nIdleTime) {
    nIdleTime = _nIdleTime;
    Log(L"install proc called from app: _nIdleTime", _nIdleTime);
    hhKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hinst, threadID);
    hhMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, hinst, threadID);
    logger->Log("Install");
    logger->Log("Keyboard", (LONG)hhKeyboard);
    logger->Log("Mouse", (LONG)hhMouse);

}

//Uninstall the dll from the Target Process
DWORD WINAPI UnInjectDLLFromTarget() {
    uninstall();
    //DWORD_PTR dwResult = 0;
    //SendMessageTimeout(HWND_BROADCAST, WM_NULL, 0, 0, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 1000, &dwResult);
    return TRUE;
}

LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code < 0) {

        return CallNextHookEx(0, code, wParam, lParam);
    }
    StartTimer();
    Beep(1000, 20);


    return CallNextHookEx(hhKeyboard, code, wParam, lParam);
}

LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
    if (code < 0) {

        return CallNextHookEx(0, code, wParam, lParam);
    }
    //  StartTimer();
        //Beep(1000, 20);

    return CallNextHookEx(hhMouse, code, wParam, lParam);
}
BOOL WINAPI DllMain(__in HINSTANCE hinstDLL, __in  DWORD fdwReason, __in  LPVOID lpvReserved) {


    if (fdwReason == DLL_PROCESS_DETACH || fdwReason==DLL_THREAD_DETACH) {
        FreeLibraryAndExitThread(hinstDLL, 0);
        return 0;
    }
}

//Code in the Application [HookApp]
Similar to  [But not exactly the same - It is a bit more involved because of the need to create the message pump and the menu event handling window]
 HINSTANCE hinst = LoadLibrary(_T("MyDLL.dll")); 

    if (hinst) {
        typedef void (*Install)(unsigned long);
        typedef void (*Uninstall)();

        Install install = (Install) GetProcAddress(hinst, "install");
        Uninstall uninstall = (Uninstall) GetProcAddress(hinst, "uninstall");

        install(threadID);

        Sleep(20000);

        uninstall();
    }
  1. SendMessageTimeout в методе DLL [HookDLL] При удалении немедленно происходит сбой приложения
  2. SendMessageTimeout в приложении [HookApp], похоже, не делает ничего полезного.
  3. FreeLibraryAndExitThread, похоже, не делает ничего полезного. Тем не менее, с 2 и 3, я думаю, что я могу установить крюк во второй раз. Без них первый unhook вылетает приложение.
  4. Я не смог попробовать предложение с использованием встроенного языка ассемблера из-за 64-битной архитектуры.

Пожалуйста помоги.

1 ответ

Для деинсталляции хука и выгрузки вашей dll все что нужно - звоните UnhookWindowsHookEx за каждый дескриптор крюка, полученный предыдущим вызовом SetWindowsHookEx, все. вам не нужно звонить FreeLibrary[AndExitThread] сам. система автоматического вызова FreeLibrary на крючке длл после UnhookWindowsHookEx Вызов, когда первое (любое) сообщение будет получено целевым потоком приложения и вызовом этого потока GetMessage или же PeekMessage, так что просто выгрузите свою DLL после нескольких UnhookWindowsHookEx - вам нужно опубликовать сообщение в ветке, для которой вы устанавливаете хук. если вы делаете это для конкретной нити (dwThreadId) - тебе нужно PostThreadMessageW(dwThreadId, WM_NULL, 0, 0); - система сама позвони FreeLibrary (вызывается из user32!__ClientFreeLibrary который звонил из ntdll!KiUserCallbackDispatcher - называется внутри GetMessage или же PeekMessage когда поток (или это окно) получил какое-либо сообщение)

вызов FreeLibrary из dll для себя - всегда ошибка - если предположить, что dll будет выгружен этим вызовом - куда мы вернемся после вызова? в незагруженное место. вызов FreeLibraryAndExitThread Существуют смысл в некоторых случаях, но только из потока, который вы создаете сами. вызов FreeLibraryAndExitThread из точки входа dll вообще фатальная ошибка - вы убиваете не сам поток, а поток, который вы убиваете - удерживаете критическую секцию (блокировку загрузчика) внутри которой называется точка входа dll - настолько фатальная ошибка. и вообще абсолютно бессмысленный звонок сюда - если вы говорите, получите DLL_PROCESS_DETACH это означает, что dll уже в процессе выгрузки. DLL_THREAD_DETACH - произвольный момент, почему и сколько раз вы пытаетесь вызвать unload для себя здесь? выходите из резьбы, удерживая широкий критический участок процесса, не отпуская его. фатальная ошибка.

также потому, что тот же поток, который установил хук, должен удалить его. - это неправда. другой поток от также может сделать это.

также StartTimer(); в вашем коде выглядят как подозрительные что делает этот код? есть и где вы отменяете таймер?

Другие вопросы по тегам