📄 fspylib.c
字号:
/*++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
fspyLib.c
Abstract:
This contains library support routines for FileSpy. These routines
do the main work for logging the I/O operations --- creating the log
records, recording the relevant information, attach/detach from
devices, etc.
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
--*/
#ifndef _WIN2K_COMPAT_SLIST_USAGE
#define _WIN2K_COMPAT_SLIST_USAGE
#endif
#include <stdio.h>
#include <ntifs.h>
#include "filespy.h"
#include "fspyKern.h"
#include "namelookup.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, SpyReadDriverParameters)
#pragma alloc_text(PAGE, SpyAttachDeviceToDeviceStack)
#pragma alloc_text(PAGE, SpyQueryInformationFile)
#pragma alloc_text(PAGE, SpyIsAttachedToDeviceByName)
#pragma alloc_text(PAGE, SpyIsAttachedToDevice)
#pragma alloc_text(PAGE, SpyIsAttachedToDeviceW2K)
#pragma alloc_text(PAGE, SpyAttachToMountedDevice)
#pragma alloc_text(PAGE, SpyCleanupMountedDevice)
#pragma alloc_text(PAGE, SpyAttachToDeviceOnDemand)
#pragma alloc_text(PAGE, SpyAttachToDeviceOnDemandW2K)
#pragma alloc_text(PAGE, SpyStartLoggingDevice)
#pragma alloc_text(PAGE, SpyStopLoggingDevice)
#pragma alloc_text(PAGE, SpyAttachToFileSystemDevice)
#pragma alloc_text(PAGE, SpyDetachFromFileSystemDevice)
#pragma alloc_text(PAGE, SpyGetAttachList)
#if WINVER >= 0x0501
#pragma alloc_text(INIT, SpyLoadDynamicFunctions)
#pragma alloc_text(INIT, SpyGetCurrentVersion)
#pragma alloc_text(PAGE, SpyIsAttachedToDeviceWXPAndLater)
#pragma alloc_text(PAGE, SpyAttachToDeviceOnDemandWXPAndLater)
#pragma alloc_text(PAGE, SpyEnumerateFileSystemVolumes)
#pragma alloc_text(PAGE, SpyGetBaseDeviceObjectName)
#endif
#endif
//////////////////////////////////////////////////////////////////////////
// //
// Library support routines //
// //
//////////////////////////////////////////////////////////////////////////
VOID
SpyReadDriverParameters (
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine tries to read the FileSpy-specific parameters from
the registry. These values will be found in the registry location
indicated by the RegistryPath passed in.
Arguments:
RegistryPath - the path key which contains the values that are
the FileSpy parameters
Return Value:
None.
--*/
{
OBJECT_ATTRIBUTES attributes;
HANDLE driverRegKey;
NTSTATUS status;
ULONG bufferSize, resultLength;
PVOID buffer = NULL;
UNICODE_STRING valueName;
PKEY_VALUE_PARTIAL_INFORMATION pValuePartialInfo;
PAGED_CODE();
//
// All the global values are already set to default values. Any
// values we read from the registry will override these defaults.
//
//
// Do the initial setup to start reading from the registry.
//
InitializeObjectAttributes( &attributes,
RegistryPath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
status = ZwOpenKey( &driverRegKey,
KEY_READ,
&attributes);
if (!NT_SUCCESS(status)) {
driverRegKey = NULL;
goto SpyReadDriverParameters_Exit;
}
bufferSize = sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + sizeof( ULONG );
buffer = ExAllocatePoolWithTag( NonPagedPool,
bufferSize,
FILESPY_POOL_TAG );
if (NULL == buffer) {
goto SpyReadDriverParameters_Exit;
}
//
// Read the gMaxRecordsToAllocate from the registry
//
RtlInitUnicodeString(&valueName, MAX_RECORDS_TO_ALLOCATE);
status = ZwQueryValueKey( driverRegKey,
&valueName,
KeyValuePartialInformation,
buffer,
bufferSize,
&resultLength);
if (NT_SUCCESS(status)) {
pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
ASSERT(pValuePartialInfo->Type == REG_DWORD);
gMaxRecordsToAllocate = *((PLONG)&pValuePartialInfo->Data);
}
//
// Read the gMaxNamesToAllocate from the registry
//
RtlInitUnicodeString(&valueName, MAX_NAMES_TO_ALLOCATE);
status = ZwQueryValueKey( driverRegKey,
&valueName,
KeyValuePartialInformation,
buffer,
bufferSize,
&resultLength);
if (NT_SUCCESS(status)) {
pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
ASSERT(pValuePartialInfo->Type == REG_DWORD);
gMaxNamesToAllocate = *((PLONG)&pValuePartialInfo->Data);
}
//
// Read the initial debug setting from the registry
//
RtlInitUnicodeString(&valueName, DEBUG_LEVEL);
status = ZwQueryValueKey( driverRegKey,
&valueName,
KeyValuePartialInformation,
buffer,
bufferSize,
&resultLength );
if (NT_SUCCESS( status )) {
pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
ASSERT( pValuePartialInfo->Type == REG_DWORD );
gFileSpyDebugLevel |= *((PULONG)&pValuePartialInfo->Data);
}
//
// Read the attachment mode setting from the registry
//
RtlInitUnicodeString(&valueName, ATTACH_MODE);
status = ZwQueryValueKey( driverRegKey,
&valueName,
KeyValuePartialInformation,
buffer,
bufferSize,
&resultLength );
if (NT_SUCCESS( status )) {
pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
ASSERT( pValuePartialInfo->Type == REG_DWORD );
gFileSpyAttachMode = *((PULONG)&pValuePartialInfo->Data);
}
goto SpyReadDriverParameters_Exit;
SpyReadDriverParameters_Exit:
if (NULL != buffer) {
ExFreePoolWithTag( buffer, FILESPY_POOL_TAG );
}
if (NULL != driverRegKey) {
ZwClose(driverRegKey);
}
return;
}
#if WINVER >= 0x0501
VOID
SpyLoadDynamicFunctions (
VOID
)
/*++
Routine Description:
This routine tries to load the function pointers for the routines that
are not supported on all versions of the OS. These function pointers are
then stored in the global structure gSpyDynamicFunctions.
This support allows for one driver to be built that will run on all
versions of the OS Windows 2000 and greater. Note that on Windows 2000,
the functionality may be limited.
Arguments:
None.
Return Value:
None.
--*/
{
UNICODE_STRING functionName;
RtlZeroMemory( &gSpyDynamicFunctions, sizeof( gSpyDynamicFunctions ) );
//
// For each routine that we would want to use, lookup its address in the
// kernel or HAL. If it is not present, that field in our global
// gSpyDynamicFunctions structure will be set to NULL.
//
RtlInitUnicodeString( &functionName, L"FsRtlRegisterFileSystemFilterCallbacks" );
gSpyDynamicFunctions.RegisterFileSystemFilterCallbacks = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoAttachDeviceToDeviceStackSafe" );
gSpyDynamicFunctions.AttachDeviceToDeviceStackSafe = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoEnumerateDeviceObjectList" );
gSpyDynamicFunctions.EnumerateDeviceObjectList = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetLowerDeviceObject" );
gSpyDynamicFunctions.GetLowerDeviceObject = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetDeviceAttachmentBaseRef" );
gSpyDynamicFunctions.GetDeviceAttachmentBaseRef = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetDiskDeviceObject" );
gSpyDynamicFunctions.GetStorageStackDeviceObject = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"IoGetAttachedDeviceReference" );
gSpyDynamicFunctions.GetAttachedDeviceReference = MmGetSystemRoutineAddress( &functionName );
RtlInitUnicodeString( &functionName, L"RtlGetVersion" );
gSpyDynamicFunctions.GetVersion = MmGetSystemRoutineAddress( &functionName );
}
VOID
SpyGetCurrentVersion (
VOID
)
/*++
Routine Description:
This routine reads the current OS version using the correct routine based
on what routine is available.
Arguments:
None.
Return Value:
None.
--*/
{
if (NULL != gSpyDynamicFunctions.GetVersion) {
RTL_OSVERSIONINFOW versionInfo;
NTSTATUS status;
//
// VERSION NOTE: RtlGetVersion does a bit more than we need, but
// we are using it if it is available to show how to use it. It
// is available on Windows XP and later. RtlGetVersion and
// RtlVerifyVersionInfo (both documented in the IFS Kit docs) allow
// you to make correct choices when you need to change logic based
// on the current OS executing your code.
//
versionInfo.dwOSVersionInfoSize = sizeof( RTL_OSVERSIONINFOW );
status = (gSpyDynamicFunctions.GetVersion)( &versionInfo );
ASSERT( NT_SUCCESS( status ) );
gSpyOsMajorVersion = versionInfo.dwMajorVersion;
gSpyOsMinorVersion = versionInfo.dwMinorVersion;
} else {
PsGetVersion( &gSpyOsMajorVersion,
&gSpyOsMinorVersion,
NULL,
NULL );
}
}
#endif
////////////////////////////////////////////////////////////////////////
// //
// Memory allocation routines //
// //
////////////////////////////////////////////////////////////////////////
PVOID
SpyAllocateBuffer (
IN OUT PLONG Counter,
IN LONG MaxCounterValue,
OUT PULONG RecordType
)
/*++
Routine Description:
Allocates a new buffer from the gFreeBufferList if there is enough memory
to do so and Counter does not exceed MaxCounterValue. The RecordType
is set to one of the record type constants based on the allocation state.
Arguments:
Counter - (optional) the counter variable to test and increment if
we can allocate
MaxCounterValue - (ignored if Counter not given) the value which
Counter should not exceed
RecordType - (optional) set to one of the following:
RECORD_TYPE_NORMAL allocation succeeded
RECORD_TYPE_OUT_OF_MEMORY allocation failed because the system was
out of memory
RECORD_TYPE_EXCEED_MEMORY_ALLOWANCE allocation failed because the
counter exceeded its maximum value.
Return Value:
Pointer to the buffer allocate, or NULL if allocation failed (either
because system is out of memory or we have exceeded the MaxCounterValue).
--*/
{
PVOID newBuffer;
ULONG newRecordType = RECORD_TYPE_NORMAL;
#ifdef MEMORY_DBG
//
// When we are debugging the memory usage to make sure that we
// don't leak memory, we want to allocate the memory from pool
// so that we can use the Driver Verifier to help debug any
// memory problems.
//
newBuffer = ExAllocatePoolWithTag( NonPagedPool,
RECORD_SIZE,
FILESPY_LOGRECORD_TAG );
#else
//
// When we are not debugging the memory usage, we use a look-aside
// list for better performance.
//
newBuffer = ExAllocateFromNPagedLookasideList( &gFreeBufferList );
#endif
if (newBuffer) {
if (Counter) {
if (*Counter < MaxCounterValue) {
InterlockedIncrement(Counter);
} else {
//
// We've exceed our driver's memory limit so note that
// and give back the record
//
SetFlag( newRecordType,
(RECORD_TYPE_STATIC |
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -