📄 minispy.c
字号:
if ((OutputBufferSize < sizeof( MINISPYVER )) ||
(OutputBuffer == NULL)) {
status = STATUS_INVALID_PARAMETER;
break;
}
//
// Validate Buffer alignment. If a minifilter cares about
// the alignment value of the buffer pointer they must do
// this check themselves. Note that a try/except will not
// capture alignment faults.
//
if (!IS_ALIGNED(OutputBuffer,sizeof(ULONG))) {
status = STATUS_DATATYPE_MISALIGNMENT;
break;
}
//
// Protect access to raw user-mode output buffer with an
// exception handler
//
try {
((PMINISPYVER)OutputBuffer)->Major = MINISPY_MAJ_VERSION;
((PMINISPYVER)OutputBuffer)->Minor = MINISPY_MIN_VERSION;
} except( EXCEPTION_EXECUTE_HANDLER ) {
return GetExceptionCode();
}
*ReturnOutputBufferLength = sizeof( MINISPYVER );
status = STATUS_SUCCESS;
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
} else {
status = STATUS_INVALID_PARAMETER;
}
return status;
}
//---------------------------------------------------------------------------
// Operation filtering routines
//---------------------------------------------------------------------------
FLT_PREOP_CALLBACK_STATUS
SpyPreOperationCallback (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
)
/*++
Routine Description:
This routine receives ALL pre-operation callbacks for this filter. It then
tries to log information about the given operation. If we are able
to log information then we will call our post-operation callback routine.
NOTE: This routine must be NON-PAGED because it can be called on the
paging path.
Arguments:
Data - Contains information about the given operation.
FltObjects - Contains pointers to the various objects that are pertinent
to this operation.
CompletionContext - This receives the address of our log buffer for this
operation. Our completion routine then receives this buffer address.
Return Value:
Identifies how processing should continue for this operation
--*/
{
FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; //assume we are NOT going to call our completion routine
PRECORD_LIST recordList;
PFLT_FILE_NAME_INFORMATION nameInfo = NULL;
UNICODE_STRING defaultName;
PUNICODE_STRING nameToUse;
NTSTATUS status;
//
// Try and get a log record
//
recordList = SpyNewRecord();
if (recordList) {
//
// We got a log record, if there is a file object, get its name.
//
// NOTE: By default, we use the query method
// FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP
// because MiniSpy would like to get the name as much as possible, but
// can cope if we can't retrieve a name. For a debugging type filter,
// like Minispy, this is reasonable, but for most production filters
// who need names reliably, they should query the name at times when it
// is known to be safe and use the query method
// FLT_FILE_NAME_QUERY_DEFAULT.
//
if (FltObjects->FileObject != NULL) {
status = FltGetFileNameInformation( Data,
FLT_FILE_NAME_NORMALIZED |
MiniSpyData.NameQueryMethod,
&nameInfo );
} else {
//
// Can't get a name when there's no file object
//
status = STATUS_UNSUCCESSFUL;
}
//
// Use the name if we got it else use a default name
//
if (NT_SUCCESS( status )) {
nameToUse = &nameInfo->Name;
//
// Parse the name if requested
//
if (FlagOn( MiniSpyData.DebugFlags, SPY_DEBUG_PARSE_NAMES )) {
status = FltParseFileNameInformation( nameInfo );
ASSERT(NT_SUCCESS(status));
}
} else {
RtlInitUnicodeString( &defaultName, L"<NO NAME>" );
nameToUse = &defaultName;
}
//
// Store the name
//
SpySetRecordName( &(recordList->LogRecord), nameToUse );
//
// Release the name information structure (if defined)
//
if (NULL != nameInfo) {
FltReleaseFileNameInformation( nameInfo );
}
//
// Set all of the operation information into the record
//
SpyLogPreOperationData( Data, FltObjects, recordList );
//
// Pass the record to our completions routine and return that
// we want our completion routine called.
//
if (Data->Iopb->MajorFunction == IRP_MJ_SHUTDOWN) {
//
// Since completion callbacks are not supported for
// this operation, do the completion processing now
//
SpyPostOperationCallback( Data,
FltObjects,
recordList,
0 );
returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
} else {
*CompletionContext = recordList;
returnStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;
}
}
return returnStatus;
}
FLT_POSTOP_CALLBACK_STATUS
SpyPostOperationCallback (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
)
/*++
Routine Description:
This routine receives ALL post-operation callbacks. This will take
the log record passed in the context parameter and update it with
the completion information. It will then insert it on a list to be
sent to the usermode component.
NOTE: This routine must be NON-PAGED because it can be called at DPC level
Arguments:
Data - Contains information about the given operation.
FltObjects - Contains pointers to the various objects that are pertinent
to this operation.
CompletionContext - Pointer to the RECORD_LIST structure in which we
store the information we are logging. This was passed from the
pre-operation callback
Flags - Contains information as to why this routine was called.
Return Value:
Identifies how processing should continue for this operation
--*/
{
PRECORD_LIST recordList;
PRECORD_LIST reparseRecordList = NULL;
PLOG_RECORD reparseLogRecord;
PFLT_TAG_DATA_BUFFER tagData;
ULONG copyLength;
UNREFERENCED_PARAMETER( FltObjects );
recordList = (PRECORD_LIST)CompletionContext;
//
// If our instance is in the process of being torn down don't bother to
// log this record, free it now.
//
if (FlagOn(Flags,FLTFL_POST_OPERATION_DRAINING)) {
SpyFreeRecord( recordList );
return FLT_POSTOP_FINISHED_PROCESSING;
}
//
// Set completion information into the record
//
SpyLogPostOperationData( Data, recordList );
//
// Log reparse tag information if specified.
//
if (tagData = Data->TagData) {
reparseRecordList = SpyNewRecord();
if (reparseRecordList) {
//
// only copy the DATA portion of the information
//
RtlCopyMemory( &reparseRecordList->LogRecord.Data,
&recordList->LogRecord.Data,
sizeof(RECORD_DATA) );
reparseLogRecord = &reparseRecordList->LogRecord;
copyLength = FLT_TAG_DATA_BUFFER_HEADER_SIZE + tagData->TagDataLength;
if(copyLength > MAX_NAME_SPACE) {
copyLength = MAX_NAME_SPACE;
}
//
// Copy reparse data
//
RtlCopyMemory(
&reparseRecordList->LogRecord.Name[0],
tagData,
copyLength
);
reparseLogRecord->RecordType |= RECORD_TYPE_FILETAG;
reparseLogRecord->Length += (ULONG) ROUND_TO_SIZE( copyLength, sizeof( PVOID ) );
}
}
//
// Send the logged information to the user service.
//
SpyLog( recordList );
if (reparseRecordList) {
SpyLog( reparseRecordList );
}
//
// For creates within a transaction enlist in the transaction
// if we haven't already done.
//
if ((FltObjects->Transaction != NULL) &&
(Data->Iopb->MajorFunction == IRP_MJ_CREATE) &&
(Data->IoStatus.Status == STATUS_SUCCESS)) {
//
// Enlist in the transaction.
//
SpyEnlistInTransaction( FltObjects );
}
return FLT_POSTOP_FINISHED_PROCESSING;
}
NTSTATUS
SpyEnlistInTransaction (
__in PCFLT_RELATED_OBJECTS FltObjects
)
{
#if MINISPY_LONGHORN
PFLT_CONTEXT transactionContext;
PRECORD_LIST recordList;
NTSTATUS status;
//
// This code is only built in the Longhorn environment, but
// we need to ensure this binary still runs down-level. Return
// at this point if the transaction dynamic imports were not found.
//
// If we find FltGetTransactionContext, we assume the other
// transaction APIs are also present.
//
if (NULL == MiniSpyData.PFltGetTransactionContext) {
return STATUS_SUCCESS;
}
//
// Try to get our context for this transaction. If we get
// one we have already enlisted in this transaction.
//
status = (*MiniSpyData.PFltGetTransactionContext)( FltObjects->Instance,
FltObjects->Transaction,
&transactionContext );
if (NT_SUCCESS( status )) {
FltReleaseContext( transactionContext );
return STATUS_SUCCESS;
}
//
// If the context does not exist create a new one, else return the error
// status to the caller.
//
if (status != STATUS_NOT_FOUND) {
return status;
}
//
// Allocate a transaction context.
//
status = FltAllocateContext( FltObjects->Filter,
FLT_TRANSACTION_CONTEXT,
0,
PagedPool,
&transactionContext );
if (!NT_SUCCESS( status )) {
return status;
}
//
// Set the context into the transaction
//
ASSERT( MiniSpyData.PFltSetTransactionContext );
status = (*MiniSpyData.PFltSetTransactionContext)( FltObjects->Instance,
FltObjects->Transaction,
FLT_SET_CONTEXT_KEEP_IF_EXISTS,
transactionContext,
NULL );
if (!NT_SUCCESS( status )) {
FltReleaseContext( transactionContext ); //this will free the context
return status;
}
//
// Enlist on this transaction for notifications.
//
ASSERT( MiniSpyData.PFltEnlistInTransaction );
status = (*MiniSpyData.PFltEnlistInTransaction)( FltObjects->Instance,
FltObjects->Transaction,
transactionContext,
FLT_MAX_TRANSACTION_NOTIFICATIONS );
//
// If the enlistment failed we need to delete the context and remove
// our count
//
if (!NT_SUCCESS( status )) {
FltDeleteContext( transactionContext );
FltReleaseContext( transactionContext );
return status;
}
//
// The operation succeeded, remove our count
//
FltReleaseContext( transactionContext );
//
// Log a record that a new transaction has started.
//
recordList = SpyNewRecord();
if (recordList) {
SpyLogTransactionNofity( FltObjects, recordList, 0 );
//
// Send the logged information to the user service.
//
SpyLog( recordList );
}
#endif // MINISPY_LONGHORN
return STATUS_SUCCESS;
}
#if MINISPY_LONGHORN
NTSTATUS
SpyKtmNotificationCallback (
__in PCFLT_RELATED_OBJECTS FltObjects,
__in PFLT_CONTEXT TransactionContext,
__in ULONG TransactionNotification
)
{
PRECORD_LIST recordList;
//
// Try and get a log record
//
recordList = SpyNewRecord();
if (recordList) {
SpyLogTransactionNofity( FltObjects, recordList, TransactionNotification );
//
// Send the logged information to the user service.
//
SpyLog( recordList );
}
return STATUS_SUCCESS;
}
#endif // MINISPY_LONGHORN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -