Доброго времени суток всем. Мне необходимо получить наименование устройства, находящегося в стеке драйверов файловой системы 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, что тоже бесполезно. Если мысли есть - напишите, буду благодарен.
rav, спасибо за совет, но заний для получения из DEVICE_OBJECT FILE_OBJECT не хватает: в OBJECT_HEADER, DEVICE_OBJECT, DRIVER_OBJECT нет указателя на FILE_OBJECT. Может кто подскажет откуда его вытащить?
Могу ошибиться, но, видимо, ты пытаешься получить имя девайса, который сидит над 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
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): NTSTATUS status; USHORT sDevName[260]; ULONG iDevNameLen; PDEVICE_OBJECT HDD_DeviceObject; iDevNameLen=255; 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). Может кто наступал на эти грабли, помогите пожалуйста.
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): NTSTATUS status; PVOID pOutBuffer; ULONG cbBuffer; PAGED_CODE(); status = IoGetDeviceProperty( i_pPDO, DevicePropertyPhysicalDeviceObjectName, 0, NULL, &cbBuffer ); ASSERT( STATUS_BUFFER_TOO_SMALL == status ); if ( STATUS_BUFFER_TOO_SMALL != status ) { return STATUS_UNSUCCESSFUL; } if ( (0 == cbBuffer) || (cbBuffer > UNICODE_STRING_MAX_BYTES) ) { return STATUS_UNSUCCESSFUL; } pOutBuffer = ExAllocatePool( PagedPool, cbBuffer ); if ( NULL == pOutBuffer ) { return STATUS_INSUFFICIENT_RESOURCES; } status = IoGetDeviceProperty( i_pPDO, DevicePropertyPhysicalDeviceObjectName, cbBuffer, pOutBuffer, &cbBuffer ); if ( !NT_SUCCESS( status ) ) { ExFreePool( pOutBuffer ); return status; } DbgPrint( "PDO Name: %ws \n", pOutBuffer )); ExFreePool( pOutBuffer ); return STATUS_SUCCESS; Слей WinObjEx http://www.wasm.ru/toollist.php?list=21 и убедись, что у твоего \Device\HarddiskVolume3 поле AttachedTo действительно NULL.
Four-F, спасибо за программу и за код, убедился в том, что \Device\HarddiskVolume3 имеет AttachedTo ==NULL, порадовался за радиус кривизны своих ручек . ошибка по которой отваливается система - PNP_DETECTED_FATAL_ERROR (причём тут это понять пока не могу, но BugCheck код 0х000000СА). В нулевом кольце сплошные грабли разложены, детские в том числе. Спасибо за советы. Буду разбираться дальше.
Ну я же говорил, что ты не 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.
Пытаюсь получить имя девайса. Вот функция (я покрамсал сех-фреймы и прочее, только основное): Код (Text): NTSTATUS GetObjectName( PUNICODE_STRING ObjectName, PVOID Object ) { NTSTATUS st = STATUS_SUCCESS; POBJECT_NAME_INFORMATION ObjectNameInfo; ULONG ReturnLength; UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION)+(1024*sizeof(WCHAR))]; ObjectNameInfo = (POBJECT_NAME_INFORMATION)Buffer; RtlZeroMemory( Buffer, sizeof(Buffer) ); st = ObQueryNameString( Object, ObjectNameInfo, sizeof(Buffer), &ReturnLength ); if(!NT_SUCCESS(st)) { DbgPrint("ObQueryNameString failed with status %08x", st); return st; } RtlCopyUnicodeString( ObjectName, &ObjectNameInfo->Name ); return st; } Она работает "50х50". Для большинства девайсов она правильно выдает имя, а, например, для \Device\CdRom0 у меня она падает с PAGE_FAULT_IN_NONPAGED_AREA (адрес BAD0B154). Откуда такой адрес - черт его знает, я передаю валидный указатель (проверял в DbgPrint). Это все для DEVICE_OBJECT было. Для FILE_OBJECT на реальной тачке не пробовал, вмваря вообще отдала концы. Может ей стоит заполнить как-нибудь передаваемую ObjectNameInfo->Name ?
Попробовал с 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. Вот на этом месте на получении имени самого верхнего девайса оно падает.
Убедись на 100%, что указатель на DEVICE_OBJECT, который передается в ObQueryNameString именно указатель на DEVICE_OBJECT, а не просто валидный указатель. Скорее всего проблема в этом. Судя по фразе "Дальше сравниваю имя каждого девайса в стеке с CdRom0", ты как-то обходишь стек. Здесь видимо и косяк.
Four-F Да, я проверял - сначала от DbgPrint'ил указатель, возвращаемый IoGetDeviceObjectPointer (она нормально возвращает STATUS_SUCCESS). Далее перед вызовом ObQueryNameString проверяю Object - тот же самый указатель. Щас попробую вручную пропарсить заголовок объекта и вытащить имя оттуда.
Код (Text): DbgPrint("Trying"); POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER( Object ); DbgPrint("Header = %08x", Header); DbgPrint("Header->NameInfoOffset = %08x", Header->NameInfoOffset); POBJECT_HEADER_NAME_INFO NameInfo = OBJECT_HEADER_TO_NAME_INFO( Header ); DbgPrint("NameInfo = %08x", NameInfo); Выдает: Неужели ObQueryNameString не проверяет, что NameInfoOffset == 0 ?
Проблема решена. Мелкомягкие благополучно исключили из ядра все проверки. В том числе не проверяется, что NameInfoOffset = 0. Далее получается указатель на OBJECT_HEADER_NAME_INFO (конечно, неправильный, но указывающий на валидную память), а как раз поле Name.Buffer его указывает на тот самый BAD0B0B0, на котором было бы падение ObQueryNameString. Получается такой вывод: винде доверяй, но проверяй. Судя по всему, облегчив ядро, программеры выкинули и совсем не лишние проверки. Гады =) Судя по всему, макрос Код (Text): #define OBJECT_HEADER_TO_NAME_INFO( oh ) \ ((POBJECT_HEADER_NAME_INFO) ((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset))) в релиз версии ядра был благополучно заменен на Код (Text): #define OBJECT_HEADER_TO_NAME_INFO( oh ) ((POBJECT_HEADER_NAME_INFO) ((PCHAR)(oh) - (oh)->NameInfoOffset))
Ядерный стек всего 12кб на 32-х битных машинах. Так что если злоупотеблять... USHORT sDevName[260]; , то легко можно исчерпать стек.
почти тот же вопрос ))))) Для реальных дисков код работает, т.е. получается строка \Device\HarddiskVolume1 или \Device\HarddiskVolume2 А в случае использования этого способа для TrueCrypt дисков (виртуальных дисков) возвращается ошибка типа STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L) А необходима строка типа \Device\TrueCryptVolume, подскажите, пожалуйста, хоть в какую сторону искать, чтобы получить то, что нужно?