На данный момент занимаюсь созданием клавиатурного шпиона. Физически он представляет (должен представлять) собой драйвер фильтр клавиатуры (огромное спасибо Four-F, за его полезный во всех отношениях цикл статей). Этот фильтр сохраняет информацию о нажатых символах, а также целевом приложении и окне ввода в файл. Не смотря на то что всё довольно тривиально, накопилось множество вопросов на часть которых ответил всезнающий гугл, на часть - Руссинович и Four-F в своих, заслуживающих всяческих похвал, трудах. Однако, неотвеченных вопросов осталось ещё очень много. Буду очень признателен за ссылки на исходники аналогичных шпионов (мне, признаться, не удалось найти ни одного шпиона выполненого в виде WDM или legacy драйвера-фильтра с исходниками). Так вот, собственно, самые волнующие вопросы : 1. Как узнать что за приложение запросило этот самый ввод с клавиатуры? Я так полагаю это делается при получении IRP_MJ_READ при запросе на ввод от csrss.exe, но кому в дальнейшем предназначаются этот ввод драйвер, вроде бы, не ведает. 2. Как лучше организовать запись в файл собранной информации? В процедуре завершения IRP_MJ_READ запись делать нельзя. Может следует это делать вызовом процедуры записи по таймеру? 3. Можно ли устройство фильтр создавать в DriverEntry и там же приаттачивать его к стеку устройств клавиатуры? Вопрос возник поскольку в ответ на все свои попытки я видел только синий экран, и весь вчерашний вечер мне напоминал басню про мартышку и очки . Заранее спасибо.
1. Никак. csrss просто в цикле делает NtReadFile, что приводит к формированию IRP_MJ_READ и посылке его в стек, где он ставится в очередь. Когда нажимается, IRP завершается. Но никакой информации относительно текущих процессов или окон с фокусом ввода там нет. Это проблемы csrss. 2. Нет, это делается с помощью системных рабочих потоков (Work Items). Если правильно помню, например, в klog так и делается. Klog - A Filter Driver Example Using A Kernel Key Logger: http://www.rootkit.com/newsread.php?newsid=187 http://www.rootkit.com/vault/Clandestiny/Klog%201.0.zip 3. Теоретически можно. Хорошая статья по теме: Unloading those pesky keyboard filter drivers! http://www.rootkit.com/newsread.php?newsid=398
Four-F *1* а что мешает узнать фокус окна? когда-то очень давно, когда я только пытался писать драйвера под 9x, я сделал так: 1) ставлю драйвер, хавающий ввод с клавы 2) ставлю user-mode резидента, который при смене фокуса окна сообщает об этом моему драйверу через devioctl вместе с именем окна/процессом и другой инфой. 3) драйвер запоминает эту инфу и до следующего переключения фокуса относит все нажатые клавиши к данному окну/процессу минусы: сейчас я вижу, что это кривой способ, не гарантирующий вообще ничего!!! многие клавиши идут мимо фокуса (например, ctrl-shift-esc) у рихтера подробно описан процесс "траспортироки" клавиатурного ввода, от сырого потока до разбиения по нитям, я сейчас уже не помню всех подробностей и так с ходу не скажу, что нужно перехватывать, чтобы понять кто _реально_ сожрал нащи символы, а кому их только показали но, имхо... для многих задач и моего решения вполне достаточно...
Ну как-то конечно можно узнать. Csrss же узнаёт. Я имел ввиду, что из самого IRP этого узнать нельзя.
А какая разница? Код, который может вызываться на высоких IRQL, нельзя выгружать. Посмотри в DDK главы "Paging an Entire Driver" и "MmPageEntireDriver"
Вроде как пример клавиатурного (и мышиного тоже) драйвер-фильтра входит в Samples NTDDK... Вот даже посмотрел на пути, у меня "NTDDK\src\input\kbfiltr\" -- это и есть клавиатурный драйвер-фильтр. Еще вроде был примерчик с сырцами клавиатурного драйвер-фильтра на www.sysinternals.com
DO_POWER_PAGABLE заставляет менеджер вызывать все обработчики IRP для данного девайса на уровне PASSIVE_LEVEL полагаю, то же относится и к CompletionRoutine
Нет. Только Power IRPs. Ни в коем случае. DO_POWER_PAGABLE и любой другой DO_XXX флаг вообще не влияет на IRQL в CompletionRoutine.
Тема эта темная, клавиатурный шпион из драйвера: куча проблем таких как правильное получение имени активного окна, его процесса и т.п. (без использования других прог из под ring-3, вообщем придется делать шелл-код, инжектировать его в какой-нибудь процесс и главное ГАРАНТИРОВАТЬ ЕГО ПРАВИЛЬНУЮ РАБОТУ И СОВМЕСТИМОСТЬ) - я это сделал, было очень и очень непросто. Не говоря о передачи данных через интернет в обход фаеров (а иначе нафиг извращаться с ring-0). Тут нужно хорошо расчитать свои силы. Почитай на rootkit.com статейку Valeryno о запуске процесса из под ring-0 там то что надо, тока там ошибка в коде, надо 1 nop убрать. Читай rootkit.com.
Конвертил в драйвере, а локаль вместе с данными передовалась, тока это не просто, да и вообще нужно куча времени на тестрирование (я натыкался на кучу подводных камней). Лучше локаль в юзермоде конвертить, так надежнее, но сложно в шэлл добавить.