I have implemented the shadow device technique to read files during IRP_MJ_CREATE in my dispatch routine of my filter driver and to avoid reentrancy problems. I am hooking the usb stick volume. This works fine so far.
But, in some cases (reading especially MS files like doc, ppt etc), there are open file handles left so that the usb stick cannot be removed safely. I don’t know why.
Below my shadow device dispatch routine (the decision to go that way is made on the device name in the device extensions):
NTSTATUS
ShadowRoutine(
PDEVICE_OBJECT HookDevice,
IN PIRP Irp)
{
PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
PHOOK_EXTENSION hookExt;
PFILE_OBJECT FileObject;
//
// Extract the file object from the IRP
//
FileObject = currentIrpStack->FileObject;
//
// Point at the device extension, which contains information on which
// file system this IRP is headed for
//
hookExt = HookDevice->DeviceExtension;
// We use a shadow device for calls to ZwCreateFile during IRP_MJ_CREATE in FilemonHookRoutine
DbgPrint((“Irp for shadow device: %S - pass it down to FSD \n”, hookExt->DeviceName));
//
if( FileObject->DeviceObject != NULL )
{
if( FileObject->DeviceObject == HookDevice )
{
DbgPrint((“FileObject is shadow device: InterlockedDecrement \n”));
InterlockedDecrement(&FileObject -> DeviceObject -> ReferenceCount);
}
FileObject->DeviceObject = hookExt->FileSystem;
InterlockedIncrement(&FileObject->DeviceObject->ReferenceCount);
}
currentIrpStack->DeviceObject = hookExt->FileSystem;
IoSkipCurrentIrpStackLocation(Irp);
//simply pass IRPs…
return IoCallDriver ( hookExt->FileSystem, Irp );
}
Now the relevant part of my main dispatch routine (hook device)
switch( currentIrpStack->MajorFunction ) {
case IRP_MJ_CREATE:
if (condition)
{
// access device file name with shadow device
if (FileObject->FileName.Buffer != NULL)
{
// Get the Device Name of the shadow device
shadowExtension = hookExt->RelatedDeviceObject->DeviceExtension;
if (shadowExtension == NULL)
{
DbgPrint((“Device Object has NO shadow device!! \n”));
}
else
{
if (wcslen(FileObject->FileName.Buffer) > 1)
{
// construct device file name with shadow device name if file name is available (ignore ‘\’)
pwszShadowDeviceFileName = ExAllocatePool( PagedPool, (MAXPATHLEN + 1) * sizeof(WCHAR) );
if (pwszShadowDeviceFileName == NULL)
{
DbgPrint((“ExAllocatePool returned NULL -> insufficient resources \n”));
}
else
{
swprintf(pwszShadowDeviceFileName, L"%s%s", shadowExtension->DeviceName, FileObject->FileName.Buffer);
DbgPrint((“Shadow Device File Name in IRP_MJ_CREATE: %S \n”, pwszShadowDeviceFileName));
// ZwCreate and file operations with shadow device
RtlInitUnicodeString(&unipathname, pwszShadowDeviceFileName);
InitializeObjectAttributes(&oa, &unipathname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
fstatus = ZwCreateFile(&hfile, SYNCHRONIZE|GENERIC_READ, &oa, &fiostatus, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (NT_SUCCESS(fstatus))
{
DbgPrint((“ZwCreateFile in IRP_MJ_CREATE successful!!\n”));
fbyteOffset.LowPart = fbyteOffset.HighPart = 0;
fstatus = ZwReadFile(hfile, NULL, NULL, NULL, &fiostatus, idcharbuf, bufsize, &fbyteOffset, NULL);
if (NT_SUCCESS(fstatus))
{
// do something
}
}
else
{
DbgPrint((“ZwCreateFile Error: Status=%x,IoStatusBlock=%x\n”, fstatus, fiostatus));
}
if (hfile != NULL)
{
fstatus = ZwClose(hfile);
if (!NT_SUCCESS(fstatus))
{
DbgPrint((“ZwClose Error: Status=%x \n”, fstatus));
}
}
ExFreePool(pwszShadowDeviceFileName);
}
}
}
}
What could be the reason that some (kernel) handles obviously will not be closed correctly?
Any help would be appreciated. Thanks.