📄 filespy.c
字号:
/*++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
filespy.c
Abstract:
This is the main module of FileSpy.
As of the Windows XP SP1 IFS Kit version of this sample and later, this
sample can be built for each build environment released with the IFS Kit
with no additional modifications. To provide this capability, additional
compile-time logic was added -- see the '#if WINVER' locations. Comments
tagged with the 'VERSION NOTE' header have also been added as appropriate to
describe how the logic must change between versions.
If this sample is built in the Windows XP environment or later, it will run
on Windows 2000 or later. This is done by dynamically loading the routines
that are only available on Windows XP or later and making run-time decisions
to determine what code to execute. Comments tagged with 'MULTIVERISON NOTE'
mark the locations where such logic has been added.
Environment:
Kernel mode
--*/
//
// Fixes Win2K compatibility regarding lookaside lists.
//
#ifndef _WIN2K_COMPAT_SLIST_USAGE
#define _WIN2K_COMPAT_SLIST_USAGE
#endif
#include <ntifs.h>
#include <stdlib.h>
#include "filespy.h"
#include "fspyKern.h"
//
// Global variables.
//
ULONG gFileSpyDebugLevel = DEFAULT_FILESPY_DEBUG_LEVEL;
#if WINVER >= 0x0501
ULONG gFileSpyAttachMode = FILESPY_ATTACH_ALL_VOLUMES;
#else
ULONG gFileSpyAttachMode = FILESPY_ATTACH_ON_DEMAND;
#endif
UNICODE_STRING gInsufficientUnicode = CONSTANT_UNICODE_STRING(L"[-=Insufficient Resources=-]");
UNICODE_STRING gEmptyUnicode = CONSTANT_UNICODE_STRING(L"");
//
// This lookaside list is used to allocate NAME_CONTROLs. A name control
// has a small buffer that should be big enough to handle most object names,
// and can be resized if necessary. These name controls are used in many
// places to avoid allocating a large name buffer on the stack.
//
// We allocate space for the name control from the lookaside list, which is
// efficient because the size of the allocation is known and constant. If more
// buffer space is needed, we use NLCheckAndGrowNameControl which then
// allocates more space from paged pool.
//
#define FILESPY_LOOKASIDE_SIZE sizeof( NAME_CONTROL )
PAGED_LOOKASIDE_LIST gFileSpyNameBufferLookasideList;
PDEVICE_OBJECT gControlDeviceObject;
PDRIVER_OBJECT gFileSpyDriverObject;
//
// The list of device extensions for the volume device objects we are
// attached to (the volumes we are spying on). Note: This list does NOT
// include FileSystem control device objects we are attached to. This
// list is used to answer the question "Which volumes are we logging?"
//
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;
#ifndef MEMORY_DBG
NPAGED_LOOKASIDE_LIST gFreeBufferList;
#endif
ULONG gLogSequenceNumber = 0;
KSPIN_LOCK gLogSequenceLock;
UNICODE_STRING gVolumeString;
UNICODE_STRING gOverrunString;
UNICODE_STRING gPagingIoString;
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];
#if WINVER >= 0x0501
//
// The structure of function pointers for the functions that are not available
// on all OS versions.
//
SPY_DYNAMIC_FUNCTION_POINTERS gSpyDynamicFunctions = {0};
ULONG gSpyOsMajorVersion = 0;
ULONG gSpyOsMinorVersion = 0;
#endif
//
// Control FileSpy statistics
//
FILESPY_STATISTICS gStats;
//
// This lock is used to synchronize our attaching to a given device object.
// This lock fixes a race condition where we could accidently attach to the
// same device object more then once. This race condition only occurs if
// a volume is being mounted at the same time as this filter is being loaded.
// This problem will never occur if this filter is loaded at boot time before
// any file systems are loaded.
//
// This lock is used to atomically test if we are already attached to a given
// device object and if not, do the attach.
//
FAST_MUTEX gSpyAttachLock;
//
// Macro for validating the FastIo dispatch routines before calling
// them in the FastIo pass through functions.
//
#define VALID_FAST_IO_DISPATCH_HANDLER(FastIoDispatchPtr, FieldName) \
(((FastIoDispatchPtr) != NULL) && \
(((FastIoDispatchPtr)->SizeOfFastIoDispatch) >= \
(FIELD_OFFSET(FAST_IO_DISPATCH, FieldName) + sizeof(VOID *))) && \
((FastIoDispatchPtr)->FieldName != NULL))
//
// list of known device types
//
const PCHAR DeviceTypeNames[] = {
"",
"BEEP",
"CD_ROM",
"CD_ROM_FILE_SYSTEM",
"CONTROLLER",
"DATALINK",
"DFS",
"DISK",
"DISK_FILE_SYSTEM",
"FILE_SYSTEM",
"INPORT_PORT",
"KEYBOARD",
"MAILSLOT",
"MIDI_IN",
"MIDI_OUT",
"MOUSE",
"MULTI_UNC_PROVIDER",
"NAMED_PIPE",
"NETWORK",
"NETWORK_BROWSER",
"NETWORK_FILE_SYSTEM",
"NULL",
"PARALLEL_PORT",
"PHYSICAL_NETCARD",
"PRINTER",
"SCANNER",
"SERIAL_MOUSE_PORT",
"SERIAL_PORT",
"SCREEN",
"SOUND",
"STREAMS",
"TAPE",
"TAPE_FILE_SYSTEM",
"TRANSPORT",
"UNKNOWN",
"VIDEO",
"VIRTUAL_DISK",
"WAVE_IN",
"WAVE_OUT",
"8042_PORT",
"NETWORK_REDIRECTOR",
"BATTERY",
"BUS_EXTENDER",
"MODEM",
"VDM",
"MASS_STORAGE",
"SMB",
"KS",
"CHANGER",
"SMARTCARD",
"ACPI",
"DVD",
"FULLSCREEN_VIDEO",
"DFS_FILE_SYSTEM",
"DFS_VOLUME",
"SERENUM",
"TERMSRV",
"KSEC"
};
//
// We need this because the compiler doesn't like doing sizeof an external
// array in the other file that needs it (fspylib.c)
//
ULONG SizeOfDeviceTypeNames = sizeof( DeviceTypeNames );
//
// Since functions in drivers are non-pageable 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).
//
#if DBG && WINVER >= 0x0501
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
);
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#if DBG && WINVER >= 0x0501
#pragma alloc_text(PAGE, DriverUnload)
#endif
#pragma alloc_text(PAGE, SpyFsNotification)
#pragma alloc_text(PAGE, SpyClose)
#pragma alloc_text(PAGE, SpyFsControl)
#pragma alloc_text(PAGE, SpyFsControlMountVolume)
#pragma alloc_text(PAGE, SpyFsControlMountVolumeComplete)
#pragma alloc_text(PAGE, SpyFsControlLoadFileSystem)
#pragma alloc_text(PAGE, SpyFsControlLoadFileSystemComplete)
#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, SpyFastIoMdlRead)
#pragma alloc_text(PAGE, SpyFastIoPrepareMdlWrite)
#pragma alloc_text(PAGE, SpyFastIoReadCompressed)
#pragma alloc_text(PAGE, SpyFastIoWriteCompressed)
#pragma alloc_text(PAGE, SpyFastIoQueryOpen)
#pragma alloc_text(PAGE, SpyCommonDeviceIoControl)
#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;
NTSTATUS status;
PFAST_IO_DISPATCH fastIoDispatch;
ULONG i;
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.
//
//////////////////////////////////////////////////////////////////////
#if WINVER >= 0x0501
//
// Try to load the dynamic functions that may be available for our use.
//
SpyLoadDynamicFunctions();
//
// Now get the current OS version that we will use to determine what logic
// paths to take when this driver is built to run on various OS version.
//
SpyGetCurrentVersion();
#endif
//
// Read the custom parameters for FileSpy from the registry
//
SpyReadDriverParameters( RegistryPath );
if (FlagOn(gFileSpyDebugLevel,SPYDEBUG_BREAK_ON_DRIVER_ENTRY)) {
DbgBreakPoint();
}
//
// Save our Driver Object.
//
gFileSpyDriverObject = DriverObject;
//
// Initialize the lookaside list for name buffering. This is used in
// several places to avoid having a large name buffer on the stack. It is
// also needed by the name lookup routines (NLxxx).
//
ExInitializePagedLookasideList( &gFileSpyNameBufferLookasideList,
NULL,
NULL,
0,
FILESPY_LOOKASIDE_SIZE,
FILESPY_NAME_BUFFER_TAG,
0 );
#if DBG && WINVER >= 0x0501
//
// MULTIVERSION NOTE:
//
// We can only support unload for testing environments if we can enumerate
// the outstanding device objects that our driver has.
//
//
// Unload is useful for development purposes. It is not recommended for
// production versions.
//
if (IS_WINDOWSXP_OR_LATER()) {
ASSERT( NULL != gSpyDynamicFunctions.EnumerateDeviceObjectList );
gFileSpyDriverObject->DriverUnload = DriverUnload;
}
#endif
//
// Create the device object that will represent the FileSpy device.
//
RtlInitUnicodeString( &nameString, FILESPY_FULLDEVICE_NAME1 );
//
// 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, // has no device extension
&nameString,
FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&gControlDeviceObject);
if (STATUS_OBJECT_PATH_NOT_FOUND == status) {
//
// The "\FileSystem\Filter' path does not exist in the object name
// space, so we must be dealing with an OS pre-Windows XP. Try
// the second name we have to see if we can create a device by that
// name.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -