Помогите составить IRP

Тема в разделе "WASM.WIN32", создана пользователем Maveric, 1 фев 2006.

  1. Maveric

    Maveric New Member

    Публикаций:
    0
    Регистрация:
    19 янв 2004
    Сообщения:
    90
    Есть такая задачка из ядра послать IRP другому устройству. Если конкретно, то SMART_GET_VERSION для "\\??\\PhysicalDrive0".

    И что-то пока не особо получается. Делаю так:
    Код (Text):
    1.  
    2. ...
    3. NTSTATUS            status;
    4. IO_STATUS_BLOCK     iosb;
    5. HANDLE          hDevice;
    6. PIRP                pIRP = NULL;
    7. PIO_STACK_LOCATION  pNextStack;
    8. GETVERSIONINPARAMS  VersionParams;
    9. PVOID               pObject;
    10. KEVENT          event;
    11. LARGE_INTEGER       timeout;
    12. ...
    13.  
    14. status = ObReferenceObjectByHandle(hDevice, GENERIC_READ, 0, KernelMode, &pObject, NULL);
    15. ZwClose(hDevice);
    16. if(status != STATUS_SUCCESS)
    17. {
    18.    DbgPrint("kdiskid: ObReferenceObjectByHandle fail\n");
    19.    return STATUS_INSUFFICIENT_RESOURCES;
    20. }
    21.  
    22. KeInitializeEvent(&event, NotificationEvent, FALSE);
    23. pIRP = IoAllocateIrp(((PDEVICE_OBJECT)pObject)->StackSize + 1, FALSE);
    24. if(pIRP == NULL)
    25. {
    26.    DbgPrint("kdiskid: IoAllocateIrp fail\n");
    27.    ObDereferenceObject(pObject);
    28.    return STATUS_INSUFFICIENT_RESOURCES;
    29. }
    30.  
    31. // заполняем IRP
    32. pNextStack = IoGetNextIrpStackLocation(pIRP);
    33. pNextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
    34. pNextStack->MinorFunction = 0;
    35. pNextStack->Parameters.DeviceIoControl.IoControlCode = SMART_GET_VERSION;
    36. pNextStack->Parameters.DeviceIoControl.InputBufferLength = 0;
    37. pNextStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(VersionParams);
    38. pNextStack->Parameters.DeviceIoControl.Type3InputBuffer = &VersionParams;
    39. pIRP->AssociatedIrp.SystemBuffer = &VersionParams;
    40. pIRP->RequestorMode = KernelMode;
    41. IoSetCompletionRoutine(pIRP, CompletionRoutine, &event, TRUE, TRUE, TRUE);
    42.  
    43. IoCallDriver(pObject, pIRP); // и писеееец...
    44.  
    45. timeout.QuadPart = -100000000;
    46. status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout);  
    47. if(status == STATUS_SUCCESS)
    48.    DbgPrint("kdiskid: KeWaitForSingleObject - success\n");
    49. if(status == STATUS_TIMEOUT)
    50.    DbgPrint("kdiskid: KeWaitForSingleObject - SATUS_TIMEOUT \n");
    51. IoFreeIrp(pIRP);
    52. ObDereferenceObject(pObject);
    53.  




    в sice ловлю page fault



    я так понимаю, что что-то с буферами делаю не то

    код выполняется в PASSIVE_LEVEL



    помогите чем можете :)
     
  2. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Смотри в сторону функций IoBuildDeviceIoControlRequest и IoBuildSynchronousFsdRequest.

    И проверяй результат IoCallDriver. Ждать надо только при возврате STATUS_PENDING.
     
  3. Maveric

    Maveric New Member

    Публикаций:
    0
    Регистрация:
    19 янв 2004
    Сообщения:
    90
    Пробовал IoBuildDeviceIoControlRequest. Там нет такого нужного параметра как StackSize... В итоге, как и следовало ожидать, BSOD. А если возврат будет не STATUS_PENDING, а, скажем, STATUS_SUCCESS, то CompletionRoutine не вызовется ?
     
  4. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"


    Конечно нет, так как он равен DeviceObject->StackSize.





    Вызоветься, но в точки зрения производительности лучше в этом случае не ждать.
     
  5. Maveric

    Maveric New Member

    Публикаций:
    0
    Регистрация:
    19 янв 2004
    Сообщения:
    90
    Я уже говорил, что пробовал IoBuildDeviceIoControlRequest. И, кстати, BSOD вылетал как раз по поводу StackSize. Такой же BSOD вылетает и при IoAllocateIrp если ставлю StackSize = DeviceObject->StackSize.

    может есть смысл перед IoBuildDeviceIoControlRequest увеличить DeviceObject->StackSize ?
     
  6. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    А использовать NtDeviceIoControlFile не годиться?

    И и почему поле pNextStack->FileObject не заполняешь?
     
  7. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Короче в общем случае посылка IOCTL будет выглядеть так:


    Код (Text):
    1. Status = ObReferenceObjectByHandle(DeviceHandle,
    2.                                        (IoControlCode >> 14) & 0x3,
    3.                                        IoFileObjectType,
    4.                                        KernelMode,
    5.                                        &FileObject,
    6.                                        NULL);
    7.  
    8.     if (!NT_SUCCESS(Status)) return Status;
    9.  
    10.     DeviceObject = IoGetRelatedDeviceObject(FileObject);
    11.    
    12.     Irp = IoBuildDeviceIoControlRequest(IoControlCode,
    13.                                         DeviceObject,
    14.                                         InputBuffer,
    15.                                         InputBufferLength,
    16.                                         OutputBuffer,
    17.                                         OutputBufferLength,
    18.                                         FALSE,
    19.                                         Event,
    20.                                         IoStatusBlock);
    21.  
    22.     Irp->Tail.Overlay.OriginalFileObject = FileObject;
    23.     Irp->RequestorMode = KernelMode;
    24.     StackPtr = IoGetNextIrpStackLocation(Irp);
    25.     StackPtr->FileObject = FileObject;
    26.     StackPtr->MajorFunction = IRP_MJ_DEVICE_CONTROL;
    27.  
    28.     Status = IoCallDriver(DeviceObject, Irp);
    29.  
    30.     if (Status == STATUS_PENDING)
    31.     {
    32.         KeWaitForSingleObject(&Event,
    33.                               Executive,
    34.                               PreviousMode,
    35.                               FALSE,
    36.                               NULL
    37.                               );
    38.  
    39.          Status = FileObject->FinalStatus;
    40.     }
    41.  
     
  8. Maveric

    Maveric New Member

    Публикаций:
    0
    Регистрация:
    19 янв 2004
    Сообщения:
    90
    10x ! попробую
     
  9. Maveric

    Maveric New Member

    Публикаций:
    0
    Регистрация:
    19 янв 2004
    Сообщения:
    90
    Круть ! Похоже прокатило !

    Cпасибо !
     
  10. Four-F

    Four-F New Member

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





    <font color="gray][ Maveric</font><!--color--><font color="gray]: я так понимаю, что что-то с буферами делаю не то ]</font><!--color-->
    Код (Text):
    1. pNextStack->Parameters.DeviceIoControl.Type3InputBuffer = &VersionParams;


    Это неверно.



    Должно быть:



    irp->UserBuffer = pOutputBuffer;



    + должно быть:



    pIrp->UserIosb = IoStatusBlock;

    pIrp->UserEvent = Event;



    + ещё флаги, наверное:



    pIrp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;





    <font color="gray][ Maveric</font><!--color--><font color="gray]: Там нет такого нужного параметра как StackSize ]</font><!--color-->



    Он тебе вообще не нужен. pDeviceObject->StackSize + 1 нужно только если нужен один доп. блок стека, для использования не по прямому назначению, а просто как буфер пристёгнутый к IRP. В этом случае IoGetNextIrpStackLocation делается 2 раза и инициализируется второй IO_STACK_LOCATION, а в первый (буферный) пихается что-то.



    <font color="gray][ Maveric</font><!--color--><font color="gray]: А если возврат будет не STATUS_PENDING, а, скажем, STATUS_SUCCESS, то CompletionRoutine не вызовется ? ]</font><!--color-->



    Последние три параметра в IoSetCompletionRoutine определяют, при каком исходе звать CompletionRoutine. Если все три = TRUE, то CompletionRoutine будет вызвана в любом случае.





    <font color="gray][ Maveric</font><!--color--><font color="gray]: может есть смысл перед IoBuildDeviceIoControlRequest увеличить DeviceObject->StackSize ? ]</font><!--color-->



    Нет.



    Зря паришься с ручным созданием IRP. Этот код должен работать:


    Код (Text):
    1.     GETVERSIONINPARAMS  VersionParams;
    2.     KEVENT              event;
    3.     NTSTATUS            status;
    4.     IO_STATUS_BLOCK     IoStatus;
    5.     PIRP                pIrp;
    6.     PDEVICE_OBJECT      pDeviceObject;
    7.  
    8.     PAGED_CODE();
    9.  
    10.     KeInitializeEvent( &event, NotificationEvent, FALSE );
    11.  
    12.     pIrp = IoBuildDeviceIoControlRequest(SMART_GET_VERSION,
    13.                                          pDeviceObject,
    14.                                          (PVOID) NULL,
    15.                                          0,
    16.                                          &VersionParams,
    17.                                          sizeof(VersionParams),
    18.                                          FALSE,
    19.                                          &event,
    20.                                          &IoStatus);
    21.     if ( pIrp ) {
    22.  
    23.         status = IoCallDriver( pDeviceObject, pIrp );
    24.  
    25.         if ( STATUS_PENDING == status ) {
    26.  
    27.             KeWaitForSingleObject( &event,
    28.                                    Executive,
    29.                                    KernelMode,
    30.                                    FALSE,
    31.                                    NULL );
    32.            status = IoStatus.Status;
    33.     }




    Если име девайса или символьной ссылки не него заранее известны, то можно не парится с хендлами.


    Код (Text):
    1. PDEVICE_OBJECT pDeviceObject;
    2. UNICODE_STRING us;
    3. PFILE_OBJECT   pFileObject;
    4.  
    5. RtlInitUnicodeString( &us, L"\\??\\PhysicalDrive0" );
    6.  
    7. status = IoGetDeviceObjectPointer( &us,
    8.                                    FILE_READ_ATTRIBUTES,
    9.                                    &pFileObject,
    10.                                    &pDeviceObject );
    11.  
    12. //  build IRP and call driver
    13.  
    14. ObDereferenceObject( pFileObject );
     
  11. Maveric

    Maveric New Member

    Публикаций:
    0
    Регистрация:
    19 янв 2004
    Сообщения:
    90
    Four-F, огромное спасибо за внимание. Сейчас всё работает, хотя не мешало бы кое-что прояснить. Код, который ты привёл, очень похож на то что у меня было в самом начале.

    IRP создавался с помощью IoBuildDeviceIoControlRequest. Но на IoCallDriver вылет BSOD по поводу этих самых StackSize.

    Я открывал "\\??\\PhysicalDrive0" и уже по хэндлу получал объект (уже понятно, что это лишние телодвижения), и дальше эото самый объект я и подставлял в IoBuildDeviceIoControlRequest. Я так понимаю, что в этом и была ошибка, потому что сделав так, как написал Ms Rem "(DeviceObject = IoGetRelatedDeviceObject(FileObject);" всё стало нормально работать.

    Честно говоря, хотелось бы услышать комментарии по этому поводу.
     
  12. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Наконец-то я понял. У тебя hDevice соответствует FILE_OBJECT. Ты его, наверное, через (Zw)CreateFile получил. Поэтому твой pObject указывал на FILE_OBJECT, а не на DEVICE_OBJECT. Когда ты звал IoBuildDeviceIoControlRequest, то она делала так:



    irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );



    но DeviceObject был указателем на FILE_OBJECT. Соответственно DeviceObject->StackSize было равно тому, что по этому смещению лежит в FILE_OBJECT. Вот и всё. IoCallDriver по любому кирдыкнулась бы.



    IoGetDeviceObjectPointer же делает так (псевдо-код):




    Код (Text):
    1.  NTSTATUS
    2.    IoGetDeviceObjectPointer(
    3.      IN PUNICODE_STRING  pusObjectName,
    4.      IN ACCESS_MASK      DesiredAccess,
    5.      OUT PFILE_OBJECT    *out_pFileObject,
    6.      OUT PDEVICE_OBJECT  *out_pDeviceObject
    7.      )
    8.  {
    9.      PFILE_OBJECT        pFileObject
    10.      OBJECT_ATTRIBUTES   oa
    11.      HANDLE              hFile
    12.  
    13.      InitializeObjectAttributes( &oa, pusObjectName, ... )
    14.  
    15.      ZwOpenFile( &hFile, DesiredAccess, &oa, ... )
    16.  
    17.      ObReferenceObjectByHandle( hFile, 0, IoFileObjectType, KernelMode, &pFileObject, NULL )
    18.  
    19.      *out_pFileObject   = pFileObject
    20.      *out_pDeviceObject = IoGetRelatedDeviceObject( pFileObject )
    21.  
    22.      ZwClose( hFile )
    23.  
    24.      return STATUS_XXX
    25.  }
    26.  


    Как видишь, тоже ZwOpenFile, но потом IoGetRelatedDeviceObject, чтобы извлечь из файлового объекта указатель на соответствующий ему девайс.
     
  13. Maveric

    Maveric New Member

    Публикаций:
    0
    Регистрация:
    19 янв 2004
    Сообщения:
    90
    Только сегодня смог прочитать ответ, т.к. сервер лежал. Спасибо раз разъяснения. Всё работает :)
     
  14. dsmovsw

    dsmovsw New Member

    Публикаций:
    0
    Регистрация:
    9 фев 2006
    Сообщения:
    2
    Адрес:
    Russia
    Тут все давным давно решилось. Но... :)

    Вообще про разруливание IRP могу посоветовать классную статью Toby Opferman`a. На англицком. http://www.codeproject.com/system/driverdev5asp.asp

    Там на примире посылки пакетов IRP \driver\tcpip

    Есть возможность скачать исходник драйвера.