-3

我正在尝试挂钩目标应用程序的键盘和鼠标事件。我遵循了 SO question How to hook external process with 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.a. 从 HookApp b 调用带有 HWND_BROADCAST 的 SendMessageTimeout API。使用 HWND_BROADCAST 从 HookDLL 调用 SendMessageTimeout API,基于Unloading DLL from all processes after unhook global CBT hook

二、一个。在 DLL_PROCESS_DETACH 和 DLL_THREAD_DETACH 的 DLLMain 方法中调用 FreeLibraryAndExitThread API - 一起和单独基于http://www.rohitab.com/discuss/topic/42505-unloading-dll-crashes-exe/

三、使 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. DLL [HookDLL] 方法中的 SendMessageTimeout 卸载立即使应用程序崩溃
  2. 应用程序 [HookApp] 中的 SendMessageTimeout 似乎没有做任何有用的事情。
  3. FreeLibraryAndExitThread 似乎没有做任何有用的事情。但是,使用 2 和 3,我想我可以第二次安装挂钩。没有它们,第一次取消挂钩会使应用程序崩溃。
  4. 由于 64 位架构,我无法尝试使用内联汇编语言的建议。

请帮忙。

4

1 回答 1

1

用于卸载钩子并卸载所有您需要的 dll - 调用UnhookWindowsHookEx由先前调用获得的每个钩子句柄SetWindowsHookEx。全部。你不需要给FreeLibrary[AndExitThread]自己打电话。callend 后系统自动调用FreeLibrary您的钩子 dll UnhookWindowsHookEx,当目标应用程序线程接收到第一条(任何)消息并且此线程调用GetMessagePeekMessage. 因此,只需在几次后卸载您的 dll UnhookWindowsHookEx- 您需要将消息发布到线程,您需要为其安装钩子。如果您为具体的单线程(dwThreadId)执行此操作-您需要PostThreadMessageW(dwThreadId, WM_NULL, 0, 0);-系统自己调用FreeLibrary(从user32!__ClientFreeLibrary哪个调用位置调用ntdll!KiUserCallbackDispatcher-在内部调用GetMessagePeekMessage在线程(或它的窗口)收到任何消息时调用)

为自己从 dll调用FreeLibrary- 总是错误 - 如果假设 dll 将被此调用卸载 - 调用后我们返回到哪里?到卸货的地方。在某些情况下调用FreeLibraryAndExitThread存在意义,但仅来自您自己创建的线程。从 dll 入口点调用FreeLibraryAndExitThread所有致命错误 - 你杀死的不是自线程,你杀死的线程 - 持有关键部分(加载器锁),其中调用 dll 入口点 - 所以致命错误。并且在这里完全没有意义的调用-如果您说收到DLL_PROCESS_DETACH这意味着dll已经在卸载过程中。DLL_THREAD_DETACH- 任意点,你为什么和多少次尝试在这里为自己调用卸载?退出线程,同时保持进程宽临界区而不释放它。致命错误。

因为安装钩子的同一线程必须卸载它。- 这不是真的。另一个线程也可以做到这一点。

StartTimer();你的代码在这里看起来也很可疑。这段代码是做什么的?在哪里取消计时器?

于 2019-01-06T09:51:42.917 回答