📄 fspylib.c
字号:
RECORD_TYPE_EXCEED_MEMORY_ALLOWANCE) );
#ifdef MEMORY_DBG
ExFreePoolWithTag( newBuffer, FILESPY_LOGRECORD_TAG );
#else
ExFreeToNPagedLookasideList( &gFreeBufferList, newBuffer );
#endif
newBuffer = NULL;
}
}
} else {
SetFlag( newRecordType,
(RECORD_TYPE_STATIC | RECORD_TYPE_OUT_OF_MEMORY) );
}
if (RecordType) {
*RecordType = newRecordType;
}
return newBuffer;
}
VOID
SpyFreeBuffer (
IN PVOID Buffer,
IN PLONG Counter
)
/*++
Routine Description:
Returns a Buffer to the gFreeBufferList.
Arguments:
Buffer - the buffer to return to the gFreeBufferList
Return Value:
None.
--*/
{
#ifdef MEMORY_DBG
ExFreePoolWithTag( Buffer, FILESPY_LOGRECORD_TAG );
#else
ExFreeToNPagedLookasideList( &gFreeBufferList, Buffer );
#endif
//
// Update the count
//
if (Counter) {
InterlockedDecrement(Counter);
}
}
////////////////////////////////////////////////////////////////////////
// //
// Logging routines //
// //
////////////////////////////////////////////////////////////////////////
PRECORD_LIST
SpyNewRecord (
IN ULONG AssignedSequenceNumber
)
/*++
Routine Description:
Allocates a new RECORD_LIST structure if there is enough memory to do so. A
sequence number is updated for each request for a new record.
Arguments:
AssignedSequenceNumber - 0 if you want this function to generate the
next sequence number; if not 0, the new record is assigned the
given sequence number.
Return Value:
Pointer to the RECORD_LIST allocated, or NULL if no memory is available.
--*/
{
PRECORD_LIST newRecord = NULL;
ULONG currentSequenceNumber;
KIRQL irql;
ULONG initialRecordType;
newRecord = (PRECORD_LIST) SpyAllocateBuffer( &gRecordsAllocated,
gMaxRecordsToAllocate,
&initialRecordType);
KeAcquireSpinLock(&gLogSequenceLock, &irql);
//
// Assign a new sequence number if 0 was passed in, otherwise use the
// number passed in
//
if (AssignedSequenceNumber == 0) {
gLogSequenceNumber++;
currentSequenceNumber = gLogSequenceNumber;
} else {
currentSequenceNumber = AssignedSequenceNumber;
}
if ((newRecord == NULL) &&
!InterlockedCompareExchange( &gStaticBufferInUse, TRUE, FALSE)) {
//
// Toggle on our gStaticBufferInUse flag and use the static out of
// memory buffer to record this log entry. This special log record is
// used to notify the user application that we are out of memory. Log
// request will be dropped until we can get more memory.
//
newRecord = (PRECORD_LIST)gOutOfMemoryBuffer;
newRecord->LogRecord.RecordType = initialRecordType;
newRecord->LogRecord.Length = SIZE_OF_LOG_RECORD;
newRecord->LogRecord.SequenceNumber = currentSequenceNumber;
} else if (newRecord) {
//
// We were able to allocate a new record so initialize it
// appropriately.
//
newRecord->LogRecord.RecordType = initialRecordType;
newRecord->LogRecord.Length = SIZE_OF_LOG_RECORD;
newRecord->LogRecord.SequenceNumber = currentSequenceNumber;
}
KeReleaseSpinLock(&gLogSequenceLock, irql);
//
// Init record specific fields.
//
if (newRecord != NULL) {
newRecord->NewContext = NULL;
newRecord->WaitEvent = NULL;
newRecord->Flags = 0;
}
return( newRecord );
}
VOID
SpyFreeRecord (
IN PRECORD_LIST Record
)
/*++
Routine Description:
Frees a RECORD_LIST, which returns the memory to the gFreeBufferList
look-aside list and updates the gRecordsAllocated count.
Arguments:
Record - the record to free
Return Value:
None.
--*/
{
//
// If there is a context record defined, release it now
//
#if USE_STREAM_CONTEXTS
if (NULL != Record->NewContext) {
SpyReleaseContext( Record->NewContext );
}
#endif
if (FlagOn( Record->LogRecord.RecordType, RECORD_TYPE_STATIC )) {
//
// This is our static record, so reset our gStaticBufferInUse flag.
//
InterlockedExchange( &gStaticBufferInUse, FALSE );
} else {
//
// This isn't our static memory buffer, so free the dynamically
// allocated memory.
//
SpyFreeBuffer( Record, &gRecordsAllocated );
}
}
PRECORD_LIST
SpyLogFastIoStart (
IN FASTIO_TYPE FastIoType,
IN PDEVICE_OBJECT DeviceObject,
IN PFILE_OBJECT FileObject OPTIONAL,
IN PLARGE_INTEGER FileOffset OPTIONAL,
IN ULONG Length OPTIONAL,
IN BOOLEAN Wait OPTIONAL
)
/*++
Routine Description:
Creates the log record if possible and records the necessary Fast I/O
information at the beginning of the fast I/O operation in RecordList
according to LoggingFlags.
The optional arguments are not recorded for all Fast I/O types. If
the argument is not needed for a given Fast I/O type, the parameter
was ignored.
Arguments:
FastIoType - The type of fast I/O we are logging (REQUIRED)
DeviceObject - The device object for our filter. (REQUIRED)
FileObject - Pointer to the file object this operation is on (OPTIONAL)
FileOffset - Pointer to the file offset for this operation (OPTIONAL)
Length - Length of the data for this operation (OPTIONAL)
Wait - Whether or not this operation can wait for a result (OPTIONAL)
Return Value:
The RECORD_LIST structure created with the appropriate information
filled in. If a RECORD_LIST structure couldn't be allocated, NULL
is returned.
--*/
{
PRECORD_LIST pRecordList;
PRECORD_FASTIO pRecordFastIo;
PFILESPY_DEVICE_EXTENSION devExt;
//
// Try to get a new record
//
pRecordList = SpyNewRecord( 0 );
//
// If we didn't get a RECORD_LIST, exit and return NULL
//
if (pRecordList == NULL) {
return NULL;
}
//
// We got a RECORD_LIST, so now fill in the appropriate information
//
pRecordFastIo = &pRecordList->LogRecord.Record.RecordFastIo;
//
// Perform the necessary book keeping for the RECORD_LIST
//
SetFlag( pRecordList->LogRecord.RecordType, RECORD_TYPE_FASTIO );
//
// Set the RECORD_FASTIO fields that are set for all Fast I/O types
//
pRecordFastIo->Type = FastIoType;
KeQuerySystemTime( &pRecordFastIo->StartTime );
//
// Get process and thread information
//
pRecordFastIo->ProcessId = (ULONG_PTR) PsGetCurrentProcessId();
pRecordFastIo->ThreadId = (ULONG_PTR) PsGetCurrentThreadId();
//
// Record the information that is appropriate based on the
// Fast I/O type
//
pRecordFastIo->FileObject = (FILE_ID)FileObject;
pRecordFastIo->DeviceObject = (DEVICE_ID)DeviceObject;
pRecordFastIo->FileOffset.QuadPart = ((FileOffset != NULL) ? FileOffset->QuadPart : 0);
pRecordFastIo->Length = Length;
pRecordFastIo->Wait = Wait;
devExt = DeviceObject->DeviceExtension;
if (FastIoType == CHECK_IF_POSSIBLE) {
//
// On NTFS, locks are sometimes held but top-level IRP is not set,
// therefore it is not safe to query the base file system for the
// file name at this time. If we've got it in the cache, we'll
// use it. Otherwise, we will not return a name.
//
SpySetName( pRecordList,
DeviceObject,
FileObject,
NLFL_ONLY_CHECK_CACHE,
NULL );
} else {
SpySetName( pRecordList, DeviceObject, FileObject, 0, NULL );
}
return pRecordList;
}
VOID
SpyLogFastIoComplete (
IN PIO_STATUS_BLOCK ReturnStatus,
IN PRECORD_LIST RecordList
)
/*++
Routine Description:
Records the necessary Fast I/O information in RecordList according to
LoggingFlags.
The optional arguments are not recorded for all Fast I/O types. If
the argument is not needed for a given Fast I/O type, the parameter
was ignored.
Arguments:
ReturnStatus - The return value of the operation (OPTIONAL)
RecordList - The PRECORD_LIST in which the Fast I/O information is stored.
Return Value:
None.
--*/
{
PRECORD_FASTIO pRecordFastIo;
ASSERT(RecordList);
pRecordFastIo = &RecordList->LogRecord.Record.RecordFastIo;
//
// Set the RECORD_FASTIO fields that are set for all Fast I/O types
//
KeQuerySystemTime( &pRecordFastIo->CompletionTime );
if (ReturnStatus != NULL) {
pRecordFastIo->ReturnStatus = ReturnStatus->Status;
} else {
pRecordFastIo->ReturnStatus = 0;
}
SpyLog( RecordList );
}
#if WINVER >= 0x0501 /* See comment in DriverEntry */
VOID
SpyLogPreFsFilterOperation (
IN PFS_FILTER_CALLBACK_DATA Data,
OUT PRECORD_LIST RecordList
)
{
NAME_LOOKUP_FLAGS lookupFlags = 0;
PRECORD_FS_FILTER_OPERATION pRecordFsFilterOp;
pRecordFsFilterOp = &RecordList->LogRecord.Record.RecordFsFilterOp;
//
// Record the information we use for an originating Irp. We first
// need to initialize some of the RECORD_LIST and RECORD_IRP fields.
// Then get the interesting information from the Irp.
//
SetFlag( RecordList->LogRecord.RecordType, RECORD_TYPE_FS_FILTER_OP );
pRecordFsFilterOp->FsFilterOperation = Data->Operation;
pRecordFsFilterOp->FileObject = (FILE_ID) Data->FileObject;
pRecordFsFilterOp->DeviceObject = (FILE_ID) Data->DeviceObject;
pRecordFsFilterOp->ProcessId = (FILE_ID)PsGetCurrentProcessId();
pRecordFsFilterOp->ThreadId = (FILE_ID)PsGetCurrentThreadId();
KeQuerySystemTime( &pRecordFsFilterOp->OriginatingTime );
//
// Do not query for the name on any of the release operations
// because a file system resource is currently being held and
// we may deadlock.
//
switch (Data->Operation) {
case FS_FILTER_RELEASE_FOR_CC_FLUSH:
case FS_FILTER_RELEASE_FOR_SECTION_SYNCHRONIZATION:
case FS_FILTER_RELEASE_FOR_MOD_WRITE:
SPY_LOG_PRINT( SPYDEBUG_TRACE_DETAILED_CONTEXT_OPS,
("FileSpy!SpyLogPreFsFilterOp: RelOper\n") );
SetFlag( lookupFlags, NLFL_ONLY_CHECK_CACHE );
break;
}
//
// Only set the volumeName if the next device is a file system
// since we only want to prepend the volumeName if we are on
// top of a local file system.
//
SpySetName( RecordList,
Data->DeviceObject,
Data->FileObject,
lookupFlags,
NULL );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -