Hooking IRP_MJ_READ драйвера

Тема в разделе "WASM.NT.KERNEL", создана пользователем SlyBit, 29 апр 2009.

  1. SlyBit

    SlyBit New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2008
    Сообщения:
    43
    Всем привет.

    Хукаю IRP_MJ_READ драйвера, устанавливаю свою CompletionRoutine, но через некоторое время (буквально 1-2 минуты) система падает. Оригинальная pIrpStack->CompletionRoutine всегда ровна NULL. В чем проблема?

    Код (Text):
    1. NTSTATUS IoCompletionRoutine(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext)
    2. {
    3.     if(pContext) {
    4.         ((PIO_COMPLETION_ROUTINE)pContext)(pDeviceObject, pIrp, NULL);
    5.     } else {
    6.         return STATUS_SUCCESS;        
    7.     }
    8. }
    9.  
    10. NTSTATUS HookedMajorFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    11. {  
    12.     PIO_STACK_LOCATION pIrpStack = NULL;
    13.    
    14.     pIrpStack = IoGetCurrentIrpStackLocation(Irp);
    15.    
    16.     switch(pIrpStack->MajorFunction)
    17.     {
    18.         case IRP_MJ_READ:
    19.            
    20.             pIrpStack->Control = 0;
    21.             pIrpStack->Control |= SL_INVOKE_ON_SUCCESS;
    22.             pIrpStack->Context = pIrpStack->CompletionRoutine;
    23.             pIrpStack->CompletionRoutine = IoCompletionRoutine;  
    24.              
    25.             return pOriginalIrpMjRead(DeviceObject, Irp);
    26.     }
    27. }
    p.s.

    В IoCompletionRoutine() адрес буфера с данными всегда будет находиться в pIrp->AssociatedIrp.SystemBuffer, а их длина в pIrp->IoStatus.Information ?

    Спасибо.
     
  2. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Для приличия хоть посмотрели б IoSetCompletionRoutine макрос.
    IoCompletionRoutine тоже хреновая
     
  3. SlyBit

    SlyBit New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2008
    Сообщения:
    43
    > Для приличия хоть посмотрели б IoSetCompletionRoutine макрос.
    Спасибо. Не знал про него.

    > IoCompletionRoutine тоже хреновая
    Что это значит?
     
  4. SlyBit

    SlyBit New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2008
    Сообщения:
    43
    Действительно хреновая... Нагуглил сэмплы кодесов. Пока поразбираюсь, будут вопросы - отпишусь.
     
  5. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Не вводи людей в заблуждение. IoSetCompletionRoutine() здесь не поможет, ибо используется в фильтрах, а у человека обычный хукер.
     
  6. SlyBit

    SlyBit New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2008
    Сообщения:
    43
    Да, просто хукер.
     
  7. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Код (Text):
    1. NTSTATUS IoCompletionRoutine(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext)
    2. {
    3.     if(pContext) {
    4.         ((PIO_COMPLETION_ROUTINE)pContext)(pDeviceObject, pIrp, NULL);
    5.     } else {
    6.         return STATUS_SUCCESS;        
    7.     }
    8. }
    В твоей completion routine косяков немеряно. По пунктам:

    1. От pContext ничего зависеть не должно, ты должен чётко знать, что там.
    2. Если уж вызываешь нижележащую completion routine, то возвращай системе то значение, которое она вернула тебе.
    3. Нижележащая completion routine вызывается с контекстом, равным NULL, а должна вызываться с оригинальным.

    Код (Text):
    1. NTSTATUS HookedMajorFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    2. {  
    3.     PIO_STACK_LOCATION pIrpStack = NULL;
    4.    
    5.     pIrpStack = IoGetCurrentIrpStackLocation(Irp);
    6.    
    7.     switch(pIrpStack->MajorFunction)
    8.     {
    9.         case IRP_MJ_READ:
    10.            
    11.             pIrpStack->Control = 0;
    12.             pIrpStack->Control |= SL_INVOKE_ON_SUCCESS;
    13.             pIrpStack->Context = pIrpStack->CompletionRoutine;
    14.             pIrpStack->CompletionRoutine = IoCompletionRoutine;  
    15.              
    16.             return pOriginalIrpMjRead(DeviceObject, Irp);
    17.     }
    18. }
    Здесь правильно было бы выделить область памяти под собственный контекст, где сохранять как минимум три вещи: адрес оригинальной completion routine, указатель на её контекст и оригинальное значение поля pIrpStack->Control (короче, структурка с тремя полями). pIrpStack->Control действительно в твоём случае настраивать нужно ручками, но делать это нужно так:

    Код (Text):
    1. pIrpStack -> Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
    Т.о. ты добьёшься того, что твоя copmletion routine будет вызвана в любом случае. В ней в зависимости от результата можешь сделать своё чёрное дело. Далее там же в completion routine тебе придётся вручную проверить результат, проанализировать IRP на предмет отменённости и принять решение о том, следует ли вызывать нижележащую completion routine или нет в соответствии с оригинальным значением поля pMyContext->OriginalControl.

    Вот тебе нужен весь это гемор, а? Перепиши сразу на фильтры, пока не поздно, проще будет, брось ты хернёй маяться.

    Нет, сие зависит от значения поля pDeviceObject->Flags. Если там есть флаг DO_BUFFERED_IO, тогда да, буфер будет в pIrp->AssociatedIrp.SystemBuffer, если там есть флаг DO_DIRECT_IO, тогда буфер будет в pIrp->MdlAddress, и достать его можно через MmGetSystemAddressForMdlSafe().

    В pIrp->IoStatus.Information будет кол-во записанных в буфер байт, но не размер самого буфера (он может быть больше).
     
  8. SlyBit

    SlyBit New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2008
    Сообщения:
    43
    x64

    Большое спасибо за развернутый ответ.

    > Вот тебе нужен весь это гемор, а?
    да не такой уж и гемор.