2016-05-16 8 views
1

Существует клавиатуру крюк установлен так:Краша после возвращения из процедуры крюка клавиатуры Windows,

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

(Это плагин, который хочет, чтобы перехватывать событие клавиатуры, которые получают отправленный его хозяину (64-разрядную версию), хотя хост не обеспечивает клавиатурные события для своих плагинов обычным способом. У меня нет исходного кода хоста, хотя у меня есть исходный код подключаемого модуля.)

После процедура крючка клавиатуры успешно запускается и возвращается, программа вылетает из строя. Сбой происходит внутри Windows 'ZwCallbackReturn(), выполняя инструкцию syscall. Исключением является 0XC0000005 (нарушение прав доступа). Сбой происходит только при нажатии определенной клавиши, которая вызывает определенную логику.

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

Я застрял диагностировать эту аварию и может реально использовать некоторую помощь. Я уверен, что проблема заключается в этом большом фрагменте кода, который находится в hook proc. У меня возникают проблемы с пониманием того, где произошел сбой, и где в основном разместить точку останова, чтобы выгрузить ее.


Дополнительная информация:

1) Подключаемая процедура действительно очень тяжелая, с большим количеством блокирующего ввода/вывода и использования памяти (она завершается в течение нескольких секунд на быстрой машине) , Возможно, это часть проблемы.

2) Если скомпилирован как 32-бит, стек сразу после аварии выглядит более интересно, но я сомневаюсь, что это можно доверять:

2a71f510() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
2a10f24a() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
AfxInternalPumpMessage() Line 153 C++ 
AfxWinMain(0x00000000, 0x00000020, 0x00000001, 1638280) Line 47 C++ 
@[email protected]() Unknown 

где верхние 5 строк повторяются много раз.


Вот что я пробовал до сих пор. Я понимаю, что инструкция syscall не генерирует исключение: регистры выглядят разумно, и я думаю, что стек остался бы таким же, если бы он разбился. Поэтому я думаю, что после того, как эта инструкция инициирует переход в режим ядра, откуда возникла «обратная связь с пользователем» (вызов процедуры hook), ядро ​​продолжает работать нормально. В конце концов он должен вернуть управление обратно в userland - GetMessage() Я полагаю). По дороге, я думаю, стек поврежден, и программа выйдет из строя. Но, к сожалению, я не могу проинструктировать моего отладчика Visual C++ для разрыва при первой инструкции пользовательского режима, прежде чем поврежден стек. Я попытался установить условные точки останова в TranslateMessage() и DispatchMessage(), которые, скорее всего, будут работать сразу после GetMessage(), но они не срабатывают между последней хорошей инструкцией пользователя и сбоем.

+0

'Крушение происходит только, если нажата конкретная клавиша, которая запускает какую-то определенную логику" - это немного неопределенно, чтобы мы могли различить, что может быть проблемой. –

+0

Если вы отделите всю логику от своего крючка и сразу вернетесь, она все равно сработает? Если нет, вы знаете, где искать. –

+0

Является ли плагин запущенным в том же процессе, что и хост? Если да, я предполагаю, что плагин - это DLL, которая загружается явно. Возможно ли, что DLL плагина разгружается, возможно, в ответ на нажатие клавиши? –

ответ

1

Авария произошла из-за того, что процедура крючка клавиатуры НЕ была первой в цепочке крючков. Он был вызван с предыдущего крючка в цепи крюка через CallNextHookEx(). И этот предыдущий крюк был зарегистрирован в DLL, который был выгружен внутри «нашего» клавишного крючка.

Следовательно, после того, как все вызванные вызовы были вызваны, элемент управления вернулся к первой процедуре захвата, которой больше не было. И авария пыталась выполнить недопустимый адрес.