Получение имени DEVICE_OBJECT

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

  1. Koshak

    Koshak New Member

    Публикаций:
    0
    Регистрация:
    21 фев 2006
    Сообщения:
    31
    Адрес:
    Russia
    Доброго времени суток всем.

    Мне необходимо получить наименование устройства, находящегося в стеке драйверов файловой системы NTFS. Сразу оговорюся, что это "\Device\HarddiskVolume3". В программе DeviceTree это устройство отображается как "unnamed", однако, имеет "уточняющий индикатор" (так в хэлпе по DeviceTree написано) "MED", который и имеет название "\Device\HarddiskVolume3".
    В своём драйвере я получаю указатель PDEVICE_OBJECT на этот объект и могу подключить к нему фильтр, что и отображается в DeviceTree, т.е. объект я получаю именно тот что нужен. Теперь о том, что уже перепробовано:
    - Вызов ObQueryNameString(PDEVICE_OBJECT, ......) даёт пустую строку;
    - поле NameOffset в структуре OBJECT_HEADER этого объекта равно 0 => имени у него нет;
    - DeviceObject->Vpb == 0, => структура Volume Parameter Blok отсутствует;
    - DeviceObject->DriverObject->DriverName == "\FileSystem\Ntfs", что не радует;
    - DeviceObject->DriverObject->DeviceObject указывает само на себя,
    т.е. DeviceObject == DeviceObject->DriverObject->DeviceObject, что тоже бесполезно.

    Если мысли есть - напишите, буду благодарен.
     
  2. rav

    rav New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2004
    Сообщения:
    159
    Адрес:
    Москва
    Имя надо получать не с DEVICE_OBJECT, а с FILE_OBJECT. Стандартная ошибка.
     
  3. Koshak

    Koshak New Member

    Публикаций:
    0
    Регистрация:
    21 фев 2006
    Сообщения:
    31
    Адрес:
    Russia
    rav, спасибо за совет, но заний для получения из DEVICE_OBJECT FILE_OBJECT не хватает: в OBJECT_HEADER, DEVICE_OBJECT, DRIVER_OBJECT нет указателя на FILE_OBJECT. Может кто подскажет откуда его вытащить?
     
  4. rav

    rav New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2004
    Сообщения:
    159
    Адрес:
    Москва
    А его там и нет. Это очевидно. Иди другим путём.
     
  5. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Могу ошибиться, но, видимо, ты пытаешься получить имя девайса, который сидит над HarddiskVolume3, а не его самого. Раз уж в OBJECT_HEADER пусто, то и нету имени у этого девайса. HarddiskVolume3 - это PDO, а для PDO получить имя просто.

    PDEVICE_OBJECT pPDO = IoGetDeviceAttachmentBaseRef( pSomeDoInStack );
    IoGetDeviceProperty( pPDO, DevicePropertyPhysicalDeviceObjectName, ... );
    ObDereferenceObject( pPDO );

    где pSomeDoInStack - указатель на любой девайс в стеке. ObQueryNameString тоже должна работать с pPDO.

    IoGetDeviceAttachmentBaseRef документирована в IFS Kit и доступна начиная с ХР. Под W2K нужно руками спуститься до PDO.

    http://www.wasm.ru/forum/viewtopic.php?id=11363
     
  6. Koshak

    Koshak New Member

    Публикаций:
    0
    Регистрация:
    21 фев 2006
    Сообщения:
    31
    Адрес:
    Russia
    Four-F
    Спасибо тебе, сейчас буду разбираться...
     
  7. Koshak

    Koshak New Member

    Публикаций:
    0
    Регистрация:
    21 фев 2006
    Сообщения:
    31
    Адрес:
    Russia
    Four-F, у меня ОС 2к, поэтому IoGetDeviceAttachmentBaseRef мне недоступна. Попробовал сделать как ты предложил - через структуру DEVOBJ_EXTENSION_EX, получилось вот что: DEVOBJ_EXTENSION_EX->AttachedTo указывает на DEVICE_OBJECT, которому принадлежит сама структура DEVOBJ_EXTENSION_EX. Т.е. получилось закольцовывание. Возможно потому, что этот DEVICE_OBJECT - первичный, и не к кому не подключён. В программе DeviceTree именно этот DEVICE_OBJECT виден под именем "\Device\HarddiskVolume3" (точнее к нему присобачен "MED", имеющий это имя).
    При попытке вызвать IoGetDeviceProperty для получения имени устройства машина сваливается в BSOD. Возможно я что-то делаю неправильно. Вот код, который вызывает BSOD:
    Код (Text):
    1. NTSTATUS    status;
    2. USHORT      sDevName[260];
    3. ULONG       iDevNameLen;
    4. PDEVICE_OBJECT  HDD_DeviceObject;
    5.  
    6. iDevNameLen=255;
    7. status=IoGetDeviceProperty(HDD_DeviceObject,DevicePropertyPhysicalDeviceObjectName,iDevNameLen,sDevName,&iDevNameLen);
    конструкция try - except не помогает.
    HDD_DeviceObject - правильный указатель на DEVICE_OBJECT устройства \Device\HarddiskVolume3 - я к нему могу подключить свой фильтр и просматривать все проходящие IRP. Этот же DEVICE_OBJECT виден в программе DeviceTree под именем "\Device\HarddiskVolume3" (я вывел HDD_DeviceObject в Dbgview и сравнил с тем, что отображается в DeviceTree).

    Может кто наступал на эти грабли, помогите пожалуйста.
     
  8. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Koshak, могу тебе точно сказать, что ты где-то ошибаешься.

    Этого не может быть, иначе не будут работать IoAttachDeviceToDeviceStack/IoDetachDevice.

    Не может быть никакого закольцовывания. Если девайс "ни к кому не подключён", то это PDO (physical device object) и у него поле AttachedTo должно быть равно NULL.

    Какой хоть стоп-код? А лучше авто-анализ краш-дампа из WinDBG.

    Код кривенький. Во-первых функции ядра, работающие со строками, не работают с кол-вом символов (пожалуй кроме Safe String функций). Т.е. iDevNameLen - д.б. = sizeof(sDevName). Во-вторых, выделять строковый буфер на стеке - ни-ни - только из пула. Но кирдык не из-за этого, а скорее всего из-за того, что HDD_DeviceObject не указатель на PDO. У PDO DEVOBJ_EXTENSION_EX.DeviceNode не должна быть NULL. У всех других девайсов в стеке там как раз NULL.

    Вот код. Если i_pPDO указатель на PDO, то он будет работать.
    Код (Text):
    1. NTSTATUS    status;
    2. PVOID       pOutBuffer;
    3. ULONG       cbBuffer;
    4.  
    5. PAGED_CODE();
    6.  
    7. status = IoGetDeviceProperty(
    8.                         i_pPDO,
    9.                         DevicePropertyPhysicalDeviceObjectName,
    10.                         0,
    11.                         NULL,
    12.                         &cbBuffer );
    13.  
    14. ASSERT( STATUS_BUFFER_TOO_SMALL == status );
    15. if ( STATUS_BUFFER_TOO_SMALL != status ) {
    16.  
    17.     return STATUS_UNSUCCESSFUL;
    18. }
    19.  
    20. if ( (0 == cbBuffer)  ||  (cbBuffer > UNICODE_STRING_MAX_BYTES) ) {
    21.  
    22.     return STATUS_UNSUCCESSFUL;
    23. }
    24.  
    25. pOutBuffer = ExAllocatePool( PagedPool, cbBuffer );
    26.  
    27. if ( NULL == pOutBuffer ) {
    28.  
    29.     return STATUS_INSUFFICIENT_RESOURCES;
    30. }
    31.  
    32. status = IoGetDeviceProperty(
    33.                         i_pPDO,
    34.                         DevicePropertyPhysicalDeviceObjectName,
    35.                         cbBuffer,
    36.                         pOutBuffer,
    37.                         &cbBuffer );
    38.  
    39. if ( !NT_SUCCESS( status ) ) {
    40.  
    41.     ExFreePool( pOutBuffer );
    42.     return status;
    43. }
    44.  
    45. DbgPrint( "PDO Name: %ws \n", pOutBuffer ));
    46.  
    47. ExFreePool( pOutBuffer );
    48.  
    49. return STATUS_SUCCESS;
    Слей WinObjEx http://www.wasm.ru/toollist.php?list=21 и убедись, что у твоего \Device\HarddiskVolume3 поле AttachedTo действительно NULL.
     
  9. Koshak

    Koshak New Member

    Публикаций:
    0
    Регистрация:
    21 фев 2006
    Сообщения:
    31
    Адрес:
    Russia
    Four-F, спасибо за программу и за код, убедился в том, что \Device\HarddiskVolume3 имеет AttachedTo ==NULL, порадовался за радиус кривизны своих ручек :). ошибка по которой отваливается система - PNP_DETECTED_FATAL_ERROR (причём тут это понять пока не могу, но BugCheck код 0х000000СА). В нулевом кольце сплошные грабли разложены, детские в том числе. Спасибо за советы. Буду разбираться дальше.
     
  10. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Ну я же говорил, что ты не PDO скармливаешь, а какой-то девайс выше по стеку. Первый параметр стоп-кода наверняка 2: "Invalid PDO: An API which requires a PDO has been called with random memory, or with an FDO, or with a PDO which hasn't been initialized."

    ЗЫ: Поправлю себя насчёт "не будут работать IoAttachDeviceToDeviceStack/IoDetachDevice". Для PDO эти функции никто никогда юзать не будет ибо PDO никогда ни к кому не аттачится и не детачится, соответственно. Но по-любому у него AttachedTo == NULL.
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Пытаюсь получить имя девайса. Вот функция (я покрамсал сех-фреймы и прочее, только основное):
    Код (Text):
    1. NTSTATUS GetObjectName( PUNICODE_STRING ObjectName, PVOID Object )
    2. {
    3.     NTSTATUS st = STATUS_SUCCESS;
    4.     POBJECT_NAME_INFORMATION ObjectNameInfo;
    5.     ULONG ReturnLength;
    6.     UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION)+(1024*sizeof(WCHAR))];
    7.     ObjectNameInfo = (POBJECT_NAME_INFORMATION)Buffer;
    8.     RtlZeroMemory( Buffer, sizeof(Buffer) );
    9.  
    10.     st = ObQueryNameString( Object, ObjectNameInfo, sizeof(Buffer), &ReturnLength );
    11.  
    12.     if(!NT_SUCCESS(st))
    13.     {
    14.         DbgPrint("ObQueryNameString failed with status %08x", st);
    15.         return st;
    16.     }
    17.  
    18.     RtlCopyUnicodeString( ObjectName, &ObjectNameInfo->Name );
    19.     return st;
    20. }
    Она работает "50х50". Для большинства девайсов она правильно выдает имя, а, например, для \Device\CdRom0 у меня она падает с PAGE_FAULT_IN_NONPAGED_AREA (адрес BAD0B154). Откуда такой адрес - черт его знает, я передаю валидный указатель (проверял в DbgPrint).
    Это все для DEVICE_OBJECT было. Для FILE_OBJECT на реальной тачке не пробовал, вмваря вообще отдала концы.

    Может ей стоит заполнить как-нибудь передаваемую ObjectNameInfo->Name ?
     
  12. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Попробовал с FILE_OBJECT... один хрен

    PAGE_FAULT_IN_NONPAGED_AREA (50)
    Invalid system memory was referenced. This cannot be protected by try-except,
    it must be protected by a Probe. Typically the address is just plain bad or it
    is pointing at freed memory.
    Arguments:
    Arg1: bad0b154, memory referenced.
    Arg2: 00000000, value 0 = read operation, 1 = write operation.
    Arg3: 8057ce27, If non-zero, the instruction address which referenced the bad memory
    address.
    Arg4: 00000000, (reserved)

    Странно, что для большинства девайсов это работает
    ЗЫ. Я передаю не адрес \Device\CdRom0, а адрес, полученный через IoGetDeviceObjectPointer, то есть вершину его стека. Дальше сравниваю имя каждого девайса в стеке с CdRom0. Вот на этом месте на получении имени самого верхнего девайса оно падает.
     
  13. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Убедись на 100%, что указатель на DEVICE_OBJECT, который передается в ObQueryNameString именно указатель на DEVICE_OBJECT, а не просто валидный указатель. Скорее всего проблема в этом. Судя по фразе "Дальше сравниваю имя каждого девайса в стеке с CdRom0", ты как-то обходишь стек. Здесь видимо и косяк.
     
  14. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Four-F
    Да, я проверял - сначала от DbgPrint'ил указатель, возвращаемый IoGetDeviceObjectPointer (она нормально возвращает STATUS_SUCCESS). Далее перед вызовом ObQueryNameString проверяю Object - тот же самый указатель.
    Щас попробую вручную пропарсить заголовок объекта и вытащить имя оттуда.
     
  15. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Код (Text):
    1. DbgPrint("Trying");
    2.  
    3. POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER( Object );
    4. DbgPrint("Header = %08x", Header);
    5.  
    6. DbgPrint("Header->NameInfoOffset = %08x", Header->NameInfoOffset);
    7.  
    8. POBJECT_HEADER_NAME_INFO NameInfo = OBJECT_HEADER_TO_NAME_INFO( Header );
    9. DbgPrint("NameInfo = %08x", NameInfo);
    Выдает:
    Неужели ObQueryNameString не проверяет, что NameInfoOffset == 0 ?
     
  16. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Проблема решена. Мелкомягкие благополучно исключили из ядра все проверки. В том числе не проверяется, что NameInfoOffset = 0. Далее получается указатель на OBJECT_HEADER_NAME_INFO (конечно, неправильный, но указывающий на валидную память), а как раз поле Name.Buffer его указывает на тот самый BAD0B0B0, на котором было бы падение ObQueryNameString.
    Получается такой вывод: винде доверяй, но проверяй. Судя по всему, облегчив ядро, программеры выкинули и совсем не лишние проверки. Гады =)

    Судя по всему, макрос
    Код (Text):
    1. #define OBJECT_HEADER_TO_NAME_INFO( oh ) \
    2.  ((POBJECT_HEADER_NAME_INFO) ((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))
    в релиз версии ядра был благополучно заменен на
    Код (Text):
    1. #define OBJECT_HEADER_TO_NAME_INFO( oh ) ((POBJECT_HEADER_NAME_INFO) ((PCHAR)(oh) - (oh)->NameInfoOffset))
     
  17. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    а почему?
     
  18. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Ядерный стек всего 12кб на 32-х битных машинах. Так что если злоупотеблять...
    USHORT sDevName[260];
    , то легко можно исчерпать стек.
     
  19. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    так вот в каком смысле
     
  20. matrix

    matrix New Member

    Публикаций:
    0
    Регистрация:
    26 июн 2007
    Сообщения:
    8
    почти тот же вопрос )))))

    Для реальных дисков код работает, т.е. получается строка \Device\HarddiskVolume1 или \Device\HarddiskVolume2

    А в случае использования этого способа для TrueCrypt дисков (виртуальных дисков) возвращается ошибка типа
    STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L)

    А необходима строка типа \Device\TrueCryptVolume, подскажите, пожалуйста, хоть в какую сторону искать, чтобы получить то, что нужно?