Всем привет. Хукаю IRP_MJ_READ драйвера, устанавливаю свою CompletionRoutine, но через некоторое время (буквально 1-2 минуты) система падает. Оригинальная pIrpStack->CompletionRoutine всегда ровна NULL. В чем проблема? Код (Text): NTSTATUS IoCompletionRoutine(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext) { if(pContext) { ((PIO_COMPLETION_ROUTINE)pContext)(pDeviceObject, pIrp, NULL); } else { return STATUS_SUCCESS; } } NTSTATUS HookedMajorFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION pIrpStack = NULL; pIrpStack = IoGetCurrentIrpStackLocation(Irp); switch(pIrpStack->MajorFunction) { case IRP_MJ_READ: pIrpStack->Control = 0; pIrpStack->Control |= SL_INVOKE_ON_SUCCESS; pIrpStack->Context = pIrpStack->CompletionRoutine; pIrpStack->CompletionRoutine = IoCompletionRoutine; return pOriginalIrpMjRead(DeviceObject, Irp); } } p.s. В IoCompletionRoutine() адрес буфера с данными всегда будет находиться в pIrp->AssociatedIrp.SystemBuffer, а их длина в pIrp->IoStatus.Information ? Спасибо.
> Для приличия хоть посмотрели б IoSetCompletionRoutine макрос. Спасибо. Не знал про него. > IoCompletionRoutine тоже хреновая Что это значит?
Не вводи людей в заблуждение. IoSetCompletionRoutine() здесь не поможет, ибо используется в фильтрах, а у человека обычный хукер.
Код (Text): NTSTATUS IoCompletionRoutine(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID pContext) { if(pContext) { ((PIO_COMPLETION_ROUTINE)pContext)(pDeviceObject, pIrp, NULL); } else { return STATUS_SUCCESS; } } В твоей completion routine косяков немеряно. По пунктам: 1. От pContext ничего зависеть не должно, ты должен чётко знать, что там. 2. Если уж вызываешь нижележащую completion routine, то возвращай системе то значение, которое она вернула тебе. 3. Нижележащая completion routine вызывается с контекстом, равным NULL, а должна вызываться с оригинальным. Код (Text): NTSTATUS HookedMajorFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION pIrpStack = NULL; pIrpStack = IoGetCurrentIrpStackLocation(Irp); switch(pIrpStack->MajorFunction) { case IRP_MJ_READ: pIrpStack->Control = 0; pIrpStack->Control |= SL_INVOKE_ON_SUCCESS; pIrpStack->Context = pIrpStack->CompletionRoutine; pIrpStack->CompletionRoutine = IoCompletionRoutine; return pOriginalIrpMjRead(DeviceObject, Irp); } } Здесь правильно было бы выделить область памяти под собственный контекст, где сохранять как минимум три вещи: адрес оригинальной completion routine, указатель на её контекст и оригинальное значение поля pIrpStack->Control (короче, структурка с тремя полями). pIrpStack->Control действительно в твоём случае настраивать нужно ручками, но делать это нужно так: Код (Text): 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 будет кол-во записанных в буфер байт, но не размер самого буфера (он может быть больше).
x64 Большое спасибо за развернутый ответ. > Вот тебе нужен весь это гемор, а? да не такой уж и гемор.