Разрабатывается фильтр файловой системы (не минифильтр!). Появилась необходимость писать в свой лог-файл информацию о перехватываемых IRP_MJ_xxx (в частности: IRP_MJ_CREATE, IRP_MJ_WRITE, IRP_MJ_READ, IRP_MJ_GET_INFORMATION). Чтобы было наглядно:
Проблема в том, что обычные методы записи (ZwWriteFile) здесь не помогают, поскольку если WriteLog(PUCHAR log) вызывает ZwWriteFile, то получится рекурсия, поскольку ZwWriteFile для записи лога инициирует новый IRP_MJ_WRITE в контексте текущей обработки IrpHandler_Write. По этому данный способ не приемлим.
Покурив документацию DDK, в голову пришла мысль использовать IoBuildSynchronousFsdRequest.
Теперь WriteLog(log) выглядит примерно так:
Собственно, здесь запрос на запись завершается нормально (STATUS_SUCCESS), если параметры верны.
Дополнительных запосов для моего фильтра при этом не строится.
Теперь, собственно проблема: если операция записи завершена успешно, а при закрытии файла лога данные на диск не сбрасываются. У кого есть какие мысли? Может быть нужно отправить еще какие-то IRP в догонку IRP_MJ_WRITE (к стати, попробовал IRP_MJ_FLUSH_BUFFERS: в результате он иницировал еще IRP_MJ_WRITE для файла лога)
Код |
---|
NTSTATUS IrpHandler_Write(PDEVICE_OBJECT pDevObj, PIRP pIrp) { PUCHAR log = ExAllocPool(NonPagedPool, LOG_SIZE); // парсим содержимое запроса ParseRequest(log, pDevObj, pIrp); // записываем в лог-файл WriteLog(log); // передача пакета нижележащему DO ... } |
Проблема в том, что обычные методы записи (ZwWriteFile) здесь не помогают, поскольку если WriteLog(PUCHAR log) вызывает ZwWriteFile, то получится рекурсия, поскольку ZwWriteFile для записи лога инициирует новый IRP_MJ_WRITE в контексте текущей обработки IrpHandler_Write. По этому данный способ не приемлим.
Покурив документацию DDK, в голову пришла мысль использовать IoBuildSynchronousFsdRequest.
Теперь WriteLog(log) выглядит примерно так:
Код |
---|
NTSTATUS WriteLog(PUCHAR log, ULONG size) { PIRP pIrp; PIO_STACK_LOCATION pIrpSp; KEVENT evt; IO_STATUS_BLOCK ioStatus; NTSTATUS ns; LARGE_INTEGER offset; ULONG allignedSize; PFILE_OBJECT pFileObjectIntern; PDEVICE_OBJECT pDeviceObjectIntern; PUCHAR pLockedBuff; // global_pFileObjectLog - глобальная переменная, содержащая указатель на объект файла лога // у него (объекта файла) должен быть установлен флаг FILE_OPENED (достаточно не вызывать // ZwClose() после создания файла лога). pFileObjectIntern = global_pFileObjectLog; // получаем указатель на объект нашего фильтрующего DO pDeviceObjectIntern = IoGetRelatedDeviceObject(pFileObjectIntern); // извлекаем указатель на нижележащий DO в стеке девайсов pDeviceObjectIntern = IoGetLowerDeviceObject(pDeviceObjectIntern); // инициализируем евент для ожидания завершения операции KeInitializeEvent(&evt, NotificationEvent, FALSE); // создаем буфер с учетом выравнивания allignedSize = ALLIGN_UP(size, 512); pLockedBuff = ExAllocatePool(NonPagedPool, allignedSize); memcpy(pLockedBuff, log, allignedSize); offset = 0i64; // создаем IRP pIrp = IoBuildSynchronousFsdRequest( IRP_MJ_WRITE, pDeviceObjectIntern, pLockedBuff, allignedSize, &offset, &evt, &ioStatus ); pIrp->Tail.Overlay.Thread = KeGetCurrentThread(); pIrp->RequestorMode = KernelMode; pIrp->Tail.Overlay.OriginalFileObject = pFileObjectIntern; pIrpSp = IoGetNextIrpStackLocation(pIrp); pIrpSp->FileObject = pFileObjectIntern; pIrpSp->Parameters.Write.ByteOffset.LowPart = offset.LowPart; pIrpSp->Parameters.Write.ByteOffset.HighPart = offset.HighPart; pIrpSp->Parameters.Write.Key =0; pIrpSp->Parameters.Write.Length = size; // пишем в файл ns = IoCallDriver( pDeviceObjectIntern, pIrp); if (ns == STATUS_PENDING) { KeWaitForSingleObject(&evt,Executive,KernelMode,FALSE, NULL); } ExFreePool(pLockedBuff); return ioStaus.Status; } |
Собственно, здесь запрос на запись завершается нормально (STATUS_SUCCESS), если параметры верны.
Дополнительных запосов для моего фильтра при этом не строится.
Теперь, собственно проблема: если операция записи завершена успешно, а при закрытии файла лога данные на диск не сбрасываются. У кого есть какие мысли? Может быть нужно отправить еще какие-то IRP в догонку IRP_MJ_WRITE (к стати, попробовал IRP_MJ_FLUSH_BUFFERS: в результате он иницировал еще IRP_MJ_WRITE для файла лога)