📄 fspylib.c
字号:
}
VOID
SpyLogPostFsFilterOperation (
IN NTSTATUS OperationStatus,
OUT PRECORD_LIST RecordList
)
{
PRECORD_FS_FILTER_OPERATION pRecordFsFilterOp;
pRecordFsFilterOp = &RecordList->LogRecord.Record.RecordFsFilterOp;
//
// Record the information we see in the post operation.
//
pRecordFsFilterOp->ReturnStatus = OperationStatus;
KeQuerySystemTime( &pRecordFsFilterOp->CompletionTime );
}
#endif
NTSTATUS
SpyAttachDeviceToDeviceStack (
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice,
IN OUT PDEVICE_OBJECT *AttachedToDeviceObject
)
/*++
Routine Description:
This routine attaches the SourceDevice to the TargetDevice's stack and
returns the device object SourceDevice was directly attached to in
AttachedToDeviceObject. Note that the SourceDevice does not necessarily
get attached directly to TargetDevice. The SourceDevice will get attached
to the top of the stack of which TargetDevice is a member.
VERSION NOTE:
In Windows XP, a new API was introduced to close a rare timing window that
can cause IOs to start being sent to a device before its
AttachedToDeviceObject is set in its device extension. This is possible
if a filter is attaching to a device stack while the system is actively
processing IOs. The new API closes this timing window by setting the
device extension field that holds the AttachedToDeviceObject while holding
the IO Manager's lock that protects the device stack.
A sufficient work around for earlier versions of the OS is to set the
AttachedToDeviceObject to the device object that the SourceDevice is most
likely to attach to. While it is possible that another filter will attach
in between the SourceDevice and TargetDevice, this will prevent the
system from bug checking if the SourceDevice receives IOs before the
AttachedToDeviceObject is correctly set.
For a driver built in the Windows 2000 build environment, we will always
use the work-around code to attach. For a driver that is built in the
Windows XP or later build environments (therefore you are building a
multiversion driver), we will determine which method of attachment to use
based on which APIs are available.
Arguments:
SourceDevice - The device object to be attached to the stack.
TargetDevice - The device that we currently think is the top of the stack
to which SourceDevice should be attached.
AttachedToDeviceObject - This is set to the device object to which
SourceDevice is attached if the attach is successful.
Return Value:
Return STATUS_SUCCESS if the device is successfully attached. If
TargetDevice represents a stack to which devices can no longer be attached,
STATUS_NO_SUCH_DEVICE is returned.
--*/
{
PAGED_CODE();
#if WINVER >= 0x0501
if (IS_WINDOWSXP_OR_LATER()) {
ASSERT( NULL != gSpyDynamicFunctions.AttachDeviceToDeviceStackSafe );
return (gSpyDynamicFunctions.AttachDeviceToDeviceStackSafe)( SourceDevice,
TargetDevice,
AttachedToDeviceObject );
} else {
#endif
*AttachedToDeviceObject = TargetDevice;
*AttachedToDeviceObject = IoAttachDeviceToDeviceStack( SourceDevice,
TargetDevice );
if (*AttachedToDeviceObject == NULL) {
return STATUS_NO_SUCH_DEVICE;
}
return STATUS_SUCCESS;
#if WINVER >= 0x0501
}
#endif
}
NTSTATUS
SpyLog (
IN PRECORD_LIST NewRecord
)
/*++
Routine Description:
This routine appends the completed log record to the gOutputBufferList.
Arguments:
NewRecord - The record to append to the gOutputBufferList
Return Value:
The function returns STATUS_SUCCESS.
--*/
{
KIRQL controlDeviceIrql;
KIRQL outputBufferIrql;
KeAcquireSpinLock( &gControlDeviceStateLock, &controlDeviceIrql );
if (gControlDeviceState == OPENED) {
//
// The device is still open so add this record onto the list
//
KeAcquireSpinLock(&gOutputBufferLock, &outputBufferIrql);
InsertTailList(&gOutputBufferList, &NewRecord->List);
KeReleaseSpinLock(&gOutputBufferLock, outputBufferIrql);
} else {
//
// We can no longer log this record, so free the record
//
SpyFreeRecord( NewRecord );
}
KeReleaseSpinLock( &gControlDeviceStateLock, controlDeviceIrql );
return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////////
// //
// FileName cache routines //
// //
////////////////////////////////////////////////////////////////////////
NTSTATUS
SpyQueryInformationFile (
IN PDEVICE_OBJECT NextDeviceObject,
IN PFILE_OBJECT FileObject,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
OUT PULONG LengthReturned OPTIONAL
)
/*++
Routine Description:
This routine returns the requested information about a specified file.
The information returned is determined by the FileInformationClass that
is specified, and it is placed into the caller's FileInformation buffer.
Arguments:
NextDeviceObject - Supplies the device object where this IO should start
in the device stack.
FileObject - Supplies the file object about which the requested
information should be returned.
FileInformation - Supplies a buffer to receive the requested information
returned about the file. This must be a buffer allocated from kernel
space.
Length - Supplies the length, in bytes, of the FileInformation buffer.
FileInformationClass - Specifies the type of information which should be
returned about the file.
LengthReturned - the number of bytes returned if the operation was
successful.
Return Value:
The status returned is the final completion status of the operation.
--*/
{
PIRP irp = NULL;
PIO_STACK_LOCATION irpSp = NULL;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// In DBG builds, make sure that we have valid parameters before we do
// any work here.
//
ASSERT( NULL != NextDeviceObject );
ASSERT( NULL != FileObject );
ASSERT( NULL != FileInformation );
//
// The parameters look ok, so setup the Irp.
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
ioStatusBlock.Status = STATUS_SUCCESS;
ioStatusBlock.Information = 0;
irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set our current thread as the thread for this
// IRP so that the IO Manager always knows which
// thread to return to if it needs to get back into
// the context of the thread that originated this
// IRP.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Set that this IRP originated from the kernel so that
// the IO Manager knows that the buffers do not
// need to be probed.
//
irp->RequestorMode = KernelMode;
//
// Initialize the UserIosb and UserEvent in the IRP.
//
irp->UserIosb = &ioStatusBlock;
irp->UserEvent = NULL;
//
// Set the IRP_SYNCHRONOUS_API to denote that this
// is a synchronous IO request.
//
irp->Flags = IRP_SYNCHRONOUS_API;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
irpSp->FileObject = FileObject;
//
// Setup the parameters for IRP_MJ_QUERY_INFORMATION. These
// were supplied by the caller of this routine.
// The buffer we want to be filled in should be placed in
// the system buffer.
//
irp->AssociatedIrp.SystemBuffer = FileInformation;
irpSp->Parameters.QueryFile.Length = Length;
irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
//
// Set up the completion routine so that we know when our
// request for the file name is completed. At that time,
// we can free the IRP.
//
IoSetCompletionRoutine( irp,
SpyQueryCompletion,
&event,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( NextDeviceObject, irp );
if (STATUS_PENDING == status) {
KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
}
//
// Verify the completion has actually been run
//
ASSERT(KeReadStateEvent(&event) || !NT_SUCCESS(ioStatusBlock.Status));
if (ARGUMENT_PRESENT(LengthReturned)) {
*LengthReturned = (ULONG) ioStatusBlock.Information;
}
return ioStatusBlock.Status;
}
NTSTATUS
SpyQueryCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT SynchronizingEvent
)
/*++
Routine Description:
This routine does the cleanup necessary once the query request completed
by the file system.
Arguments:
DeviceObject - This will be NULL since we originated this
Irp.
Irp - The IO request structure containing the information
about the current state of our file name query.
SynchronizingEvent - The event to signal to notify the
originator of this request that the operation is
complete.
Return Value:
Returns STATUS_MORE_PROCESSING_REQUIRED so that IO Manager
will not try to free the Irp again.
--*/
{
UNREFERENCED_PARAMETER( DeviceObject );
//
// Make sure that the Irp status is copied over to the users
// IO_STATUS_BLOCK so that the originator of this IRP will know
// the final status of this operation.
//
ASSERT( NULL != Irp->UserIosb );
*Irp->UserIosb = Irp->IoStatus;
//
// Signal SynchronizingEvent so that the originator of this
// Irp know that the operation is completed.
//
KeSetEvent( SynchronizingEvent, IO_NO_INCREMENT, FALSE );
//
// We are now done, so clean up the IRP that we allocated.
//
IoFreeIrp( Irp );
//
// If we return STATUS_SUCCESS here, the IO Manager will
// perform the cleanup work that it thinks needs to be done
// for this IO operation.
//
// We can do this cleanup work more efficiently than the IO Manager
// since we are handling a very specific case.
//
// Since the IO Manager has already performed all the work we want it to
// do on this IRP, we do the cleanup work, return
// STATUS_MORE_PROCESSING_REQUIRED, and ask the IO Manager to resume
// processing by calling IoCompleteRequest.
//
// See NLQueryCompletion for a more verbose comment on this.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
////////////////////////////////////////////////////////////////////////
// //
// Common attachment and detachment routines //
// //
////////////////////////////////////////////////////////////////////////
//
// VERSION NOTE:
//
// To be able to safely find out if our filter is attached to a device given
// its name on Windows 2000 and later, we need to use the approach in
// SpyIsAttachedToDeviceByName. This method uses APIs that are
// available on Windows 2000 and later. On Windows XP or later, you could
// change this routine to separate the translation from DeviceName to device
// object from the search to see if our filter's device is attached to the
// device stack. In Windows XP and later, the logic to translate the
// DeviceName to the device object is the same, but you can use the logic
// in SpyIsAttachedToDeviceWXPAndLater to find your filter's device object
// in the device stack safely.
//
NTSTATUS
SpyIsAttachedToDeviceByName (
IN PNAME_CONTROL DeviceName,
IN OUT PBOOLEAN IsAttached,
IN OUT PDEVICE_OBJECT *StackDeviceObject,
IN OUT PDEVICE_OBJECT *OurAttachedDeviceObject
)
/*++
Routine Description:
This routine maps a device name (DOS or NT style) to a file system device
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -