从Windows键盘挂钩程序返回后崩溃

时间:2016-05-16 19:08:08

标签: windows winapi hook setwindowshookex

这样安装了一个键盘钩:

s_hKeyboardHook = ::SetWindowsHookEx(WH_KEYBOARD, KeyboardHookProc, nullptr, ::GetCurrentThreadId());

(这是一个插件,它想拦截发送到主机(64位)的键盘事件,即使主机没有以正常方式向其插件提供键盘事件。我不是有主机的源代码,虽然我有插件的源代码。)

键盘钩子程序成功运行并返回后,程序崩溃。崩溃发生在Windows' ZwCallbackReturn(),执行syscall指令。例外是0XC0000005(访问冲突)。只有在按下特定键时触发某些特定逻辑才会发生崩溃。

This is how it looks like in the debugger (animated gif)

我被困在诊断这次崩溃并且真的可以使用一些帮助。我确信问题出在钩子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()之后运行,但它们不会在最后一个良好的用户模式指令和崩溃。

1 个答案:

答案 0 :(得分:2)

发生崩溃是因为键盘钩子程序不是钩子链中的第一个。它是通过CallNextHookEx()从钩链中的前一个钩子调用的。而之前的挂钩是由一个DLL注册的,它已被卸载到内部"我们的"键盘钩。

因此,在最终调用了所有钩子后,控件返回到第一个钩子程序,该程序不再存在。崩溃试图执行无效的地址。