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; }
VOID GetDosDeviceName(PDEVICE_OBJECT pDeviceObject, PUNICODE_STRING pShareName, PUNICODE_STRING pDosName) { NTSTATUS status; UNICODE_STRING tempDosDrive; ObReferenceObject(pDeviceObject); status = IoVolumeDeviceToDosName( (PVOID)pDeviceObject, &tempDosDrive); pDosName->Length = 0; if(NT_SUCCESS(status)) { int i = 0; int wchars = tempDosDrive.Length/2; int pos = 0; pDosName->MaximumLength = tempDosDrive.MaximumLength + 2; pDosName->Buffer = ExAllocatePoolWithTag(NonPagedPool, pDosName->MaximumLength, FILE_POOL_TAG); if(pDosName->Buffer != NULL) { pDosName->Buffer[pos++] = '\\'; pDosName->Length += sizeof(WCHAR); for(i = 0; i < wchars; i++) { if(tempDosDrive.Buffer[i] != 0x003A) { pDosName->Buffer[pos++] = tempDosDrive.Buffer[i]; pDosName->Length += sizeof(WCHAR); // Unicode is 2-bytes } } ExFreePool(tempDosDrive.Buffer); } } else { if(pShareName != NULL) { pDosName->MaximumLength = pShareName->MaximumLength; pDosName->Buffer = ExAllocatePoolWithTag(NonPagedPool, pDosName->MaximumLength, FILE_POOL_TAG); if(pDosName->Buffer != NULL) { RtlUnicodeStringCopy(pDosName, pShareName); } } else { pDosName->MaximumLength = 30; // Dont change this pDosName->Buffer = ExAllocatePoolWithTag(NonPagedPool, pDosName->MaximumLength, FILE_POOL_TAG); if(pDosName->Buffer != NULL) { RtlUnicodeStringCatString(pDosName, L"\\UNKNOWN DRIVE"); } } } ObDereferenceObject(pDeviceObject); }
BOOLEAN GetRegistryObjectCompleteName(PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath, PVOID pRegistryObject) { BOOLEAN foundCompleteName = FALSE; BOOLEAN partial = FALSE; if((!MmIsAddressValid(pRegistryObject)) || (pRegistryObject == NULL)) { return FALSE; } /* Check to see if the partial name is really the complete name */ if(pPartialRegistryPath != NULL) { if((((pPartialRegistryPath->Buffer[0] == '\\') || (pPartialRegistryPath->Buffer[0] == '%')) || ((pPartialRegistryPath->Buffer[0] == 'T') && (pPartialRegistryPath->Buffer[1] == 'R') && (pPartialRegistryPath->Buffer[2] == 'Y') && (pPartialRegistryPath->Buffer[3] == '\\'))) ) { RtlUnicodeStringCopy(pRegistryPath, pPartialRegistryPath); partial = TRUE; foundCompleteName = TRUE; } } if(!foundCompleteName) { /* Query the object manager in the kernel for the complete name */ NTSTATUS status; ULONG returnedLength; PUNICODE_STRING pObjectName = NULL; status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, 0, &returnedLength ); if(status == STATUS_INFO_LENGTH_MISMATCH) { pObjectName = ExAllocatePoolWithTag(NonPagedPool, returnedLength, REGISTRY_POOL_TAG); status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, returnedLength, &returnedLength ); if(NT_SUCCESS(status)) { RtlUnicodeStringCopy(pRegistryPath, pObjectName); foundCompleteName = TRUE; } ExFreePoolWithTag(pObjectName, REGISTRY_POOL_TAG); } } //ASSERT(foundCompleteName == TRUE); return foundCompleteName; }
NTSTATUS Ds4_PreparePdo(PWDFDEVICE_INIT DeviceInit, PUNICODE_STRING DeviceId, PUNICODE_STRING DeviceDescription) { NTSTATUS status; UNICODE_STRING buffer; // prepare device description status = RtlUnicodeStringInit(DeviceDescription, L"Virtual DualShock 4 Controller"); if (!NT_SUCCESS(status)) return status; // Set hardware IDs RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4&REV_0100"); status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); if (!NT_SUCCESS(status)) return status; RtlUnicodeStringCopy(DeviceId, &buffer); RtlUnicodeStringInit(&buffer, L"USB\\VID_054C&PID_05C4"); status = WdfPdoInitAddHardwareID(DeviceInit, &buffer); if (!NT_SUCCESS(status)) return status; // Set compatible IDs RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00&Prot_00"); status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); if (!NT_SUCCESS(status)) return status; RtlUnicodeStringInit(&buffer, L"USB\\Class_03&SubClass_00"); status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); if (!NT_SUCCESS(status)) return status; RtlUnicodeStringInit(&buffer, L"USB\\Class_03"); status = WdfPdoInitAddCompatibleID(DeviceInit, &buffer); if (!NT_SUCCESS(status)) return status; return STATUS_SUCCESS; }
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; } }