NTSTATUS UcaGetFileNameInformation(_In_ PFLT_CALLBACK_DATA Data, _Out_ PFLT_FILE_NAME_INFORMATION *FileNameInformation) { NTSTATUS Status; /* Get the file name info */ Status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, FileNameInformation); if (!NT_SUCCESS(Status)) { /* If we failed to get the normalized, the opened should succeed */ Status = FltGetFileNameInformation(Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, FileNameInformation); } /* Exit if we failed to get a filename */ if (!NT_SUCCESS(Status)) return Status; /* Fill in the rest of the structure */ Status = FltParseFileNameInformation(*FileNameInformation); if (!NT_SUCCESS(Status)) { FltReleaseFileNameInformation(*FileNameInformation); } return Status; }
NTSTATUS GetDirectoryName(PFLT_CALLBACK_DATA Data, PUNICODE_STRING directoryName) { PFLT_FILE_NAME_INFORMATION nameInfo; NTSTATUS status = FltGetFileNameInformation(Data, (FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT), &nameInfo); if (NT_SUCCESS(status)) { status = FltParseFileNameInformation(nameInfo); if (NT_SUCCESS(status)) { directoryName->Length = 0; directoryName->Buffer = (WCHAR*)ExAllocatePoolWithTag(PagedPool, nameInfo->Name.Length * sizeof(WCHAR), UNICODE_STRING_TAG); directoryName->MaximumLength = nameInfo->Name.Length; status = RtlUnicodeStringCopy(directoryName, &nameInfo->Name); } } if (nameInfo != NULL) { FltReleaseFileNameInformation(nameInfo); } return status; }
//--------------------------------------------------------------- FLT_PREOP_CALLBACK_STATUS FltPreCreate(IN OUT PFLT_CALLBACK_DATA Data, IN PCFLT_RELATED_OBJECTS FltObjects, OUT PVOID *CompletionContext) { char tProcessName[512] = {0}; PEPROCESS tCurProc = PsGetCurrentProcess(); char* tNamePtr = (char*)tCurProc + ProcessNameOffset; memcpy(tProcessName, tNamePtr, 15); tProcessName[15] = 0; KdPrint(("process name:%s\n",tProcessName)); NTSTATUS tRetStatus; char FileName[512] = {0}; PFLT_FILE_NAME_INFORMATION tNameInfo; PAGED_CODE(); tRetStatus = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &tNameInfo); if(NT_SUCCESS(tRetStatus)) { FltParseFileNameInformation(tNameInfo); KdPrint(("<Pre> file name: %wZ\n", &(tNameInfo->Name))); FltReleaseFileNameInformation(tNameInfo); } // return FLT_PREOP_COMPLETE; return FLT_PREOP_SUCCESS_WITH_CALLBACK; }
static FLT_PREOP_CALLBACK_STATUS on_pre_op (PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS fltobj, PVOID *context) { struct event *event; if (ESCAPE_CONDITION) return FLT_PREOP_SUCCESS_NO_CALLBACK; event = event_buffer_start_add(); if (event == NULL) return FLT_PREOP_SUCCESS_NO_CALLBACK; /* We retrieve name information in "pre" for every operation except IRP_MJ_CREATE. * For IRP_MJ_CREATE, we do it in post. */ if (data->Iopb->MajorFunction != IRP_MJ_CREATE) { FLT_FILE_NAME_INFORMATION *name_info = NULL; if (FltGetFileNameInformation(data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &name_info) != STATUS_SUCCESS) { event_buffer_cancel_add(event); return FLT_PREOP_SUCCESS_NO_CALLBACK; } event->path_length = MAX_PATH_SIZE - 1 < name_info->Name.Length / 2 ? MAX_PATH_SIZE - 1 : name_info->Name.Length / 2; RtlCopyMemory(event->path, name_info->Name.Buffer, event->path_length * 2); event->path[event->path_length] = 0; FltReleaseFileNameInformation(name_info); } event->time_pre = get_timestamp(); *context = event; return FLT_PREOP_SUCCESS_WITH_CALLBACK; }
FLT_PREOP_CALLBACK_STATUS PRE_MJ_CREATE(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext) { NTSTATUS status; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); if (!NT_SUCCESS(status)) { status = FltGetFileNameInformationUnsafe(FltObjects->FileObject, FltObjects->Instance, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); } if (nameInfo) { // block access if (wcsstr(nameInfo->Name.Buffer, L"your_file.exe") != NULL) { Data->IoStatus.Status = STATUS_NO_SUCH_FILE; Data->IoStatus.Information = 0; return FLT_PREOP_COMPLETE; } FltReleaseFileNameInformation(nameInfo); } return FLT_PREOP_SUCCESS_NO_CALLBACK; }
FLT_PREOP_CALLBACK_STATUS FLTAPI DenyCreateFileRoutine( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { NTSTATUS nsStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; PFLT_FILE_NAME_INFORMATION pFileName = NULL; UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(CompletionContext); if ( Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION && Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileRenameInformation) { if (((FILE_RENAME_INFORMATION*)Data->Iopb->Parameters.SetFileInformation.InfoBuffer)->FileName != NULL) { UNICODE_STRING uszFileNtPath = {0x00}; PUNICODE_STRING puszStoreFilePath = NULL; uszFileNtPath.Buffer = ((FILE_RENAME_INFORMATION*)Data->Iopb->Parameters.SetFileInformation.InfoBuffer)->FileName; uszFileNtPath.Length = (USHORT)((FILE_RENAME_INFORMATION*)Data->Iopb->Parameters.SetFileInformation.InfoBuffer)->FileNameLength; uszFileNtPath.MaximumLength = uszFileNtPath.Length; nsStatus = BDKitVolumeNameToDosName (&uszFileNtPath, &puszStoreFilePath); if ( NT_SUCCESS(nsStatus) && BDKitFindListNodeWithHandler (g_DenyFileHashList, puszStoreFilePath, findDenyFilePath) != NULL && !NT_SUCCESS(BDKitIsAuthorizedProcess(PsGetCurrentProcess()))) { Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; nsStatus = FLT_PREOP_COMPLETE; } BDKitFreePool(puszStoreFilePath); } } else if ( Data->Iopb->MajorFunction == IRP_MJ_CREATE ) { do { nsStatus = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED, &pFileName); BDKit_If_Not_Break(NT_SUCCESS(nsStatus)); if ( BDKitFindListNodeWithHandler(g_DenyFileHashList, &pFileName->Name, findDenyFilePath) != NULL ) { Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; nsStatus = FLT_PREOP_COMPLETE; } } while (FALSE); BDKit_If_DoAction(pFileName != NULL, FltReleaseFileNameInformation (pFileName)); } else if ( Data->Iopb->MajorFunction == IRP_MJ_UNREGISTER) { BDKitCloseListHandleWithHandler (g_DenyFileHashList, freeDenyListNode); g_DenyFileHashList = NULL; } return nsStatus; }
FLT_PREOP_CALLBACK_STATUS precreate(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext) { UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(CompletionContext); PFLT_FILE_NAME_INFORMATION info; PAGED_CODE(); __try{ FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &info); FltParseFileNameInformation(info); DbgPrint("检测到目标打开文件:%wZ\n", info->Name); FltReleaseFileNameInformation(info); } __except (EXCEPTION_EXECUTE_HANDLER) { DbgPrint("error cant execute the try\n"); } return FLT_PREOP_SUCCESS_WITH_CALLBACK; }
//--------------------------------------------------------------- FLT_POSTOP_CALLBACK_STATUS FltPostCreate( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags ) { NTSTATUS tRetStatus; char FileName[512] = {0}; PFLT_FILE_NAME_INFORMATION tNameInfo; PAGED_CODE(); tRetStatus = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &tNameInfo); if(NT_SUCCESS(tRetStatus)) { FltParseFileNameInformation(tNameInfo); KdPrint(("<post> file name: %wZ\n", &(tNameInfo->Name))); FltReleaseFileNameInformation(tNameInfo); } return FLT_POSTOP_FINISHED_PROCESSING; }
FLT_PREOP_CALLBACK_STATUS NPPreCreate ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { NTSTATUS status; PFLT_FILE_NAME_INFORMATION nameInfo; ANSI_STRING ansiStr; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); PAGED_CODE(); __try { status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); if ( !NT_SUCCESS( status ) ) leave; status = FltParseFileNameInformation( nameInfo ); if ( !NT_SUCCESS( status ) ) leave; RtlUnicodeStringToAnsiString(&ansiStr, &nameInfo->Name, TRUE); PT_DBG_PRINT( PTDBG_TRACE_OPERATION_STATUS, ("minifilter0!NPPretCreate: create [%Z]\n", &ansiStr) ); RtlFreeAnsiString( &ansiStr ); FltReleaseFileNameInformation( nameInfo ); } __except(EXCEPTION_EXECUTE_HANDLER) { DbgPrint("NPPreCreate EXCEPTION_EXECUTE_HANDLER\n"); } return FLT_PREOP_SUCCESS_WITH_CALLBACK; }
static FLT_PREOP_CALLBACK_STATUS FileSetInfoFilterPreCallback ( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID *CompletionContext ) { FLT_PREOP_CALLBACK_STATUS status = FLT_PREOP_SUCCESS_NO_CALLBACK; PFLT_FILE_NAME_INFORMATION fileInfoSrc = NULL; UNREFERENCED_PARAMETER( Data ); UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); if( FileRenameInformation == Data->Iopb->Parameters.SetFileInformation.FileInformationClass ) { // For a move, we keep the original path before the move if( NT_SUCCESS( FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &fileInfoSrc ) ) ) { status = FLT_PREOP_SYNCHRONIZE; *CompletionContext = fileInfoSrc; } } else if( FileDispositionInformation == Data->Iopb->Parameters.SetFileInformation.FileInformationClass || FileDispositionInformationEx == Data->Iopb->Parameters.SetFileInformation.FileInformationClass ) { status = FLT_PREOP_SYNCHRONIZE; } return status; }
FLT_PREOP_CALLBACK_STATUS FLTAPI FilterPreCreate( FLT_CALLBACK_DATA* Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext ) { NTSTATUS status; FLT_FILE_NAME_INFORMATION *nameInformation; UNICODE_STRING *fullPath; status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInformation ); if (status == STATUS_SUCCESS) { status = FltParseFileNameInformation(nameInformation); if (status == STATUS_SUCCESS) { FLT_FILE_LIST_ENTRY *file = FltFileList; fullPath = &nameInformation->Name; if ((Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess & FILE_EXECUTE) //Execute && (nameInformation->FinalComponent.Length == 16 //d3d8.dll/d3d9.dll || nameInformation->FinalComponent.Length == 18)) //d3d10.dll/d3d11.dll { if (wcsncmp(L"d3d8.dll", nameInformation->FinalComponent.Buffer, 8) == 0 || wcsncmp(L"d3d9.dll", nameInformation->FinalComponent.Buffer, 8) == 0 || wcsncmp(L"d3d10.dll", nameInformation->FinalComponent.Buffer, 9) == 0 || wcsncmp(L"d3d11.dll", nameInformation->FinalComponent.Buffer, 9) == 0) { PROCESSID processId; DEVICE_EXTENSION *deviceExtension; processId = FltGetRequestorProcessId(Data); deviceExtension = g_DeviceObject->DeviceExtension; deviceExtension->imageEvent.processID = processId; KeSetEvent(PushGpuAccelerationEvent, 0, FALSE); KeClearEvent(PushGpuAccelerationEvent); DbgPrint("[PUSH] %u loaded %wZ\n", processId, fullPath); } } while (file != 0) { if (fullPath->Length == file->NameLength && wcsncmp(file->Name, fullPath->Buffer, file->NameLength / sizeof(WCHAR)) == 0) { UNICODE_STRING newName; UNICODE_STRING redirect; UNICODE_STRING *currentName; UINT16 newNameSize; WCHAR *buffer; //DbgPrint("[PUSH] %ws matches %wZ", file->Name, fullPath); RtlInitUnicodeString(&newName, PUSH_RAMDISK_DEVICE_NAME L"\\"); // Calculate the size of the name newNameSize = newName.Length + nameInformation->FinalComponent.Length; redirect.Length = newName.Length; redirect.MaximumLength = newNameSize; redirect.Buffer = ExAllocatePool(NonPagedPool, newNameSize); // Copy ramdisk device name into buffer RtlCopyMemory(redirect.Buffer, newName.Buffer, newName.Length); // Append original file name //RtlAppendUnicodeStringToString(&redirect, &nameInformation->FinalComponent); buffer = &redirect.Buffer[redirect.Length / sizeof(WCHAR)]; RtlMoveMemory( buffer, nameInformation->FinalComponent.Buffer, nameInformation->FinalComponent.Length ); redirect.Length += nameInformation->FinalComponent.Length; currentName = &Data->Iopb->TargetFileObject->FileName; // Throw away the current file name ExFreePool(currentName->Buffer); currentName->Length = 0; currentName->MaximumLength = redirect.MaximumLength; currentName->Buffer = ExAllocatePool(NonPagedPool, redirect.MaximumLength); // Copy new path to buffer RtlCopyUnicodeString(currentName, &redirect); // Be nice and give back what was given to us ExFreePool(redirect.Buffer); Data->IoStatus.Information = IO_REPARSE; Data->IoStatus.Status = STATUS_REPARSE; Data->Iopb->TargetFileObject->RelatedFileObject = NULL; FltSetCallbackDataDirty(Data); return FLT_PREOP_COMPLETE; } file = file->NextEntry; } } } return FLT_PREOP_SUCCESS_NO_CALLBACK; }
FLT_PREOP_CALLBACK_STATUS FilemonPreCreate (__inout PFLT_CALLBACK_DATA Data , __in PCFLT_RELATED_OBJECTS FltObjects , __deref_out_opt PVOID *CompletionContext) { PFLT_FILE_NAME_INFORMATION nameInfo; NTSTATUS status; LONG nType; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); PAGED_CODE(); if (FALSE == IsGuardStart()) { KdPrint(( "!!! scanner.sys -- allowing create for trusted process \n" )); return FLT_PREOP_SUCCESS_NO_CALLBACK; } if (!NT_SUCCESS( Data->IoStatus.Status ) || (STATUS_REPARSE == Data->IoStatus.Status)) { KdPrint(("[ScannerPreCreate] Data->IoStatus.Status:%d.\n", Data->IoStatus.Status)); return FLT_PREOP_SUCCESS_NO_CALLBACK; } status = FltGetFileNameInformation(Data , FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT , &nameInfo); if (!NT_SUCCESS( status )) return FLT_POSTOP_FINISHED_PROCESSING; FltParseFileNameInformation( nameInfo ); KdPrint(("[ScannerPreCreate] monitoer:%wZ \n", &nameInfo->Name)); if(IsFilemonGuardPath(nameInfo->Name.Buffer , FlagOn(FILE_DIRECTORY_FILE, Data->Iopb->Parameters.Create.Options) > 0 , &nType)) { WCHAR szPath[MAX_PATH] = {0}; wcsncpy(szPath, nameInfo->Name.Buffer, min(MAX_PATH-1, nameInfo->Name.Length)); FltReleaseFileNameInformation( nameInfo ); // 获取通过与否 if(FALSE != CheckRequestIsAllowed(MAKEGUARDTYPE(MASK_GUARDLITE_FILEMON, nType) , szPath , L"" , L"")) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } // 未通过 if(FlagOn( (FILE_CREATE<<24), Data->Iopb->Parameters.Create.Options )) { Data->IoStatus.Information = 0; Data->IoStatus.Status = STATUS_ACCESS_DENIED; return FLT_PREOP_COMPLETE; } return FLT_PREOP_SUCCESS_WITH_CALLBACK; } FltReleaseFileNameInformation( nameInfo ); return FLT_PREOP_SUCCESS_NO_CALLBACK; }
FLT_POSTOP_CALLBACK_STATUS claimsmanPostOperation( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) /*++ Routine Description: This routine is the post-operation completion routine for this miniFilter. This is non-pageable because it may be called at DPC level. Arguments: Data - Pointer to the filter callbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The completion context set in the pre-operation routine. Flags - Denotes whether the completion is successful or is being drained. Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(CompletionContext); UNREFERENCED_PARAMETER(Flags); NTSTATUS status; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; PUNICODE_STRING fileName = NULL; PTOKEN_USER pTokenUser = NULL; UNICODE_STRING sidString; LARGE_INTEGER Timeout; Timeout.QuadPart = (LONGLONG)1 * 10 * 1000 * 1000; // If there is no client registered, bail out immediately! // If the event is from kernel, bail out immediately! // If the event check for existence of file, bail out immediately! if ( (ClaimsmanData.ClientPort == NULL) || (Data->RequestorMode == KernelMode) || (Data->IoStatus.Information == FILE_DOES_NOT_EXIST) || (Data->IoStatus.Information == FILE_EXISTS) ) { return FLT_POSTOP_FINISHED_PROCESSING; } // We got a log record, if there is a file object, get its name. if (FltObjects->FileObject != NULL) { status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); } else { // Can't get a name when there's no file object status = STATUS_UNSUCCESSFUL; } if (NT_SUCCESS(status)) { FltParseFileNameInformation(nameInfo); fileName = &nameInfo->Name; // Produces way too much logging //PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, // ("claimsman!claimsmanPostOperation: fileName=%wZ\n", fileName)); } else { // No point continuing because we obviously did not get a filename anyways return FLT_POSTOP_FINISHED_PROCESSING; } //The only IRP you can trust for user information is IRP_MJ_CREATE. Things //like write can be in arbitrary thread context, and even if the call works //you can get the wrong SID. status = SeQueryInformationToken(SeQuerySubjectContextToken(&(Data->Iopb->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext)), TokenUser, &pTokenUser); if (STATUS_SUCCESS == status && RtlValidSid(pTokenUser->User.Sid)) { // Interesting extension? if (ClaimsmanCheckExtension(&nameInfo->Extension)) { CLAIMSMAN_MESSAGE msg; status = RtlConvertSidToUnicodeString(&sidString, pTokenUser->User.Sid, TRUE); if (NT_SUCCESS(status)) { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: SID=%wZ\n", &sidString)); } else { // No point continuing because we obviously did not get a valid SID FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); return FLT_POSTOP_FINISHED_PROCESSING; } if (ClaimsmanCheckUserIgnore(&sidString)) { // Ignored user! Bail out! FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); RtlFreeUnicodeString(&sidString); return FLT_POSTOP_FINISHED_PROCESSING; } LONGLONG size; LONGLONG modified; getSizeModified(FltObjects->Instance, fileName, &size, &modified); InitializeMessage(&msg, &sidString, fileName, FltObjects->FileObject->ReadAccess, FltObjects->FileObject->WriteAccess, FltObjects->FileObject->DeleteAccess, size, modified, Data->IoStatus.Status); // Ready, send the message! // But only if there's a client connected if (ClaimsmanData.ClientPort != NULL) { FltSendMessage(ClaimsmanData.Filter, &ClaimsmanData.ClientPort, &msg, sizeof(msg), NULL, 0, &Timeout ); PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: sent message=%d\n", status)); } else { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: no client connected!")); } RtlFreeUnicodeString(&sidString); } } FltReleaseFileNameInformation(nameInfo); if (pTokenUser != NULL) { ExFreePool(pTokenUser); } return FLT_POSTOP_FINISHED_PROCESSING; }
NTSTATUS GenerateFileName(IN PFLT_INSTANCE Instance, IN PFILE_OBJECT FileObject, IN PFLT_CALLBACK_DATA CallbackData, IN FLT_FILE_NAME_OPTIONS NameOptions, OUT PBOOLEAN CacheFileNameInformation, OUT PFLT_NAME_CONTROL FileName ) //上层的minifilter过滤驱动的名字请求进行处理 { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFILE_OBJECT StreamObject = FileObject; PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL; BOOLEAN bEncryptResource = FALSE; PFCB Fcb = FileObject->FsContext; PCCB Ccb = FileObject->FsContext2; FsRtlEnterFileSystem(); try { if(IsMyFakeFcb(FileObject)) { ExAcquireResourceSharedLite(Fcb->EncryptResource,TRUE); bEncryptResource = TRUE; if(BooleanFlagOn(Fcb->FcbState,SCB_STATE_SHADOW_CLOSE) || Ccb->StreamFileInfo.StreamObject == NULL) { try_return (Status = STATUS_FILE_DELETED); } else { StreamObject = Ccb->StreamFileInfo.StreamObject; } } ClearFlag(NameOptions,FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER); if(FlagOn(NameOptions,FLT_FILE_NAME_NORMALIZED)) { ClearFlag(NameOptions,FLT_FILE_NAME_NORMALIZED); SetFlag(NameOptions,FLT_FILE_NAME_OPENED); } if (CallbackData) { PFILE_OBJECT TemFileObject = CallbackData->Iopb->TargetFileObject; CallbackData->Iopb->TargetFileObject = StreamObject; FltSetCallbackDataDirty(CallbackData); Status = FltGetFileNameInformation(CallbackData,NameOptions, &FileNameInformation); CallbackData->Iopb->TargetFileObject = TemFileObject; FltClearCallbackDataDirty(CallbackData); } else { Status = FltGetFileNameInformationUnsafe(StreamObject,Instance, NameOptions, &FileNameInformation); } if(!NT_SUCCESS(Status)) { try_return (Status); } Status = FltCheckAndGrowNameControl(FileName, FileNameInformation->Name.Length); if(!NT_SUCCESS(Status)) { try_return (Status); } RtlCopyUnicodeString(&FileName->Name, &FileNameInformation->Name); if(FileNameInformation != NULL) { FltReleaseFileNameInformation(FileNameInformation); } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { if(bEncryptResource) { ExReleaseResourceLite( Fcb->EncryptResource ); } } FsRtlExitFileSystem(); return Status; }
FLT_POSTOP_CALLBACK_STATUS CtxPostSetInfo ( _Inout_ PFLT_CALLBACK_DATA Cbd, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_opt_ PVOID CbdContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) { PCTX_INSTANCE_CONTEXT instanceContext = NULL; PCTX_FILE_CONTEXT fileContext = NULL; PCTX_STREAM_CONTEXT streamContext = NULL; PCTX_STREAMHANDLE_CONTEXT streamHandleContext = NULL; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; NTSTATUS status; BOOLEAN streamContextCreated, fileContextCreated, streamHandleContextReplaced; UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CbdContext ); // // The pre-operation callback will return FLT_PREOP_SYNCHRONIZE if it needs a // post operation callback. In this case, the Filter Manager will call the // minifilter's post-operation callback in the context of the pre-operation // thread, at IRQL <= APC_LEVEL. This allows the post-operation code to be // pagable and also allows it to access paged data // PAGED_CODE(); DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostSetInfo -> Enter (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); // // Initialize defaults // status = STATUS_SUCCESS; // // If the SetInfo has failed, do nothing // if (!NT_SUCCESS( Cbd->IoStatus.Status )) { goto CtxPostSetInfoCleanup; } // // Get the instance context for the target instance // DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Trying to get instance context (TargetInstance = %p, Cbd = %p, FileObject = %p)\n", Cbd->Iopb->TargetInstance, Cbd, FltObjects->FileObject) ); status = FltGetInstanceContext( Cbd->Iopb->TargetInstance, &instanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: CtxPostSetInfo -> Failed to get instance context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Instance context info for volume %wZ (Cbd = %p, FileObject = %p, InstanceContext = %p) \n\tVolumeName = %wZ \n\tInstance = %p \n\tVolume = %p\n", &instanceContext->VolumeName, Cbd, FltObjects->FileObject, instanceContext, &instanceContext->VolumeName, &instanceContext->Instance, &instanceContext->Volume) ); // // Get the directory name // status = FltGetFileNameInformation( Cbd, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to get file name information (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } // // Get the stream context // status = CtxFindOrCreateStreamContext(Cbd, FALSE, // do not create if one does not exist &streamContext, &streamContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to find stream context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Getting stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p. StreamContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, streamContextCreated) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive(streamContext->Resource); DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Old info in stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Update the file name in the context // status = CtxUpdateNameInStreamContext( &nameInfo->Name, streamContext); DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> New info in stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Relinquish write acccess to the context // CtxReleaseResource(streamContext->Resource); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to update name in stream context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } // // Create or replace a stream handle context // status = CtxCreateOrReplaceStreamHandleContext(Cbd, TRUE, &streamHandleContext, &streamHandleContextReplaced); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to find or create stream handle context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Creating/Replacing stream handle context for file %wZ (Cbd = %p, FileObject = %p StreamHandleContext = %p, StreamHandleContextReplaced = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, streamHandleContextReplaced) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive(streamHandleContext->Resource); // // Update the file name in the context // status = CtxUpdateNameInStreamHandleContext( &nameInfo->Name, streamHandleContext); DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Stream handle context info for file %wZ (Cbd = %p, FileObject = %p, StreamHandleContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, &streamHandleContext->FileName) ); // // Relinquish write acccess to the context // CtxReleaseResource( streamHandleContext->Resource ); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to update name in stream handle context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } // // Get the file context // status = CtxFindOrCreateFileContext( Cbd, FALSE, // do not create if one does not exist NULL, &fileContext, &fileContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because file contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to find file context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Getting file context for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p. FileContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, fileContextCreated) ); DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> File context info for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, &fileContext->FileName) ); CtxPostSetInfoCleanup: // // Release the references we have acquired // if (instanceContext != NULL) { FltReleaseContext( instanceContext ); } if (fileContext != NULL) { FltReleaseContext( fileContext ); } if (streamContext != NULL) { FltReleaseContext( streamContext ); } if (streamHandleContext != NULL) { FltReleaseContext( streamHandleContext ); } if (nameInfo != NULL) { FltReleaseFileNameInformation( nameInfo ); } if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR, ("[Ctx]: CtxPostSetInfo -> Failed with status 0x%x \n", status) ); // // It doesn't make sense to udate Cbd->IoStatus.Status on failure since the // file system has suceesfully completed the operation // } DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostSetInfo -> Exit (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); return FLT_POSTOP_FINISHED_PROCESSING; }
FLT_POSTOP_CALLBACK_STATUS CtxPostCreate ( _Inout_ PFLT_CALLBACK_DATA Cbd, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_opt_ PVOID CbdContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) { PCTX_FILE_CONTEXT fileContext = NULL; PCTX_STREAM_CONTEXT streamContext = NULL; PCTX_STREAMHANDLE_CONTEXT streamHandleContext = NULL; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; UNICODE_STRING fileName; NTSTATUS status; BOOLEAN fileContextCreated, streamContextCreated, streamHandleContextReplaced; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( CbdContext ); PAGED_CODE(); DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostCreate -> Enter (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); // // Initialize defaults // status = STATUS_SUCCESS; // // If the Create has failed, do nothing // if (!NT_SUCCESS( Cbd->IoStatus.Status )) { goto CtxPostCreateCleanup; } // // Get the file name // status = FltGetFileNameInformation( Cbd, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to get name information (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } // // Find or create a stream context // status = CtxFindOrCreateStreamContext(Cbd, TRUE, &streamContext, &streamContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to find or create stream context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Getting/Creating stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p. StreamContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, streamContextCreated) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive(streamContext->Resource); // // Increment the create count // streamContext->CreateCount++; // // Update the file name in the context // status = CtxUpdateNameInStreamContext( &nameInfo->Name, streamContext); DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Stream context info for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Relinquish write acccess to the context // CtxReleaseResource(streamContext->Resource); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to update name in stream context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } // // Create or replace a stream handle context // status = CtxCreateOrReplaceStreamHandleContext(Cbd, TRUE, &streamHandleContext, &streamHandleContextReplaced); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to find or create stream handle context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Creating/Replacing stream handle context for file %wZ (Cbd = %p, FileObject = %p StreamHandleContext = %p, StreamHandleContextReplaced = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, streamHandleContextReplaced) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive( streamHandleContext->Resource ); // // Update the file name in the context // status = CtxUpdateNameInStreamHandleContext( &nameInfo->Name, streamHandleContext); DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Stream handle context info for file %wZ (Cbd = %p, FileObject = %p, StreamHandleContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, &streamHandleContext->FileName) ); // // Relinquish write acccess to the context // CtxReleaseResource(streamHandleContext->Resource); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to update name in stream handle context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } // // After FltParseFileNameInformation, nameInfo->Name also // contains the stream name. We need only the filename and do // not want to include the stream name in the file context // fileName.Buffer = nameInfo->Name.Buffer; fileName.Length = nameInfo->Name.Length - nameInfo->Stream.Length; fileName.MaximumLength = fileName.Length; // // Find or create a file context // status = CtxFindOrCreateFileContext( Cbd, TRUE, &fileName, &fileContext, &fileContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because file contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to find or create file context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Getting/Creating file context for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p. FileContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, fileContextCreated) ); DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> File context info for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, &fileContext->FileName) ); CtxPostCreateCleanup: // // Release the references we have acquired // if (nameInfo != NULL) { FltReleaseFileNameInformation( nameInfo ); } if (fileContext != NULL) { FltReleaseContext( fileContext ); } if (streamContext != NULL) { FltReleaseContext( streamContext ); } if (streamHandleContext != NULL) { FltReleaseContext( streamHandleContext ); } if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR, ("[Ctx]: CtxPostCreate -> Failed with status 0x%x \n", status) ); // // It doesn't make sense to udate Cbd->IoStatus.Status on failure since the // file system has successfully completed the operation // } DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostCreate -> Exit (Cbd = %p, FileObject = %p, Status = 0x%x)\n", Cbd, FltObjects->FileObject, Cbd->IoStatus.Status) ); return FLT_POSTOP_FINISHED_PROCESSING; }
NTSTATUS NcGetFileNameInformation( _In_opt_ PFLT_CALLBACK_DATA Data, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PFLT_INSTANCE Instance, _In_ FLT_FILE_NAME_OPTIONS NameOptions, _Outptr_ PFLT_FILE_NAME_INFORMATION *FileNameInformation ) /*++ Routine Description: This function is a wrapper to call the correct variant of FltGetFileNameInformation depending on the information we happen to have available. Arguments: Data - Pointer to the callback data structure associated with a request. This is optional, but if not specified, FileObject and Instance must be supplied. FileObject - Pointer to the file object to query a name on. Optional, but if not supplied, Data must be supplied. Instance - Pointer to the instance of our filter to query the name on. Optional, but if not supplied, Data must be supplied. NameOptions - FLT_FILE_NAME_* flags for this request. FileNameInformation - On output, contains the file name information resulting from this query. On failure, contents are undefined. On success, caller is responsible for releasing this with FltReleaseFileNameInformation. Return Value: Returns the status of the operation. --*/ { NTSTATUS Status; PAGED_CODE(); FLT_ASSERT( Data || FileObject ); *FileNameInformation = NULL; if (ARGUMENT_PRESENT( Data )) { Status = FltGetFileNameInformation( Data, NameOptions, FileNameInformation ); } else if (ARGUMENT_PRESENT( FileObject )) { Status = FltGetFileNameInformationUnsafe( FileObject, Instance, NameOptions, FileNameInformation ); // // This should never happen, as either Data or FileObject must be non-NULL. // } else { FLT_ASSERT( FALSE ); Status = STATUS_INVALID_PARAMETER; } return Status; }
/* * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ** * * * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ** */ FLT_POSTOP_CALLBACK_STATUS PostSetInformation( IN OUT PFLT_CALLBACK_DATA Data, IN PCFLT_RELATED_OBJECTS FltObjects, IN PVOID CompletionContext, IN FLT_POST_OPERATION_FLAGS Flags ) { PFLT_FILE_NAME_INFORMATION FNameInfo; NTSTATUS Status; FILE_RENAME_INFORMATION FRI; // If we have an error then just exit if ( !NT_SUCCESS( Data->IoStatus.Status ) || ( STATUS_REPARSE == Data->IoStatus.Status ) ) { return FLT_POSTOP_FINISHED_PROCESSING; } Status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &FNameInfo ); // If we could not get the name information then exit if (!NT_SUCCESS( Status )) { return FLT_POSTOP_FINISHED_PROCESSING; } FltParseFileNameInformation( FNameInfo ); switch ( Data->Iopb->Parameters.SetFileInformation.FileInformationClass ) { case FileRenameInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-RENAME [%wZ] \n", &FNameInfo->Name ) ); break; } case FileAllocationInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-ALLOCATION [%wZ] \n", &FNameInfo->Name ) ); break; } case FileBasicInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-BASIC[%wZ] \n", &FNameInfo->Name ) ); break; } case FileDispositionInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-DISPOSITION [%wZ] \n", &FNameInfo->Name ) ); break; } case FileEndOfFileInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-EOF [%wZ] \n", &FNameInfo->Name ) ); break; } case FileLinkInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-LINK [%wZ] \n", &FNameInfo->Name ) ); break; } case FilePositionInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-POSITION [%wZ] \n", &FNameInfo->Name ) ); break; } case FileValidDataLengthInformation: { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "PostSetInfo()-VALIDATEDATALENGTH [%wZ] \n", &FNameInfo->Name ) ); break; } default : { DBG_PRINT( DbgOutput, DBG_IRP_MJ_SET_INFORMATION, (PRINT_TAG_SETINFO "BAD MOJO\n") ); break; } } // End switch ( Data->Iopb->Parameters.SetFileInformation.FileInformationClass ) // Free FltReleaseFileNameInformation( FNameInfo ); return FLT_POSTOP_FINISHED_PROCESSING; }
static FLT_POSTOP_CALLBACK_STATUS FileCreateFilterPostCallback ( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID CompletionContext, FLT_POST_OPERATION_FLAGS Flags ) { FLT_POSTOP_CALLBACK_STATUS status = FLT_POSTOP_FINISHED_PROCESSING; KLOCK_QUEUE_HANDLE hMutex = { 0 }; PFLT_FILE_NAME_INFORMATION fileInfo = NULL; RU32 pid = 0; RU64 ts = 0; RU32 createOptions = 0; RU32 createDispositions = 0; _fileContext* context = NULL; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); UNREFERENCED_PARAMETER( Flags ); // We only care about user mode for now. if( UserMode != Data->RequestorMode || STATUS_SUCCESS != Data->IoStatus.Status ) { return status; } if( FILE_CREATED == Data->IoStatus.Information ) { pid = (RU32)FltGetRequestorProcessId( Data ); ts = rpal_time_getLocal(); if( !NT_SUCCESS( FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &fileInfo ) ) ) { rpal_debug_kernel( "Failed to get file name info" ); fileInfo = NULL; } else { //rpal_debug_kernel( "NEW: %wZ", fileInfo->Name ); } if( NULL != ( context = _getOrSetContext( Data ) ) ) { context->isNew = TRUE; FltReleaseContext( (PFLT_CONTEXT)context ); } KeAcquireInStackQueuedSpinLock( &g_collector_2_mutex, &hMutex ); g_files[ g_nextFile ].pid = pid; g_files[ g_nextFile ].ts = ts; g_files[ g_nextFile ].uid = KERNEL_ACQ_NO_USER_ID; g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_ADDED; if( NULL != fileInfo ) { copyUnicodeStringToBuffer( &fileInfo->Name, g_files[ g_nextFile ].path ); FltReleaseFileNameInformation( fileInfo ); } g_nextFile++; if( g_nextFile == _NUM_BUFFERED_FILES ) { g_nextFile = 0; } KeReleaseInStackQueuedSpinLock( &hMutex ); } createOptions = Data->Iopb->Parameters.Create.Options & 0x00FFFFFF; createDispositions = ( Data->Iopb->Parameters.Create.Options & 0xFF000000 ) >> 24; if( IS_FLAG_ENABLED( createOptions, FILE_DELETE_ON_CLOSE ) ) { if( NULL != ( context = _getOrSetContext( Data ) ) ) { context->isDelete = TRUE; FltReleaseContext( (PFLT_CONTEXT)context ); } } return status; }
FLT_PREOP_CALLBACK_STATUS PreFileOperationCallback ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { NTSTATUS status; PFLT_FILE_NAME_INFORMATION pFileNameInformation; PFILE_EVENT pFileEvent; LARGE_INTEGER CurrentSystemTime; LARGE_INTEGER CurrentLocalTime; ULONG returnedLength; //HANDLE hThread; //HANDLE handle5; TIME_FIELDS TimeFields; BOOLEAN pathNameFound = FALSE; UNICODE_STRING filePath; FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; /* If this is a callback for a FS Filter driver then we ignore the event */ if(FLT_IS_FS_FILTER_OPERATION(Data)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } /* Allocate a large 64kb string ... maximum path name allowed in windows */ filePath.Length = 0; filePath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR); filePath.Buffer = ExAllocatePoolWithTag(NonPagedPool, filePath.MaximumLength, FILE_POOL_TAG); if(filePath.Buffer == NULL) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } if (FltObjects->FileObject != NULL && Data != NULL) { status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &pFileNameInformation ); if(NT_SUCCESS(status)) { if(pFileNameInformation->Name.Length > 0) { RtlUnicodeStringCopy(&filePath, &pFileNameInformation->Name); //RtlStringCbCopyUnicodeString(pFileEvent->filePath, 1024, &pFileNameInformation->Name); pathNameFound = TRUE; } /* Backup the file if it is marked for deletion */ CopyFileIfBeingDeleted (Data,FltObjects,pFileNameInformation); /* Release the file name information structure if it was used */ if(pFileNameInformation != NULL) { FltReleaseFileNameInformation(pFileNameInformation); } } else { NTSTATUS lstatus; PFLT_FILE_NAME_INFORMATION pLFileNameInformation; lstatus = FltGetFileNameInformation( Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &pLFileNameInformation); if(NT_SUCCESS(lstatus)) { if(pLFileNameInformation->Name.Length > 0) { RtlUnicodeStringCopy(&filePath, &pLFileNameInformation->Name); //RtlStringCbCopyUnicodeString(pFileEvent->filePath, 1024, &pLFileNameInformation->Name); pathNameFound = TRUE; } /* Backup the file if it is marked for deletion */ CopyFileIfBeingDeleted (Data,FltObjects,pFileNameInformation); /* Release the file name information structure if it was used */ if(pLFileNameInformation != NULL) { FltReleaseFileNameInformation(pLFileNameInformation); } } } } /* If path name could not be found the file monitor uses the file name stored in the FileObject. The documentation says that we shouldn't use this info as it may not be correct. It does however allow us get some nice file events such as the system process writing to the $MFT file etc. Remove this code if problems start to occur */ if( (pathNameFound == FALSE) && (FltObjects->FileObject != NULL) && (FltObjects->FileObject->RelatedFileObject == NULL) && (FltObjects->FileObject->FileName.Length > 0)) { NTSTATUS status; ULONG size; UNICODE_STRING szTempPath; UNICODE_STRING szDevice; UNICODE_STRING szFileNameDevice; /* Check the FileObject->FileName isn't already a complete filepath */ szFileNameDevice.Length = FltObjects->FileObject->FileName.Length; szFileNameDevice.MaximumLength = FltObjects->FileObject->FileName.MaximumLength; szFileNameDevice.Buffer = ExAllocatePoolWithTag(NonPagedPool, szFileNameDevice.MaximumLength, FILE_POOL_TAG); RtlInitUnicodeString(&szDevice, L"\\Device"); if(FltObjects->FileObject->FileName.Length >= szDevice.Length) { RtlUnicodeStringCchCopyN(&szFileNameDevice, &FltObjects->FileObject->FileName, 7); } if(RtlEqualUnicodeString(&szDevice, &szFileNameDevice, TRUE)) { RtlUnicodeStringCopy(&filePath, &FltObjects->FileObject->FileName); pathNameFound = TRUE; } else { szTempPath.Length = 0; szTempPath.MaximumLength = FltObjects->FileObject->FileName.MaximumLength + 2; /* Get the volume name of where the event came from */ status = FltGetVolumeName( FltObjects->Volume, NULL, &size ); if(status == STATUS_BUFFER_TOO_SMALL) { szTempPath.MaximumLength += (USHORT)size; szTempPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, szTempPath.MaximumLength, FILE_POOL_TAG); if(szTempPath.Buffer != NULL) { status = FltGetVolumeName( FltObjects->Volume, &szTempPath, &size ); if(NT_SUCCESS(status)) { /* Append the file event to the volume name */ RtlUnicodeStringCat(&szTempPath, &FltObjects->FileObject->FileName); RtlUnicodeStringCopy(&filePath, &szTempPath); pathNameFound = TRUE; } ExFreePoolWithTag(szTempPath.Buffer, FILE_POOL_TAG); } } } ExFreePoolWithTag(szFileNameDevice.Buffer, FILE_POOL_TAG); } if(!pathNameFound) { RtlUnicodeStringCatString(&filePath, L"UNKNOWN"); } /* Allocate file event and put the values into it */ /* NOTE this is freed in the post op callback (which should always get called) */ pFileEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_EVENT)+filePath.Length+sizeof(WCHAR), FILE_POOL_TAG); if(pFileEvent == NULL) { ExFreePoolWithTag(filePath.Buffer, FILE_POOL_TAG); return FLT_PREOP_SUCCESS_NO_CALLBACK; } /* Copy file path into file event */ pFileEvent->filePathLength = filePath.Length+sizeof(WCHAR); RtlStringCbCopyUnicodeString(pFileEvent->filePath, pFileEvent->filePathLength, &filePath); /* Free the allocated storage for a filepath */ ExFreePoolWithTag(filePath.Buffer, FILE_POOL_TAG); pFileEvent->majorFileEventType = Data->Iopb->MajorFunction; pFileEvent->minorFileEventType = Data->Iopb->MinorFunction; pFileEvent->processId = 0; if (FltObjects->FileObject != NULL) { pFileEvent->flags = FltObjects->FileObject->Flags; } if(Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) { if(Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformation) { PFILE_DISPOSITION_INFORMATION pFileInfo = (PFILE_DISPOSITION_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer; /* If the file is marked for deletion back it up */ if(pFileInfo->DeleteFile) { pFileEvent->majorFileEventType = 0x99; } } } /* Get the process id of the file event */ /* NOTE we are kinda using an undocumented function here but its all available on the interweb. Plus its much better than accessing the PETHREAD structure which could change at any time. Also, this one is available to userspace programs so it should be safe to use. We have to use this function because a file I/O may either be processed in the context of the userspace program or the system context. This uses the thread data from FLT_CALLBACK_DATA to determine which process it actually came from. We default back to getting the current process id if all else fails. */ /* SECOND NOTE FltGetRequestorProcessId does not get the correct process id, it looks like it still get the proces id of the context the pre callback gets called in */ /* status = ObOpenObjectByPointer(Data->Thread, OBJ_KERNEL_HANDLE, NULL, 0, 0, KernelMode, &hThread); if(NT_SUCCESS(status)) { THREAD_BASIC_INFORMATION threadBasicInformation; status = ZwQueryInformationThread(hThread, ThreadBasicInformation, &threadBasicInformation, sizeof(THREAD_BASIC_INFORMATION), &returnedLength ); if(NT_SUCCESS(status)) { pFileEvent->processId = (HANDLE)threadBasicInformation.UniqueProcessId; handle5 = pFileEvent->processId; //DbgPrint("Process4: %i\n", pFileEvent->processId); } else { DbgPrint("ZwQueryInformationThread FAILED: %08x\n", status); } ZwClose(hThread); } else { DbgPrint("ObOpenObjectByPointer FAILED: %08x\n", status); } */ /* New safe get correct process id. One above causes blue screen in some cases */ if(Data->Thread != NULL) { PEPROCESS pProcess = IoThreadToProcess( Data->Thread ); pFileEvent->processId = PsGetProcessId(pProcess); } else { pFileEvent->processId = PsGetCurrentProcessId(); DbgPrint("CaptureFileMonitor: Process id may be incorrect\n"); } /* DbgPrint("%i [%i %i] %s %i %i (%i, %i, %i) %i %i %i %i %i : %ls\n", KeGetCurrentIrql(), PsIsSystemThread(Data->Thread), PsIsSystemThread(PsGetCurrentThread()), FltGetIrpName(Data->Iopb->MajorFunction), Data->Iopb->MajorFunction, Data->Iopb->MinorFunction, pFileEvent->processId, PsGetCurrentProcessId(), FltGetRequestorProcessId(Data), FLT_IS_FASTIO_OPERATION(Data), FLT_IS_FS_FILTER_OPERATION(Data), FLT_IS_IRP_OPERATION(Data), FLT_IS_REISSUED_IO(Data), FLT_IS_SYSTEM_BUFFER(Data), pFileEvent->filePath); */ //ASSERT(pFileEvent->processId != 0); /* Get the time this event occured */ KeQuerySystemTime(&CurrentSystemTime); ExSystemTimeToLocalTime(&CurrentSystemTime,&CurrentLocalTime); RtlTimeToTimeFields(&CurrentLocalTime,&TimeFields); pFileEvent->time = TimeFields; /* Pass the created file event to the post operation of this pre file operation */ if (Data->Iopb->MajorFunction == IRP_MJ_SHUTDOWN) { PostFileOperationCallback( Data, FltObjects, pFileEvent, 0 ); return FLT_PREOP_SUCCESS_NO_CALLBACK; } else { *CompletionContext = pFileEvent; return FLT_PREOP_SUCCESS_WITH_CALLBACK; } }
static FLT_POSTOP_CALLBACK_STATUS on_post_op (PFLT_CALLBACK_DATA data, PCFLT_RELATED_OBJECTS fltobj, struct event *event, FLT_POST_OPERATION_FLAGS flags) { if (event == NULL) return FLT_POSTOP_FINISHED_PROCESSING; event->time_post = get_timestamp(); event->status = data->IoStatus.Status; if (data->Iopb->MajorFunction == IRP_MJ_CREATE) { FLT_FILE_NAME_INFORMATION *name_info = NULL; if (FltGetFileNameInformation(data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &name_info) != STATUS_SUCCESS) { event_buffer_cancel_add(event); return FLT_POSTOP_FINISHED_PROCESSING; } event->path_length = MAX_PATH_SIZE - 1 < name_info->Name.Length / 2 ? MAX_PATH_SIZE - 1 : name_info->Name.Length / 2; RtlCopyMemory(event->path, name_info->Name.Buffer, event->path_length * 2); event->path[event->path_length] = 0; FltReleaseFileNameInformation(name_info); } switch (data->Iopb->MajorFunction) { case IRP_MJ_CLOSE: event->type = ET_FILE_CLOSE; break; case IRP_MJ_CREATE: event->type = ET_FILE_CREATE; event->file_create.desired_access = data->Iopb->Parameters.Create.SecurityContext->DesiredAccess; event->file_create.share_mode = data->Iopb->Parameters.Create.ShareAccess; event->file_create.attributes = data->Iopb->Parameters.Create.FileAttributes; event->file_create.creation_disposition = data->Iopb->Parameters.Create.Options >> 24; event->file_create.create_options = data->Iopb->Parameters.Create.Options & 0x00ffffff; event->file_create.status_information = data->IoStatus.Information; break; case IRP_MJ_READ: event->type = ET_FILE_READ; event->file_rw.offset = data->Iopb->Parameters.Read.ByteOffset; event->file_rw.req_length = data->Iopb->Parameters.Read.Length; event->file_rw.ret_length = data->IoStatus.Information; break; case IRP_MJ_WRITE: event->type = ET_FILE_WRITE; event->file_rw.offset = data->Iopb->Parameters.Write.ByteOffset; event->file_rw.req_length = data->Iopb->Parameters.Write.Length; event->file_rw.ret_length = data->IoStatus.Information; break; case IRP_MJ_CREATE_MAILSLOT: event->type = ET_FILE_CREATE_MAILSLOT; break; case IRP_MJ_CREATE_NAMED_PIPE: event->type = ET_FILE_CREATE_NAMED_PIPE; break; case IRP_MJ_QUERY_INFORMATION: event->type = ET_FILE_QUERY_INFORMATION; if (data->IoStatus.Status == STATUS_SUCCESS || data->IoStatus.Status == STATUS_BUFFER_OVERFLOW) { event->file_info.info_type = data->Iopb->Parameters.QueryFileInformation.FileInformationClass; event->file_info.info_size = data->Iopb->Parameters.QueryFileInformation.Length < sizeof(event->file_info.info_data) ? data->Iopb->Parameters.QueryFileInformation.Length : sizeof(event->file_info.info_data); // NOTE: string inside the info structure is not zero terminated. RtlCopyMemory(&event->file_info.info_data, data->Iopb->Parameters.QueryFileInformation.InfoBuffer, event->file_info.info_size); } break; case IRP_MJ_SET_INFORMATION: event->type = ET_FILE_SET_INFORMATION; event->file_info.info_type = data->Iopb->Parameters.SetFileInformation.FileInformationClass; event->file_info.info_size = data->Iopb->Parameters.SetFileInformation.Length < sizeof(event->file_info.info_data) ? data->Iopb->Parameters.SetFileInformation.Length : sizeof(event->file_info.info_data); // NOTE: string inside the info structure is not zero terminated. RtlCopyMemory(&event->file_info.info_data, data->Iopb->Parameters.SetFileInformation.InfoBuffer, event->file_info.info_size); break; default: DbgPrint("resmon: unknown post MajorFunction %d\n", data->Iopb->MajorFunction); event_buffer_cancel_add(event); return FLT_POSTOP_FINISHED_PROCESSING; } event_buffer_finish_add(event); return FLT_POSTOP_FINISHED_PROCESSING; }