IoGetDeviceProperty - нужна помощь

Тема в разделе "WASM.NT.KERNEL", создана пользователем cc, 10 дек 2006.

  1. cc

    cc New Member

    Публикаций:
    0
    Регистрация:
    15 окт 2006
    Сообщения:
    34
    Здравствуйте. Возникла проблема с использованием IoGetDeviceProperty, точнее даже не проблема, а некоторое недопонимание ее использование. А именно с первый параметром - PDEVICE_OBJECT DeviceObject. Это, как следует из MSDN'а, указатель на POD. Как я понял, POD - есть ничто иное, как самое нижнее устройство стека фильтров. Теперь вопрос: как получить этот самый POD, если у меня из исходных данных только имя устройства, например \Device\Harddisk2\DP(1)0-0+5?

    Буду благодарен любой помощи.

    P.S. Просьба сильно не пинать, я в низкоуровневом программировании сравнительно недавно.

    P.P.S. К гуглу не посылать, поиском на форуме пользовался =)
     
  2. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    IoGetDeviceObjectPointer с параметром <имя устройства>
     
  3. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Только она вернёт указатель не на сам PDO, а на вершину стека, если конечно над PDO кто-то сидит. Если скормить этот указатель IoGetDeviceProperty - BSOD. Нужно сперва спуститься до PDO. Под ХР и выше можно использовать IoGetDeviceAttachmentBaseRef.

    http://www.wasm.ru/forum/viewtopic.php?id=16125
     
  4. cc

    cc New Member

    Публикаций:
    0
    Регистрация:
    15 окт 2006
    Сообщения:
    34
    Four-F
    Ссылку глянул, почитал доки. Один только вопрос остался (только не смейтесь товарищи =)): там везде упоминается DEVOBJ_EXTENSION_EX, а именно ее поле AttachedTo. Все понятно, только одна проблема: а где вы взяли этот DEVOBJ_EXTENSION_EX? У меня описания этой структуры нет ни в одном хидере ДДК. Она как я понимаю входит в DEVICE_OBJECT? Так DEVICE_OBJECT у меня во всех хидерах вот как описан:

    Код (Text):
    1. typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {
    2.     CSHORT Type;
    3.     USHORT Size;
    4.     LONG ReferenceCount;
    5.     struct _DRIVER_OBJECT *DriverObject;
    6.     struct _DEVICE_OBJECT *NextDevice;
    7.     struct _DEVICE_OBJECT *AttachedDevice;
    8.     struct _IRP *CurrentIrp;
    9.     PIO_TIMER Timer;
    10.     ULONG Flags;                                // See above:  DO_...
    11.     ULONG Characteristics;                      // See ntioapi:  FILE_...
    12.     PVPB Vpb;
    13.     PVOID DeviceExtension;
    14.     DEVICE_TYPE DeviceType;
    15.     CCHAR StackSize;
    16.     union {
    17.         LIST_ENTRY ListEntry;
    18.         WAIT_CONTEXT_BLOCK Wcb;
    19.     } Queue;
    20.     ULONG AlignmentRequirement;
    21.     KDEVICE_QUEUE DeviceQueue;
    22.     KDPC Dpc;
    23.  
    24.     //
    25.     //  The following field is for exclusive use by the filesystem to keep
    26.     //  track of the number of Fsp threads currently using the device
    27.     //
    28.  
    29.     ULONG ActiveThreadCount;
    30.     PSECURITY_DESCRIPTOR SecurityDescriptor;
    31.     KEVENT DeviceLock;
    32.  
    33.     USHORT SectorSize;
    34.     USHORT Spare1;
    35.  
    36.     struct _DEVOBJ_EXTENSION  *DeviceObjectExtension;
    37.     PVOID  Reserved;
    38. } DEVICE_OBJECT;
    Подскажите, в чем я неправ и если неверна моя структура DEVICE_OBJECT, то дайте правильную, и тогда уж и DEVOBJ_EXTENSION_EX.

    Совсем запутался я что-то...
     
  5. cc

    cc New Member

    Публикаций:
    0
    Регистрация:
    15 окт 2006
    Сообщения:
    34
    Кажется дошло. Указатель на DEVOBJ_EXTENSION_EX в структуре DEVICE_OBJECT равен адресу DEVOBJ_EXTENSION, только в DEVOBJ_EXTENSION не все поля, а только первые три:

    Код (Text):
    1. typedef struct _DEVOBJ_EXTENSION {
    2.  
    3.     CSHORT          Type;
    4.     USHORT          Size;
    5.     //
    6.     // Public part of the DeviceObjectExtension structure
    7.     //
    8.     PDEVICE_OBJECT  DeviceObject;               // owning device object
    9. } DEVOBJ_EXTENSION, *PDEVOBJ_EXTENSION;
    В то время как DEVOBJ_EXTENSION_EX

    Код (Text):
    1. typedef struct _DEVOBJ_EXTENSION_EX {
    2.     CSHORT          Type;
    3.     USHORT          Size;
    4.     PDEVICE_OBJECT  DeviceObject;
    5.     ULONG           PowerFlags;
    6.     struct          _DEVICE_OBJECT_POWER_EXTENSION  *Dope;
    7.     ULONG           ExtensionFlags;
    8.     PVOID           DeviceNode;
    9.     PDEVICE_OBJECT  AttachedTo;
    10.     LIST_ENTRY      FileObjectList;
    11. } DEVOBJ_EXTENSION_EX, *PDEVOBJ_EXTENSION_EX;
    Таким образом, получается, что DEVOBJ_EXTENSION_EX это тот же DEVOBJ_EXTENSION, только более полный, то есть содержащий все поля.

    Теперь вопросы:
    1. Правильны ли мои догадки?
    2. Если 1 верно, то верно ли описание DEVOBJ_EXTENSION_EX, которое я все же нашел?
    3. Таким образом, чтобы получить указатель на PDO нужно вызвать IoGetDeviceObjectPointer, которая возвращает указатель на FILE_OBJECT и на DEVICE_OBJECT. Если я буду использовать DEVICE_OBJECT то надо последовательно спускаться вниз по стеку фильтров до тех пор пока AttachedTo не будет равно нулю, как только равно нулю, значит это PDO?
    4. А если использовать FILE_OBJECT возвращаемый IoGetDeviceObjectPointer, то у него есть поле DeviceObject, а не является ли этот указатель (FILE_OBJECT.DeviceObject) указателем на PDO? Если так, то может быть будет лучше не спускаться "вручную" по стеку фильтров, а получить POD через FILE_OBJECT?

    Много вопросов... Буду весьма признателен если вы на все ответите.
     
  6. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Уже не помню. Если она мне была нужна до появления исходников w2k, то пропарсил pdb с помощью PdbDump (лужит на нашем сайте, кажется). Если после, то, соответственно, в исходники глянул.

    PdbDump дает вот что:
    Код (Text):
    1. struct _DEVOBJ_EXTENSION {
    2.   /*<thisrel this+0x0>*/ /*|0x2|*/ short Type;
    3.   /*<thisrel this+0x2>*/ /*|0x2|*/ unsigned short Size;
    4.   /*<thisrel this+0x4>*/ /*|0x4|*/ struct _DEVICE_OBJECT* DeviceObject;
    5.   /*<thisrel this+0x8>*/ /*|0x4|*/ unsigned long PowerFlags;
    6.   /*<thisrel this+0xc>*/ /*|0x4|*/ struct _DEVICE_OBJECT_POWER_EXTENSION* Dope;
    7.   /*<thisrel this+0x10>*/ /*|0x4|*/ unsigned long ExtensionFlags;
    8.   /*<thisrel this+0x14>*/ /*|0x4|*/ void* DeviceNode;
    9.   /*<thisrel this+0x18>*/ /*|0x4|*/ struct _DEVICE_OBJECT* AttachedTo;
    10.   /*<thisrel this+0x1c>*/ /*|0x8|*/ struct _LIST_ENTRY FileObjectList;
    11. };
    В DDK есть только публичная часть DEVOBJ_EXTENSION. То что идет после DeviceObject недокументировано, но в отладочные символы таки попадает.

    Не входит, а на нее указывает поле DeviceObjectExtension.

    Если нужно спуститься до PDO под w2k, то можно юзать мой вариант GetNextLowerDeviceObject по этой ссылке: http://www.wasm.ru/forum/viewtopic.php?id=11363

    Под ХР+ IoGetDeviceAttachmentBaseRef либо в цикле IoGetLowerDeviceObject.
     
  7. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Да.

    Да.


    Да.

    Ммм... Точно не скажу - отладчика под рукой щас нет, но даже если так, то я бы не стал на это опираться.
     
  8. cc

    cc New Member

    Публикаций:
    0
    Регистрация:
    15 окт 2006
    Сообщения:
    34
    Уважаемый Four-F, не мог бы ты еще мне помочь. Вот мой код:

    Код (Text):
    1. const PCWSTR DeviceName=L"\\Device\\Harddisk2\\DP(1)0-0+5";
    2.  
    3. NTSTATUS ns;
    4. UNICODE_STRING usDeviceName;
    5. PFILE_OBJECT pFileObject=0;
    6. PDEVICE_OBJECT pDeviceObject;
    7. PDEVOBJ_EXTENSION_EX pDevObjExtensionEx;
    8.  
    9. RtlInitUnicodeString(&usDeviceName, DeviceName);
    10. ns=IoGetDeviceObjectPointer(&usDeviceName, FILE_READ_DATA, &pFileObject, &pDeviceObject);
    11. DBGPRINT(NT_SUCCESS(ns) ? "IoGetDeviceObjectPointer success" : "IoGetDeviceObjectPointer failed");
    12. pDevObjExtensionEx=(PDEVOBJ_EXTENSION_EX) pDeviceObject->DeviceObjectExtension;
    13. if(!pDevObjExtensionEx->AttachedTo)
    14. {
    15.     IoGetDeviceProperty(...); // [b]на этом месте вылетает BSOD[/b]
    16. }
    17. if(pFileObject)
    18. {
    19.     ObDereferenceObject(pFileObject);
    20. }
    Почему БСОД? Ведь если AttachedTo == 0 то это POD? Хотя если это POD то у него DeviceNode != 0, а у меня ноль.

    В чем ошибка? Я явно что-то недогоняю...
     
  9. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Не POD, я PDO (Physical Device Object). Я пошарился, с помощью WinObjEx, у себя в системе и нашёл парочку девайсов вида \Device\HarddiskX\DP(X)XXX, у которых AttachedTo == NULL и DeviceNode == NULL, но это не PDO. В том смысле, что эти девайсы не являются узлами PnP. К сожалению, я плохо шарю в файловых системах, но возможно это CDO (Control Device Object), которые создает файловая система при монтировании тома, или какие-то особые девайсы, представляющие логические разделы диска, т.к. судя по именам..

    DP(1)0x7e00-0x138c97e00+1
    DP(2)0x138ca7a00-0x36f888600+2

    .. цифры - смещения начала и конца раздела. У меня на стареньком ноуте, за которым щас сижу, как раз два раздела 5,2 и 14,7 гига.

    Твой DP(1)0-0+5, видимо, соотв. единственному разделу диска или флешки.

    Вобщем, я не знаю, что это за девайсы, но по-любому, если у них нет ноды, то от IoGetDeviceProperty толку всё равно не будет.

    Кстати, вспомнил ещё один хороший способ поиметь PDO, хотя в данном случае это всё равно не поможет. Нужно синхронно послать в стек PnP IRP IRP_MN_QUERY_DEVICE_RELATIONS с пареметром TargetDeviceRelation. Целевой девайс любой в стеке: хоть на вершину, хоть в любой другой. Он гарантированно дойдёт до PDO и драйвер, управляющий PDO, обязан его обработать и вернуть указатель на PDO. Не забыть дереференс потом сделать.

    См. в DDK\src\general\toaster\toastmon\toastmon.c функцию ToastMon_GetTargetDevicePdo. Если ещё глянуть ToastMon_OpenTargetDevice, то вообще красота ;)
     
  10. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Это действительно девайсы, соответствующие разделам диска. Пара слов есть тут: http://www.osp.ru/text/302/174349/
     
  11. cc

    cc New Member

    Публикаций:
    0
    Регистрация:
    15 окт 2006
    Сообщения:
    34
    Да, это действительно флешка.

    Но ведь вызов SetupDiGetDeviceRegistryProperty в юзермоде дает необходимую информацию? А разве SetupDiGetDeviceRegistryProperty не спускается в конце концов к вызову IoGetDeviceProperty?

    И если действительно не получится использовать IoGetDeviceProperty в данном случае, то не мог бы ты еще подсказать, каким образов в ядре можно получить идентификационные данные устройства (желательно без прямого обращения к драйверу устройства, т.е. без посылки ему каких-то управляющих кодов и т.д., поскольку это, как я понимаю, лишает код некоторой универсальности).
     
  12. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Попробуй через DeviceNode. Если он нулевой, можно сходить по ссылке NextSibling или через Parent получить ссылки на NextSibling. Класс-драйверы могут создавать несколько разнотипных объектов для обслуживания одного устройства, и у некоторых из них AttachedTo и DeviceNode выставляются в NULL, это не PDO
     
  13. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Скорее всего спускается, но SetupDiGetDeviceRegistryProperty в юзермоде не может дать ничего для девайса не являющегося узлом PnP. Если у девайса в экстеншене DeviceNode == NULL, то это не узел PnP и SetupDiGetDeviceRegistryProperty просто не может работать! Дело в том, что для получения PnP-related инфы, имея указатель на девайс, IoGetDeviceProperty должна сначала перевести этот указатель в DeviceInstance. DeviceInstance - это грубо говоря ветка в реестре, например для моей флешки \HKLM\SYSTEM\CurrentControlSet\Enum\STORAGE\RemovableMedia\7&3517586&0&RM. DeviceInstance содержится в DeviceNode. Если нет DeviceNode, то нет и DeviceInstance и ничего PnP-related получить невозможно.

    Я почти уверен, что ты просто путаешь девайсы. SetupDiGetDeviceRegistryProperty вызываешь для одного, а IoGetDeviceProperty для совершенно другого.

    Возьми devcon из DDK. Прогони его с параметром stack storage*. Получишь что-то вроде этого:

    Код (Text):
    1. E:\DDK\tools\devcon\i386>devcon stack storage*
    2. STORAGE\REMOVABLEMEDIA\7&3517586&0&RM
    3.     Name:     Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume
    4.     Class upper filters:
    5.         VolSnap
    6.     Controlling service:
    7.         (none)
    8. STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET1316FDC00LENGTH262DE3E00
    9.     Name:     Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume
    10.     Class upper filters:
    11.         VolSnap
    12.     Controlling service:
    13.         (none)
    14. STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET3944E9800LENGTH7281E3400
    15.     Name:     Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume
    16.     Class upper filters:
    17.         VolSnap
    18.     Controlling service:
    19.         (none)
    20. STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET7E00LENGTH1316EE000
    21.     Name:     Setup Class: {71A27CDD-812A-11D0-BEC7-08002BE2092F} Volume
    22.     Class upper filters:
    23.         VolSnap
    24.     Controlling service:
    25.         (none)
    26. 4 matching device(s) found.
    Это DeviceInstance для томов. Первый - моя флешка, три остальных разделы на харде. Затем в поиске WinObjEx поищи символьные ссылки с такими же именами (бери только часть имени после слеша). Увидишь, что они кажут на девайсы:

    Код (Text):
    1. STORAGE\REMOVABLEMEDIA\7&3517586&0&RM                                        -> \Device\Harddisk1\DP(1)0-0+5
    2. STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET1316FDC00LENGTH262DE3E00  -> \Device\HarddiskVolume2
    3. STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET3944E9800LENGTH7281E3400  -> \Device\HarddiskVolume3
    4. STORAGE\VOLUME\1&30A96598&0&SIGNATUREE432E432OFFSET7E00LENGTH1316EE000       -> \Device\HarddiskVolume1
    У всех этих девайсов DeviceNode != NULL (WinObjEx это показывает в свойствах), что естественно, иначе бы они просто не попали в вывод devcon'a.

    Те девайсы, которые у меня представляют логические разделы диска, DP(1)0x7e00-0x138c97e00+1, DP(2)0x138ca7a00-0x36f888600+2... не попадают в вывод devcon'a, т.к. у них нет ноды.

    Можешь ещё получить всё PnP дерево в KernelDebugger по команде...

    kd> !devnode 0 1

    ...там тоже будут только PnP узлы. Попробуй поискать там тот девайс, на котором у тебя облом - его там быть не должно.

    Короче разберись точно, что и от какого девайса ты хочешь поиметь. В любом случае, если DeviceNode == NULL, то никаких "Plug and Play device property" не будет.
     
  14. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Возможен ещё вариант, что хозяин этих девайсов, соответствующих разделам диска, у которых нет ноды просто редиректит какие-то запросы в другой стек. И если SetupDiGetDeviceRegistryProperty посылает PnP IRP, то может быть просто возвращается инфа о другом девайсе. Но сомневаюсь, что это так. Т.к. я не знаю как работает файловая система, то не могу точно сказать.