?? filespy.c
字號:
/*++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
filespy.c
Abstract:
This is the main module of FileSpy.
Author:
Environment:
Kernel mode
Revision History:
George Jenkins (georgeje) 6-Jan-1999 cloned from sfilter.c
--*/
#include <ntifs.h>
#include "filespy.h"
#include "fspyKern.h"
//
// Global storage for this file system filter driver.
//
PDEVICE_OBJECT gControlDeviceObject;
PDRIVER_OBJECT gFsDriverObject;
FAST_MUTEX gSpyDeviceExtensionListLock;
LIST_ENTRY gSpyDeviceExtensionList;
//
// NOTE 1: There are some cases where we need to hold both the
// gControlDeviceStateLock and the gOutputBufferLock at the same time. In
// these cases, you should acquire the gControlDeviceStateLock then the
// gOutputBufferLock.
// NOTE 2: The gControlDeviceStateLock MUST be a spinlock since we try to
// acquire it during the completion path in SpyLog, which could be called at
// DISPATCH_LEVEL (only KSPIN_LOCKs can be acquired at DISPATCH_LEVEL).
//
CONTROL_DEVICE_STATE gControlDeviceState = CLOSED;
KSPIN_LOCK gControlDeviceStateLock;
// NOTE: Like the gControlDeviceStateLock, gOutputBufferLock MUST be a spinlock
// since we try to acquire it during the completion path in SpyLog, which
// could be called at DISPATCH_LEVEL (only KSPIN_LOCKs can be acquired at
// DISPATCH_LEVEL).
//
KSPIN_LOCK gOutputBufferLock;
LIST_ENTRY gOutputBufferList;
NPAGED_LOOKASIDE_LIST gFreeBufferList;
ULONG gLogSequenceNumber = 0;
KSPIN_LOCK gLogSequenceLock;
UNICODE_STRING gVolumeString;
UNICODE_STRING gOverrunString;
UNICODE_STRING gPagingIoString;
//
// NOTE: Like above for the ControlDeviceLock, we must use KSPIN_LOCKs
// to synchronize access to hash buckets since we may call try to
// acquire them at DISPATCH_LEVEL.
//
LIST_ENTRY gHashTable[HASH_SIZE];
KSPIN_LOCK gHashLockTable[HASH_SIZE];
ULONG gHashMaxCounters[HASH_SIZE];
ULONG gHashCurrentCounters[HASH_SIZE];
HASH_STATISTICS gHashStat;
LONG gMaxRecordsToAllocate = DEFAULT_MAX_RECORDS_TO_ALLOCATE;
LONG gRecordsAllocated = 0;
LONG gMaxNamesToAllocate = DEFAULT_MAX_NAMES_TO_ALLOCATE;
LONG gNamesAllocated = 0;
LONG gStaticBufferInUse = FALSE;
CHAR gOutOfMemoryBuffer[RECORD_SIZE];
//
// Macro to test if we are logging for this device
// NOTE: We don't bother synchronizing to check the gControlDeviceState since
// we can tolerate a stale value here. We just look at it here to avoid
// doing the logging work if we can. We synchronize to check the
// gControlDeviceState before we add the log record to the gOutputBufferList
// and discard the log record if the ControlDevice is no longer OPENED.
//
#define SHOULD_LOG(pDeviceObject) \
((gControlDeviceState == OPENED) && \
ASSERT(((PDEVICE_EXTENSION)(pDeviceObject)->DeviceExtension)->Type == \
FILESPY_DEVICE_TYPE) && \
((PDEVICE_EXTENSION)(pDeviceObject)->DeviceExtension)->LogThisDevice)
//
// Macro for validating the FastIo dispatch routines before calling
// them in the FastIo pass through functions.
//
#define VALID_FAST_IO_DISPATCH_HANDLER( FastIoDispatchPtr, Handler) \
((FastIoDispatchPtr) && (FastIoDispatchPtr)->Handler)
//
// Since functions in drivers are non-pagable by default, these pragmas
// allow the driver writer to tell the system what functions can be paged.
//
// Use the PAGED_CODE() macro at the beginning of these functions'
// implementations while debugging to ensure that these routines are
// never called at IRQL > APC_LEVEL (therefore the routine cannot
// be paged).
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, SpyFastIoCheckIfPossible)
#pragma alloc_text(PAGE, SpyFastIoRead)
#pragma alloc_text(PAGE, SpyFastIoWrite)
#pragma alloc_text(PAGE, SpyFastIoQueryBasicInfo)
#pragma alloc_text(PAGE, SpyFastIoQueryStandardInfo)
#pragma alloc_text(PAGE, SpyFastIoLock)
#pragma alloc_text(PAGE, SpyFastIoUnlockSingle)
#pragma alloc_text(PAGE, SpyFastIoUnlockAll)
#pragma alloc_text(PAGE, SpyFastIoUnlockAllByKey)
#pragma alloc_text(PAGE, SpyFastIoDeviceControl)
#pragma alloc_text(PAGE, SpyFastIoDetachDevice)
#pragma alloc_text(PAGE, SpyFastIoQueryNetworkOpenInfo)
#pragma alloc_text(PAGE, SpyFastIoAcquireForModWrite)
#pragma alloc_text(PAGE, SpyFastIoMdlRead)
#pragma alloc_text(PAGE, SpyFastIoPrepareMdlWrite)
#pragma alloc_text(PAGE, SpyFastIoMdlWriteComplete)
#pragma alloc_text(PAGE, SpyFastIoReadCompressed)
#pragma alloc_text(PAGE, SpyFastIoWriteCompressed)
#pragma alloc_text(PAGE, SpyFastIoQueryOpen)
#pragma alloc_text(PAGE, SpyFastIoReleaseForModWrite)
#pragma alloc_text(PAGE, SpyFastIoAcquireForCcFlush)
#pragma alloc_text(PAGE, SpyFastIoReleaseForCcFlush)
#ifdef SPY_BOOT_DRIVER
#pragma alloc_text(PAGE, SpyReinitDriver)
#endif
#endif
#ifdef SPY_BOOT_DRIVER
VOID
SpyReinitDriver(
PDRIVER_OBJECT DriverObject,
PVOID Context,
ULONG Count
)
/*++
Routine Description:
This routine attaches FileSpy to the drives that were listed
in the Registry. This routine is passed into
IoRegisterBootDriverReinitialization.
Arguments:
DriverObject - FileSpy's driver object
Context - The partial value information from reading the
list of drives to attached to from the registry.
Count - not used
Return Value:
None.
--*/
{
PKEY_VALUE_PARTIAL_INFORMATION pValuePartialInfo;
NTSTATUS status;
PWSTR attachDrives;
PAGED_CODE();
if (NULL != Context) {
pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) Context;
attachDrives = (PWSTR)&pValuePartialInfo->Data;
while(*attachDrives){
status = SpyAttachDevice(gControlDeviceObject, attachDrives);
while(*attachDrives++) // look for the null
;
}
ExFreePool(Context);
}
}
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the initialization routine for the general purpose file system
filter driver. This routine creates the device object that represents
this driver in the system and registers it for watching all file systems
that register or unregister themselves as active file systems.
Arguments:
DriverObject - Pointer to driver object created by the system.
Return Value:
The function value is the final status from the initialization operation.
--*/
{
UNICODE_STRING nameString;
PFILE_OBJECT fileObject;
NTSTATUS status;
PFAST_IO_DISPATCH fastIoDispatch;
ULONG i;
PDEVICE_EXTENSION deviceExtension;
UNICODE_STRING linkString;
//////////////////////////////////////////////////////////////////////
// //
// General setup for all filter drivers. This sets up the filter //
// driver's DeviceObject and registers the callback routines for //
// the filter driver. //
// //
//////////////////////////////////////////////////////////////////////
//
// Create the device object that will represent the FileSpy device.
//
RtlInitUnicodeString( &nameString, FILESPY_FULLDEVICE_NAME );
//
// Create the "control" device object. Note that this device object does
// not have a device extension (set to NULL). Most of the fast IO routines
// check for this condition to determine if the fast IO is directed at the
// control device.
//
status = IoCreateDevice(
DriverObject,
0,
&nameString,
FILESPY_DEVICE_TYPE,
0,
FALSE,
&gControlDeviceObject);
if (!NT_SUCCESS( status )) {
#if DBG
DbgPrint( "Error creating FileSpy device, error: %x\n", status );
#endif // DBG
return status;
} else {
RtlInitUnicodeString ( &linkString, FILESPY_DOSDEVICE_NAME );
status = IoCreateSymbolicLink ( &linkString, &nameString );
if (!NT_SUCCESS(status)) {
DbgPrint (("FileSpy.SYS: IoCreateSymbolicLink failed\n"));
IoDeleteDevice(gControlDeviceObject);
return status;
}
}
//
// Initialize the driver object with this device driver's entry points.
//
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObject->MajorFunction[i] = SpyDispatch;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = SpyCreate;
//
// Allocate fast I/O data structure and fill it in. This structure
// is used to register the callbacks for FileSpy in the fast I/O
// data paths.
//
fastIoDispatch = ExAllocatePool( NonPagedPool, sizeof( FAST_IO_DISPATCH ) );
if (!fastIoDispatch) {
IoDeleteDevice( gControlDeviceObject );
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( fastIoDispatch, sizeof( FAST_IO_DISPATCH ) );
fastIoDispatch->SizeOfFastIoDispatch = sizeof( FAST_IO_DISPATCH );
fastIoDispatch->FastIoCheckIfPossible = SpyFastIoCheckIfPossible;
fastIoDispatch->FastIoRead = SpyFastIoRead;
fastIoDispatch->FastIoWrite = SpyFastIoWrite;
fastIoDispatch->FastIoQueryBasicInfo = SpyFastIoQueryBasicInfo;
fastIoDispatch->FastIoQueryStandardInfo = SpyFastIoQueryStandardInfo;
fastIoDispatch->FastIoLock = SpyFastIoLock;
fastIoDispatch->FastIoUnlockSingle = SpyFastIoUnlockSingle;
fastIoDispatch->FastIoUnlockAll = SpyFastIoUnlockAll;
fastIoDispatch->FastIoUnlockAllByKey = SpyFastIoUnlockAllByKey;
fastIoDispatch->FastIoDeviceControl = SpyFastIoDeviceControl;
fastIoDispatch->FastIoDetachDevice = SpyFastIoDetachDevice;
fastIoDispatch->FastIoQueryNetworkOpenInfo = SpyFastIoQueryNetworkOpenInfo;
fastIoDispatch->AcquireForModWrite = SpyFastIoAcquireForModWrite;
fastIoDispatch->MdlRead = SpyFastIoMdlRead;
fastIoDispatch->MdlReadComplete = SpyFastIoMdlReadComplete;
fastIoDispatch->PrepareMdlWrite = SpyFastIoPrepareMdlWrite;
fastIoDispatch->MdlWriteComplete = SpyFastIoMdlWriteComplete;
fastIoDispatch->FastIoReadCompressed = SpyFastIoReadCompressed;
fastIoDispatch->FastIoWriteCompressed = SpyFastIoWriteCompressed;
fastIoDispatch->MdlReadCompleteCompressed =
SpyFastIoMdlReadCompleteCompressed;
fastIoDispatch->MdlWriteCompleteCompressed =
SpyFastIoMdlWriteCompleteCompressed;
fastIoDispatch->FastIoQueryOpen = SpyFastIoQueryOpen;
fastIoDispatch->ReleaseForModWrite = SpyFastIoReleaseForModWrite;
fastIoDispatch->AcquireForCcFlush = SpyFastIoAcquireForCcFlush;
fastIoDispatch->ReleaseForCcFlush = SpyFastIoReleaseForCcFlush;
DriverObject->FastIoDispatch = fastIoDispatch;
//////////////////////////////////////////////////////////////////////
// //
// Initialize global data structures that are used for FileSpy's //
// logging of I/O operations. //
// //
//////////////////////////////////////////////////////////////////////
InitializeListHead( &gSpyDeviceExtensionList );
//
// A fast mutex was used in this case because the mutex is never acquired at DPC level or above.
// Spinlocks were chosen in other cases because they are acquired at DPC level or above.
// Another consideration is that on an MP machine, a spin lock will literally spin trying to
// acquire the lock when the lock is already acquired. Acquiring a previously acquired fast
// mutex will suspend the thread, thus freeing up the processor.
//
ExInitializeFastMutex( &gSpyDeviceExtensionListLock );
gFsDriverObject = DriverObject;
KeInitializeSpinLock( &gControlDeviceStateLock );
InitializeListHead( &gOutputBufferList );
KeInitializeSpinLock( &gOutputBufferLock );
KeInitializeSpinLock( &gLogSequenceLock );
#ifndef MEMORY_DBG
//
// When we aren't debugging our memory usage, we want to allocate
// memory from a lookaside list for better performance. Unfortunately,
// we cannot benefit from the memory debugging help of the Driver
// Verifier if we allocate memory from a look-aside list.
//
ExInitializeNPagedLookasideList(
&gFreeBufferList,
ExAllocatePoolWithTag,
ExFreePool,
0,
RECORD_SIZE,
MSFM_TAG,
100 );
#endif
//
// Initialize the hash table
//
for (i = 0; i < HASH_SIZE; i++){
InitializeListHead(&gHashTable[i]);
KeInitializeSpinLock(&gHashLockTable[i]);
}
//
// Indicate that the type for this device object is a primary, not a
// filter device object so that it doesn't accidentally get used to
// call a file system.
//
RtlInitUnicodeString(&gVolumeString, L"VOLUME");
RtlInitUnicodeString(&gOverrunString, L"......");
RtlInitUnicodeString(&gPagingIoString, L"Paging IO");
//
// Read the custom parameters for FileSpy from the registry
//
SpyReadDriverParameters(RegistryPath, DriverObject);
return STATUS_SUCCESS;
}
DBGSTATIC
NTSTATUS
SpyPassThrough(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -