这样安装了一个键盘钩:
s_hKeyboardHook = ::SetWindowsHookEx(WH_KEYBOARD, KeyboardHookProc, nullptr, ::GetCurrentThreadId());
(这是一个插件,它想拦截发送到主机(64位)的键盘事件,即使主机没有以正常方式向其插件提供键盘事件。我不是有主机的源代码,虽然我有插件的源代码。)
键盘钩子程序成功运行并返回后,程序崩溃。崩溃发生在Windows' ZwCallbackReturn()
,执行syscall
指令。例外是0XC0000005
(访问冲突)。只有在按下特定键时触发某些特定逻辑才会发生崩溃。
我被困在诊断这次崩溃并且真的可以使用一些帮助。我确信问题出在钩子proc中的这一大块代码中。我遇到的问题是了解崩溃发生的位置以及断点在哪里抢占它。
其他信息:
1)钩子程序真的很重,有很多阻塞,i / o和内存使用(它在快速机器上完成几秒钟)。也许这就是问题的一部分。
2)如果编译为32位,崩溃后的堆栈看起来更有趣,但我怀疑它是否可信:
2a71f510() Unknown
ExecuteHandler2@20() Unknown
ExecuteHandler@20() Unknown
_RtlDispatchException@8() Unknown
_KiUserExceptionDispatcher@8() Unknown
2a10f24a() Unknown
_DispatchHookW@16() Unknown
_CallHookWithSEH@16() Unknown
___fnHkINDWORD@4() Unknown
_KiUserCallbackDispatcher@12() Unknown
_LdrAddLoadAsDataTable@20() Unknown
AfxInternalPumpMessage() Line 153 C++
AfxWinMain(0x00000000, 0x00000020, 0x00000001, 1638280) Line 47 C++
@BaseThreadInitThunk@12() Unknown
前5行重复多次。
这是我到目前为止所尝试的内容。我的理解是syscall
指令本身并没有产生异常:寄存器看起来很清晰,我想如果它崩溃,堆栈将保持不变。所以我认为在这个指令之后启动转换回内核模式,从那里"用户回调" (钩子程序调用)已经发起,内核继续运行就好了。最终它应该将控制权返回给用户空间 - 我认为是GetMessage()
。接下来,我认为,堆栈已损坏,程序崩溃。但遗憾的是,在堆栈损坏之前,我无法指示我的Visual C ++调试器在执行的第一个用户模式指令时中断。我尝试在TranslateMessage()
和DispatchMessage()
中安装条件断点,这些断点最有可能在GetMessage()
之后运行,但它们不会在最后一个良好的用户模式指令和崩溃。
答案 0 :(得分:2)
发生崩溃是因为键盘钩子程序不是钩子链中的第一个。它是通过CallNextHookEx()
从钩链中的前一个钩子调用的。而之前的挂钩是由一个DLL注册的,它已被卸载到内部"我们的"键盘钩。
因此,在最终调用了所有钩子后,控件返回到第一个钩子程序,该程序不再存在。崩溃试图执行无效的地址。