Есть у меня клавиатурный фильтр, изначально писанный под NT4. Соответственно, Legacy, для присоединения к клавиатурным устройствам использовавший IoAttachDevice по именам (DD_KEYBOARD_DEVICE_NAME плюс номер). Все прекрасно работало, драйвер в любой момент можно было выгрузить. Затем появилась 2k с поддержкой USB-клавиатур, и выяснилось, что к ним IoAttachDevice цепляться не хочет. Тогда я не стал вдаваться в проблему, а переделал, как рекомендовали Руссинович с Соломоном, на стандартный PnP-фильтр, цепляемый через UpperFilters, и получающий DEVICE_OBJECT'ы через AddDevice. Все опять-таки прекрасно работает, за исключением невозможности поставить/удалить/перезапустить драйвер без перезагрузки.
Сейчас у меня дошли руки его немного доработать, и перезагрузка целевой машины после каждой модификации (а если упал — то и двойная) уже достала. Решил переделать обратно в динамическое присоединение, тем более, что обработка Remove и Surprise Removal там уже есть, дело только за получением DEVICE_OBJECT целевого устройства. При попытке присоединения к устройству USB-клавиатуры IoAttachDevice возвращает STATUS_SHARING_VIOLATION, а ей это возвращает IoGetDeviceObjectPointer. Последняя работает через ZwOpenFile.
Собственно, вполне понятно, что системный процесс, сидящий на USB-клавиатуре, открыл устройство с запретом шаринга. По факту, мне и не нужен клиентский доступ, с получением FILE_OBJECT — достаточно простого увеличения RefCount. Если нахожу адрес объекта вручную, и затем передаю его IoAttachDeviceToDeviceStack — все прекрасно цепляется, работает, при выдергивании клавиатуры — отцепляется, при неотцепленной клавиатуре система корректно уходит в шатдаун, драйвер в любой момент выгружается, Verifier ни на него, ни на kbdclass не обижается. То есть, проблема исключительно в получении адреса объекта устройства.
В принципе, я могу тупо находить объект драйвера по постоянно присутствующему устройству \Device\KeyboardClass0, сканировать все его объекты устройств, и цепляться к каждому, но это уже попахивает грязным хаком.
Может, есть сравнительно честный способ получения адреса устройства по имени иначе, чем через его полноценное клиентское открывание?