информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Сетевые кракеры и правда о деле ЛевинаПортрет посетителяВсе любят мед
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Прописываться напрямую в реестр не рекомендую, нужно... 01.03.05 19:10  Число просмотров: 2240
Автор: leo <Леонид Юрьев> Статус: Elderman
Отредактировано 01.03.05 19:17  Количество правок: 2
<"чистая" ссылка>
Прописываться напрямую в реестр не рекомендую, нужно установить (и потом вернуть) права доступа, а в перспективе можно поиметь проблемы совместимости. Не сложнее через SetupAPI, ну конечно нужно разобраться для начала.

Если делать через inf-файлы, то нужно два inf-файла. Ничего сложного там нет, просто два как-бы независимых inf-файла со ссылкой на один sys-драйвер. Только одно условие - параметры InstallService должны быть одинаковые.
<programming>
Драйвер фильтра клавиатуры и мыши 16.02.05 11:56  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>
Надо связаться с DDK-ными фильтрами клавы и мыши (kbfiltr.c, moufiltr.c) как из Kernel (обратится из kbfiltr в moufiltr) так и из User mode.
Первый, и надеюсь, последний раз, пишу драйвер под W2K, чтение документации ничего не прояснило.
Что для фильтра нельзя задать DeviceName? Если задаю его при вызове IoCreateDevice, то ошибка. в kbfiltr.c вместо DeviceName в IoCreateDevice передается NULL. Как тогда связыватся с фильтром без имени? или надо обращаться к имени драйвера клавиатуры, а не фильтра?
В User mode пытаюсь определить имена имеющиеся драйверов. Вызываю SetupDiGetClassDevs(), затем SetupDiEnumDeviceInterfaces(), последний возвращает ERROR_NO_MORE_ITEMS. Смотрел несколько примеров из DDK использующих SetupDiEnumDeviceInterfaces() там тоже ERROR_NO_MORE_ITEMS.
Подскажите, как сделать, а то уже зашол в тупик.
PS:
А объединить два фильтра (клавы и мыши) в одном драйвере можно? Если да то как?
Связывайся, что мешает? [upd] 16.02.05 14:41  
Автор: amirul <Serge> Статус: The Elderman
Отредактировано 16.02.05 14:44  Количество правок: 1
<"чистая" ссылка>
> Надо связаться с DDK-ными фильтрами клавы и мыши
> (kbfiltr.c, moufiltr.c) как из Kernel (обратится из kbfiltr
> в moufiltr) так и из User mode.

Связывайся, что мешает?

> Что для фильтра нельзя задать DeviceName? Если задаю его

> при вызове IoCreateDevice, то ошибка. в kbfiltr.c вместо
> DeviceName в IoCreateDevice передается NULL. Как тогда
> связыватся с фильтром без имени? или надо обращаться к
> имени драйвера клавиатуры, а не фильтра?

Сам ответил на свой вопрос.

> В User mode пытаюсь определить имена имеющиеся драйверов.

Э-э-э. А зачем это?

> Вызываю SetupDiGetClassDevs(), затем
> SetupDiEnumDeviceInterfaces(), последний возвращает

Ну дык это ж интерфейсы девайса. Если ты при этом указал класс клавиатуры, то она использует для связи с третьим кольцом символические ссылки, а не интерфейсы и тебе совершенно правильно вернули статус отсутствия интерфейсов у этого девайса.

> ERROR_NO_MORE_ITEMS. Смотрел несколько примеров из DDK
> использующих SetupDiEnumDeviceInterfaces() там тоже
> ERROR_NO_MORE_ITEMS.
> Подскажите, как сделать, а то уже зашол в тупик.

Если тебе ДЕЙСТВИТЕЛЬНО надо перечислить все драйвера в системе, то гораздо приятнее пользоваться NtOpenDirectoryObject/NtQueryDirectoryObject


> PS:
> А объединить два фильтра (клавы и мыши) в одном драйвере
> можно? Если да то как?

По моему ты путаешь устройства (Device) и драйверы (Driver). Один драйвер может управлять произвольным количеством устройств в том числе и устройств-фильтров.
-----

А еще лучше пользоваться специально для этого предназначенной NtQuerySystemInformation
Немогу получить указатель на нужное устройство 17.02.05 07:51  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>
> > Надо связаться с DDK-ными фильтрами клавы и мыши
> > (kbfiltr.c, moufiltr.c) как из Kernel (обратится из kbfiltr
> > в moufiltr) так и из User mode.
>
> Связывайся, что мешает?

Что бы связаться с одним драйвером из другого, нужно, если я правильно понимаю, получить указатель на нужное устройство с помощью IoGetDeviceObjectPointer() вот он у меня возвращает ошибку (см. ниже).

> > В User mode пытаюсь определить имена имеющиеся
> драйверов.
>
> Э-э-э. А зачем это?

Хочу из диалогового окна на лету менять настройки драйвера (назначать горячие клавиши и т.д.),
обращаясь к KbFilter_IoCtl. Это приложение уже было написано для аналогичного VXD для W95. Хотел с минимальными переделками использовать его для W2K.
Так для CreateFile() нужно имя моего драйвера, вот и хотел с помощью вызовов SetupDiGetClassDevs(), затем SetupDiEnumDeviceInterfaces(), SetupDiGetDeviceInterfaceDetail() определить какое же имя подставлять в CreateFile().

> Ну дык это ж интерфейсы девайса. Если ты при этом указал
> класс клавиатуры, то она использует для связи с третьим
> кольцом символические ссылки, а не интерфейсы и тебе
> совершенно правильно вернули статус отсутствия интерфейсов
> у этого девайса.

Ладно, сейчас попробую через символическую ссылку.

> > А объединить два фильтра (клавы и мыши) в одном
> драйвере можно?
>
> Один драйвер может управлять произвольным
> количеством устройств в том числе и устройств-фильтров.

А как это сделать? Думал добавить в AddDevice DDK-ого драйвера фильтра клавиатуры следующий код:

RtlInitUnicodeString(&mouseDevName, L"\\Device\\PointerPort0" );
// Get a pointer to the Mouse device
status = IoGetDeviceObjectPointer(&mouseDevName, STANDARD_RIGHTS_ALL,
&DeviceFileObject, &mouseDevice);

devExt->mouseTopOfStack = IoAttachDeviceToDeviceStack(device, mouseDevice);

но status возвращаемый IoGetDeviceObjectPointer не успешен. Что сделано не так?
Дык, надо иметь в виду, что ты хоть и получаешь указатель на... 17.02.05 11:59  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Что бы связаться с одним драйвером из другого, нужно, если
> я правильно понимаю, получить указатель на нужное
> устройство с помощью IoGetDeviceObjectPointer() вот он у
> меня возвращает ошибку (см. ниже).

Дык, надо иметь в виду, что ты хоть и получаешь указатель на устройство, НА САМОМ ДЕЛЕ перед любым IoCallDriver-ом производится IoGetRelatedDeviceObject(), который возвращает ВЕРШИНУ стека (на самом деле все немного сложнее, но принцип понятен) и все обращения к устройству начинаются с самой вершины стека. Если в своем фильтре ты введешь свой IOCTL, ничто не мешает тебе НЕ передавать его вниз по стеку, а обработать прямо в своем фильтре.

> Хочу из диалогового окна на лету менять настройки драйвера
> (назначать горячие клавиши и т.д.),
> обращаясь к KbFilter_IoCtl. Это приложение уже было
> написано для аналогичного VXD для W95. Хотел с минимальными
> переделками использовать его для W2K.
> Так для CreateFile() нужно имя моего драйвера, вот и хотел
> с помощью вызовов SetupDiGetClassDevs(), затем
> SetupDiEnumDeviceInterfaces(),
> SetupDiGetDeviceInterfaceDetail() определить какое же имя
> подставлять в CreateFile().
Дык прям клавиатуре (и мыше) и посылай. У них всегда стандартные имена (\Device\KeyboardClassX и \Device\PointerClassX, где X - порядковый номер).

> Ладно, сейчас попробую через символическую ссылку.

А на фига фильтру символическая ссылка?

> А как это сделать? Думал добавить в AddDevice DDK-ого
> драйвера фильтра клавиатуры следующий код:

А ты на прототип AddDevice-а смотрел?

NTSTATUS
  XxxAddDevice(
    IN PDRIVER_OBJECT  DriverObject,
    IN PDEVICE_OBJECT  PhysicalDeviceObject 
    );

---

Про значение второго аргумента читал?

> RtlInitUnicodeString(&mouseDevName,
> L"\\Device\\PointerPort0" );

Не вдаваясь в то, что этого в AddDevice делать не нужно, а ты уверен, что устройство \Device\PointerPort0 существует?

> // Get a pointer to the Mouse device
> status = IoGetDeviceObjectPointer(&mouseDevName,
> STANDARD_RIGHTS_ALL,
>
> &DeviceFileObject, &mouseDevice);
>
> devExt->mouseTopOfStack =
> IoAttachDeviceToDeviceStack(device, mouseDevice);

А не легче аттачится прямо на переданный тебе PhysicalDeviceObject?

> но status возвращаемый IoGetDeviceObjectPointer не успешен.
> Что сделано не так?
Имя указано не так и само написание AddDevice-процедуры неверно. IO Manager сам найдет для тебя девайс, к которому ты должен приконнектиться и вызовет твою AddDevice процедуру, в которую передаст указатель на это устройство
Продолжаем разговор :-) , меня тут отвлекали на другую... 01.03.05 15:39  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>
Продолжаем разговор :-) , меня тут отвлекали на другую работу поэтому от меня небыло вопросов :-).

> По моему ты путаешь устройства (Device) и драйверы (Driver). Один драйвер может управлять >произвольным количеством устройств в том числе и устройств-фильтров.

<осталное я убрал>

>IO Manager сам найдет для тебя девайс, к которому
> ты должен приконнектиться и вызовет твою AddDevice
> процедуру, в которую передаст указатель на это устройство

Ну вроде я чего-то немного понял, написал драйвер который может управлять клавиатурой и мышью, а как Windows сказать, что один драйвер управляет и клавиатурой и мышью? Что сделать чтобы IO Manager вызвал мою AddDevice два раза (один раз для клавиатуры, другой раз для мыши)?
В примерах DDK фильтры клавиатуры и мыши в разных драйверах и там два разных inf файла. Если выполнить только inf фильтра клавиатуры из DDK, то в моем драйвере работает только фильтр клавиатуры.
Пробовал дополнительно выполнить inf фильтра мыши из DDK, заменив в нем moufiltr на kbfiltr, и удалив секцию Service Installation (т.к. Windows ругалась, что такой сервис уже установлен) , то в моем драйвере работает только фильтр мыши. Что нужно сделать чтобы все работало одновременно?
Читай внимательно насчет фильтров класса 01.03.05 16:12  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Пробовал дополнительно выполнить inf фильтра мыши из DDK,
> заменив в нем moufiltr на kbfiltr, и удалив секцию Service
> Installation (т.к. Windows ругалась, что такой сервис уже
> установлен) , то в моем драйвере работает только фильтр
> мыши. Что нужно сделать чтобы все работало одновременно?
Тебе нужно добавить свой драйвер в качестве фильтра для класса Keyboard это который {4D36E96B-E325-11CE-BFC1-08002BE10318} и для класса Mouse (который {4D36E96F-E325-11CE-BFC1-08002BE10318})

Можно и без inf-а обойтись

Просто прописаться в подветке HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class для этих классов в UpperFilters (там где mouclass и kbdclass). Только не вздумай сносить драйверы классов, которые там уже стоят - перестанет работать клавиатура и мышь - добавляй отдельной строкой
Наверно все не так просто 03.03.05 12:45  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>
> Можно и без inf-а обойтись

> Просто прописаться в подветке
> HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class
> для этих классов в UpperFilters

Наверно все не так просто. Где-то в инете была программка ctrl2cap, там именно так инсталлировался драйвер меняющий клавишу caps на ctrl. Когда я переделал ту программку для инсталляции kbfilter из DDK, то ничего не заработало (то есть ctrl2cap использующий IRP_MJ_READ работает, а kbfilter использующий ServiceCallback нет).

Заработало только когда я установил через диспетчер устройств для клавиатуры свой драйвер, взяв kbfiltr.inf из DDK.
Я посмотрел что изменилось в реестре после kbfiltr.inf:
в подветке HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318} в UpperFilters ничего не добавилось,

появилась подветка HKEY_LOCAL_MACHINE\CurrentControlSet\Control\CriticalDeviceDatabase\*pnp0baad
(*pnp0baad прописан в kbfiltr.inf) в этой подветке есть параметры:
ClassGUID - {4D36E96B-E325-11CE-BFC1-08002BE10318}
Service - i8042prt
UpperFilters - kbfilter

Еще появилась подветка HKEY_LOCAL_MACHINE\ CurrentControlSet\Enum\ACPI\PNP0303\<номер>
в этой подветке тоже есть параметры:
ClassGUID - {4D36E96B-E325-11CE-BFC1-08002BE10318}
Service - i8042prt
UpperFilters - kbfilter

В подветке HKEY_LOCAL_MACHINE\ CurrentControlSet\Services\kbfilter есть раздел Enum содержащий параметр со значением <номер> из ветки описанной выше.

Устанавливать через SetupAPI - надо долго разбираться.
Для установки той части драйвера что работает с мышью сделал так, как написал leo:
> Если делать через inf-файлы, то нужно два inf-файла
> параметры InstallService должны быть одинаковые.

Изменил в moufiltr.inf параметры InstallService и через диспетчер устройств установил для мыши свой драйвер. В реестр добавились аналогичные ветки, только ClassGUID другой. После чего работает только часть драйвера, отвечающая за блокировку мыши. Если в диспетчере устройств удалить драйвер для мыши, то нормально начинает работать часть драйвера отвечающая за блокировку клавиатуры.

Попробовал сделать тоже самое на другой машине, сначала через диспетчер устройств установил драйвер для клавиатуры (kbfiltr.inf), за тем для мыши (moufiltr.inf) В реестре все аналогично, единственное отличие - наличие раздела Security на первой машине в ветке HKEY_LOCAL_MACHINE\ CurrentControlSet\Services\kbfilter, на второй машине он не появился.
Получилось наоборот блокировка клавиатуры работает, а блокировка мыши нет курсор двигается, хотя вроде не должен и на первой машине после блокировки он не двигается. Единственное, что в момент блокировки перестают запускаться программы с рабочего стола по двойному щелчку, а в Far-e мышь полностью работает.
MouFilter_ServiceCallback у меня выглядит так:

VOID
MouFilter_ServiceCallback(
IN PDEVICE_OBJECT DeviceObject,
IN PMOUSE_INPUT_DATA InputDataStart,
IN PMOUSE_INPUT_DATA InputDataEnd,
IN OUT PULONG InputDataConsumed
)
{
PCOMMON_DATA commonData;
PMOUSE_INPUT_DATA MouseData;
ULONG l_inputDataConsumed = 0;

*InputDataConsumed = 0;

commonData = GET_COMMON_DATA(DeviceObject->DeviceExtension);

for(MouseData = InputDataStart; MouseData < InputDataEnd; MouseData++)
{
if( Globals.LockFlag ) { //если клавиатура и мышь заблокирована
*InputDataConsumed = *InputDataConsumed + 1;
}
else { // клавиатура и мышь не заблокирована

if( MouseData->Buttons != 0) { //есть нажатые кнопки?
cnt_tick = lock_tick; //заново устанавливаем счетчик тиков до блокировки
}

l_inputDataConsumed = 0;

(*(PSERVICE_CALLBACK_ROUTINE) commonData->UpperConnectData.ClassService)(
commonData->UpperConnectData.ClassDeviceObject,
MouseData,
MouseData+1,
&l_inputDataConsumed);

if ( l_inputDataConsumed==0 ) return;

*InputDataConsumed += l_inputDataConsumed;

}
}
}

Короче теперь вообще не знаю, что я делаю не так?
Дык 03.03.05 13:00  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Заработало только когда я установил через диспетчер
> устройств для клавиатуры свой драйвер, взяв kbfiltr.inf из
> DDK.
> Я посмотрел что изменилось в реестре после kbfiltr.inf:
> в подветке
> HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{
> 4D36E96B-E325-11CE-BFC1-08002BE10318} в UpperFilters ничего
> не добавилось,

Тут прописываются фильтры класса. То есть драйвер фильтра для ВСЕХ клавиатур, которые появляются в системе.

> появилась подветка
> HKEY_LOCAL_MACHINE\CurrentControlSet\Control\CriticalDevice
> Database\*pnp0baad
> (*pnp0baad прописан в kbfiltr.inf) в этой подветке есть
> параметры:
> ClassGUID - {4D36E96B-E325-11CE-BFC1-08002BE10318}
> Service - i8042prt
> UpperFilters - kbfilter

Честно говоря, я не знаю что такое CriticalDeviceDatabase - ни разу с ней не встречался. Но похоже на ключ самого устройства. То есть здесь прописываются фильтры для КОНКРЕТНОЙ клавиатуры, хотя и не уверен

> Еще появилась подветка HKEY_LOCAL_MACHINE\
> CurrentControlSet\Enum\ACPI\PNP0303\<номер>
> в этой подветке тоже есть параметры:
> ClassGUID - {4D36E96B-E325-11CE-BFC1-08002BE10318}
> Service - i8042prt
> UpperFilters - kbfilter

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

> В подветке HKEY_LOCAL_MACHINE\
> CurrentControlSet\Services\kbfilter есть раздел Enum
> содержащий параметр со значением <номер> из ветки
> описанной выше.

Это все создастся на лету.
Вот еще что стоит выяснить 03.03.05 13:37  
Автор: leo <Леонид Юрьев> Статус: Elderman
Отредактировано 03.03.05 13:40  Количество правок: 1
<"чистая" ссылка>
Конкретный драйвер (sys-файл) может обслуживать несколько устройств, обслуживать несколько устройств разных классов, быть фильтром для типа устройств (с одним HARDWARE_ID) и при этом обслуживать устройства других классов.

Я не проверял, но нет причин чтобы один драйвер не мог быть фильтром для нескольких конктерных разных устройств, или одновременно upper- и lower-фильтром.

Но, например, один драйвер не может быть мини-портом (например ndis) и полноценным драйвером или фильтром, поскольку RegisterMiniport модифицирует dispatсh-таблицу адресов функций. Это можно обойти, но сейчас речь не об этом.

К чему все это.. - может быть один драйвер не может быть одновременно фильтром для двух разных классов устройств, может это просто не предусмотрено в логике работы pnp-менеджера (и еже с ним) при "сборке" стека драйверов?

Это IMHO нужно выяснить, потому что правильнее и логичнее ставить драйвер как описал amirul - фильтром для класса, а не как фильтр для конкретного устройства. Иначе "блокировка" обходится подключением еще одной usb-мыши или клавиатуры.

Теперь про ServiceCallback, я никогда его не использовал и кажется даже не читал доку. Но, если подумать, то причина того, что работает (как я понимаю) только одна часть драйвера из двух скорее всего в том, что установка второго Callback-а "убивает" первый. Может все тоже сведется к тому, что модифицируется dispatсh-таблица драйвера?
Я помогал в написании кейлоггера 03.03.05 16:55  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
Правда как это принято сейчас он выполнял гораздо больше функций, чем просто перехват нажатий на кнопки.

> К чему все это.. - может быть один драйвер не может быть
> одновременно фильтром для двух разных классов устройств,
> может это просто не предусмотрено в логике работы
> pnp-менеджера (и еже с ним) при "сборке" стека драйверов?

В частности, драйвер этого кейлоггера был фильтром для keyboard и pointer классов, TDI-фильтром, фильтром системных сервисов (модифицировал KeServiceDescriptorTable) и прочая. Хотя справедливости ради следует отметить, что через AddDevice он становился только поверх клавиатур и мышей (был фильтром обоих этих классов), все остальные привязки выполнялись в DriverEntry.

Так что могу со всей ответственностью заявить, PnP-Manager никаких проверок на единственность не делает. Единственное, о чем нужно заботиться - разделять типы устройств в dispatch-функциях.

> Это IMHO нужно выяснить, потому что правильнее и логичнее
> ставить драйвер как описал amirul - фильтром для класса, а
> не как фильтр для конкретного устройства. Иначе
> "блокировка" обходится подключением еще одной usb-мыши или
> клавиатуры.

ЗЫ: Кстати, в этом кейлоггере драйвер прописывался фильтром напрямую в реестре :-)
Вывод из драйвера на экран 04.03.05 16:23  
Автор: ValEG Статус: Незарегистрированный пользователь
Отредактировано 11.03.05 11:18  Количество правок: 1
<"чистая" ссылка>
> В частности, драйвер этого кейлоггера был фильтром для
> keyboard и pointer классов
>
> ЗЫ: Кстати, в этом кейлоггере драйвер прописывался фильтром
> напрямую в реестре :-)

Переписал свой драйвер, подключил фильтром классов как описал amirul, вроде заработало.

Вроде уже почти все сделал, что хотел.
А вот можно ли из драйвера вывести что-нибудь на экран поверх всех окон, строку или хотя бы квадратик, какой ни будь, а потом восстановить содержимое экрана. Ведь некоторые клавиатуры имеющие дополнительные клавиши, например для управления громкостью, при нажатии на эти клавиши выводят на экран надпись "Громкость" и т.д. поверх всех окон, огромными буквами. Хотелось бы тоже для пользователя из своего драйвера выводить надписи на экран, как это сделать?
Правильным способом будет держать в третьем кольце программу 11.03.05 12:21  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
Которая будет общаться с драйвером и рисовать на экране чего хошь.

Хотя можно и использовать всякие NtGdiXxx сервисы. Но это ПМСМ не нужно
А как лучше это сделать? Обращаться из третьего кольца к... 15.03.05 07:47  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>
> Правильным способом будет держать в третьем кольце программу
> Которая будет общаться с драйвером и рисовать на экране
> чего хошь.

А как лучше это сделать? Обращаться из третьего кольца к драйверу по несколько раз в секунду, проверяя его состояние? Хотя может вызывать несколько раз в секунду DeviceIoControl() - это не так накладно для процессора. Может есть какой другой способ?
Есть как минимум два правильных способа и целая куча неправильных 15.03.05 10:52  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> А как лучше это сделать? Обращаться из третьего кольца к
> драйверу по несколько раз в секунду, проверяя его
> состояние? Хотя может вызывать несколько раз в секунду
> DeviceIoControl() - это не так накладно для процессора.
> Может есть какой другой способ?

Правильный способ №1:
DeviceIoControl, драйвер принимает его и возвращает STATUS_PENDING. Сам DeviceIoControl можно запустить в синхронном режиме в отдельном потоке, тогда поток вернется из этой функции только после того, как IRP с этим запросом будет завершен. Либо можно запустить DeviceIoControl в асинхронном режиме (OVERLAPPED в Win32) и дальше делать что угодно: периодически проверять статус, ожидать на событии и пр. - любой тип синхронизации, который нравится.

Правильный способ №2:
Поставить какой нибудь поток в состояние "тревожного ожидания" (alertable wait mode). И в драйвере поставить в этот поток APC user-ского режима. (этот способ более сложный но тем не менее вполне правильный - насколько я знаю, именно так доставляются оконные сообщения в Win32).

Ну а неправильные: постоянный полл, постоянный полл с задержками и прочие извращения
Как вызвать драйвер нижнего уровня? 16.03.05 07:41  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>
> Правильным способом будет держать в третьем кольце программу с вызовом
> DeviceIoControl, драйвер принимает его и возвращает
> STATUS_PENDING.

Спасибо, за совет, будет время, попробую так сделать, если получится.
Конечно было бы лучше пример кода, а то пока плохо у меня все получается :(
Вот, например, захотелось помигать индикаторами на клавиатуре из процедуры таймера, но при вызове IoBuildDeviceIoControlRequest компьютер уходит на перезагрузку, что не так, может это делают по-другому?

KEVENT event;
NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK iosb;
PIRP irp;

KEYBOARD_INDICATOR_PARAMETERS InputBuffer;

InputBuffer.UnitId = 0;
InputBuffer.LedFlags = KEYBOARD_NUM_LOCK_ON | KEYBOARD_CAPS_LOCK_ON | KEYBOARD_SCROLL_LOCK_ON;

KeInitializeEvent(&event,
NotificationEvent,
FALSE
);

DbgPrint("KbFilter_SendIoctl: Target 0x%08lx\n", KeyboardDeviceObject);

// return status; // здесь еще работает

if (NULL == (irp = IoBuildDeviceIoControlRequest(
IOCTL_KEYBOARD_SET_INDICATORS,
KeyboardDeviceObject,
(PVOID) &InputBuffer,
sizeof(KEYBOARD_INDICATOR_PARAMETERS)
NULL,
0,
TRUE,
&event,
&iosb))) {

return STATUS_INSUFFICIENT_RESOURCES;
}

// return status; // а тут уже ПК идет на перезагрузку


status = IoCallDriver(KeyboardDeviceObject, irp);

if (STATUS_PENDING == status) {

status = KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE, // Not alertable
NULL); // No timeout structure

ASSERT(STATUS_SUCCESS == status);
status = iosb.Status;
}

return status;

переменная KeyboardDeviceObject задается в AddDevice:

status = IoCreateDevice(Driver,
maxSize,
NULL,
FILE_DEVICE_UNKNOWN, // неизвестно для клавиатуры или мышы создается устройство
0,
FALSE,
&device
);

RtlZeroMemory(device->DeviceExtension, sizeof(maxSize));

devExt = (PKEYBOARD_DEVICE_EXTENSION) device->DeviceExtension;
devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO);

if ( IsKeyboard ) KeyboardDeviceObject = devExt->TopOfStack;
Ну IoCallDriver-ом и вызывать 16.03.05 11:40  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Спасибо, за совет, будет время, попробую так сделать, если
> получится.
> Конечно было бы лучше пример кода, а то пока плохо у меня
> все получается :(

Пример есть в ddk samples-ах. Например именно так работает IOCTL_SERIAL_WAIT_ON_MASK в src/kernel/serial

> Вот, например, захотелось помигать индикаторами на
> клавиатуре из процедуры таймера, но при вызове
> IoBuildDeviceIoControlRequest компьютер уходит на
> перезагрузку, что не так, может это делают по-другому?

Во первых выключи автоматическую перезагрузку:
Мой компютер (правой кнопкой)->Свойства->Дополнительно (вкладка)->Параметры (в группе "Загрузка и восстановление")->Чекбокс Выполнить автоматическую перезагрузку (в группе "Отказ системы") выключить

Кроме того неплохо было бы поставить какой нибудь отладчик уровня ядра (SoftICE или KD - кому что нравится)

> if (NULL == (irp = IoBuildDeviceIoControlRequest(
> IOCTL_KEYBOARD_SET_INDICATORS,
> KeyboardDeviceObject,
> (PVOID) &InputBuffer,
>
> sizeof(KEYBOARD_INDICATOR_PARAMETERS)
> NULL,
> 0,
> TRUE,
> &event,
> &iosb))) {
>
> return STATUS_INSUFFICIENT_RESOURCES;
> }
>
> // return status; // а тут уже ПК идет на перезагрузку

Скорее всего твой bugcheck IRQL_NOT_LESS_OR_EQUAL. Дело в том, что практически все функции I/O manager-а должны вызываться на IRQL == PASSIVE_LEVEL, если больше - то вылетает этот багчек.

> status = IoCallDriver(KeyboardDeviceObject, irp);
>
> if (STATUS_PENDING == status) {
>
> status = KeWaitForSingleObject(&event,
> Executive,
> KernelMode,
> FALSE, // Not alertable
> NULL); // No timeout
> structure
>
> ASSERT(STATUS_SUCCESS == status);

Зря ты ассерт на такую проверку поставил. С чего ты взял, что ожидание НЕ МОЖЕТ вернуться со статусом отличным от STATUS_SUCCESS?

> status = iosb.Status;
> }
>
> return status;
>
> переменная KeyboardDeviceObject задается в AddDevice:
>
> status = IoCreateDevice(Driver,
> maxSize,
> NULL,
> FILE_DEVICE_UNKNOWN, //
> неизвестно для клавиатуры или мышы создается устройство

Здесь лучше использовать PhysicalDeviceObject->DeviceType (где PhysicalDeviceObject - второй аргумент твоего обработчика AddDevice).

> 0,
> FALSE,
> &device
> );
>
> RtlZeroMemory(device->DeviceExtension,
> sizeof(maxSize));

Неправильно, тебе надо указывать не размер ПЕРЕМЕННОЙ maxSize, а ее значение

> devExt = (PKEYBOARD_DEVICE_EXTENSION)
> device->DeviceExtension;
> devExt->TopOfStack =
> IoAttachDeviceToDeviceStack(device, PDO);

Не проверяешь возвращенное значение. Оно МОЖЕТ быть NULL, а у тебя могут быть проблемы когда оно будет NULL

> if ( IsKeyboard ) KeyboardDeviceObject =
> devExt->TopOfStack;
Как избавиться от ошибки? 17.03.05 12:49  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>
> Кроме того неплохо было бы поставить какой нибудь отладчик
> уровня ядра (SoftICE или KD - кому что нравится)

SoftICE нету, есть WinDbg, но слишком долго разбираться как с ним работать (а сегодня я должен все закончить)
По быстрому разобраться с WinDbg по документации не получилось, понял что надо соединить два ПК нулмодемным кабелем, а дальше?
Поэтому пока работаю без отладчика, использую DbgPrint() если что надо посмотреть.

> Скорее всего твой bugcheck IRQL_NOT_LESS_OR_EQUAL. Дело в
> том, что практически все функции I/O manager-а должны
> вызываться на IRQL == PASSIVE_LEVEL, если больше - то
> вылетает этот багчек.

не знаю, я тут немного переписал процедуру зажигания светодиодов клавиатуры (заменил IoBuildDeviceIoControlRequest на IoAllocateIrp, думал поможет, ... не помогло)
Cейчас на экране - KMODE_EXCEPCION_NOT_HANDLED
Главное этот же самый код, перенесенный один в один в мой KbFilter_IoCtl, нормально создает новый IRP и зажигает светодиоды, если я вызываю KbFilter_IoCtl с помощью DeviceIoControl из user mode. Конечно, можно сделать таймер в Win32 и оттуда мигать светодиодами, но приложение могут например случайно или специально выгрузить.

Поэтому хотелось бы сделать по таймеру драйвера, но если переношу вызов процедуры из KbFilter_IoCtl в TimerRoutine драйвера, вызываемую раз в секунду, то появляется KMODE_EXCEPCION_NOT_HANDLED. Можно как-нибудь сделать в драйвере периодический вызов процедуры зажигания светодиодов чтобы данная ошибка не появлялась?

> > status = IoCreateDevice(Driver,
> > maxSize,
> > NULL,
> > FILE_DEVICE_UNKNOWN, //
> > неизвестно для клавиатуры или мышы создается
> устройство

а с FILE_DEVICE_UNKNOWN так было сделано в i8042prt.sys, оттуда и перетощил, проблем небыло.

> Здесь лучше использовать
> PhysicalDeviceObject->DeviceType (где
> PhysicalDeviceObject - второй аргумент твоего обработчика
> AddDevice).

Сделал как ты написал, а проблем не будет? т.к. значение PhysicalDeviceObject->DeviceType и для клавиатуры и для мышы при вызове AddDevice у меня == 32 (FILE_DEVICE_ACPI)

В начале процедуры AddDevice я инициализирую переменную IsKeyboard, анализируя ClassGuid возвращаемый при вызове мной IoGetDeviceProperty()
может лучше там-же вызвать IoCreateDevice с соответствующим FILE_DEVICE_KEYBOARD или FILE_DEVICE_MOUSE?
IMHO это очень плохая идея, не нужно уподобляться китайцам и... 17.03.05 15:58  
Автор: leo <Леонид Юрьев> Статус: Elderman
<"чистая" ссылка>
> SoftICE нету, есть WinDbg, но слишком долго разбираться как
> с ним работать (а сегодня я должен все закончить)
IMHO это очень плохая идея, не нужно уподобляться китайцам и делать как-помало.
Очень советую включить проверку всей ветки стека драйверов (verifier.exe).

> По быстрому разобраться с WinDbg по документации не
> получилось, понял что надо соединить два ПК нулмодемным
> кабелем, а дальше?
Там все очень хорошо описано, буквально в трех разделах.
Если есть второй комп и кабель, это хорошо, еще лучше через FireWire.
Если нет, то можно отлаживаться на виртуальной машине (Virtual PC 2004), на форуме это обсуждалось.

> не знаю, я тут немного переписал процедуру зажигания
> светодиодов клавиатуры (заменил
> IoBuildDeviceIoControlRequest на IoAllocateIrp, думал
> поможет, ... не помогло)
> Cейчас на экране - KMODE_EXCEPCION_NOT_HANDLED
> Главное этот же самый код, перенесенный один в один в мой
> KbFilter_IoCtl, нормально создает новый IRP и зажигает
> светодиоды, если я вызываю KbFilter_IoCtl с помощью
> DeviceIoControl из user mode. Конечно, можно сделать таймер
> в Win32 и оттуда мигать светодиодами, но приложение могут
> например случайно или специально выгрузить.

В DDK всё достаточно хорошо описано, я не уверен что у кого-то найдется достаточно времени желяния чтобы анализировать и спвравлять ваш код.

> Поэтому хотелось бы сделать по таймеру драйвера, но если
> переношу вызов процедуры из KbFilter_IoCtl в TimerRoutine
> драйвера, вызываемую раз в секунду, то появляется
> KMODE_EXCEPCION_NOT_HANDLED. Можно как-нибудь сделать в
> драйвере периодический вызов процедуры зажигания
> светодиодов чтобы данная ошибка не появлялась?
>
Как писал amirul Таймеры "срабатывают" на DPC уровне, можно обойтись без них, создав thread в режиме ядра, или цикличеки ставя WorkItem в очередь (IoQueueWorkItem) и просто делая паузу в обработчике (KeDelayThreadExecution или KeWaitFor...).

Самый правильный путь IMHO - в процедуре таймера использовать отложенную очередь (IoQueueWorkItem) и уже потом, на PASSIVE_LEVEL делать что нужно.

> В начале процедуры AddDevice я инициализирую переменную
> IsKeyboard, анализируя ClassGuid возвращаемый при вызове
> мной IoGetDeviceProperty()
> может лучше там-же вызвать IoCreateDevice с соответствующим
> FILE_DEVICE_KEYBOARD или FILE_DEVICE_MOUSE?

ClassGuid независим от типа устройства (FILE_DEVICE_KEYBOARD или FILE_DEVICE_MOUSE). Тип устройств - это по-сути устаревшее наследство от NT4, а ClassGuid как-раз новая замена. Но тип устройств еще где-то используется, точнее я уже не помню.
Всем спасибо! 24.03.05 05:18  
Автор: ValEG Статус: Незарегистрированный пользователь
<"чистая" ссылка>

> Самый правильный путь IMHO - в процедуре таймера
> использовать отложенную очередь (IoQueueWorkItem) и уже
> потом, на PASSIVE_LEVEL делать что нужно.

Спасибо за подсказку.
Вроде все сделал.
Так же огромное спасибо amirul за ответы, которые помогли мне в написании драйвера.

PS:
А если придется переписать драйвер с W2K на ХР, насколько там большие отличия и что надо будет изменить?
2k-шный драйвер будет без изменений работать на XP/2k3 Server и т.д. 24.03.05 12:28  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
1  |  2 >>  »  




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 1 s   Design: Vadim Derkach