VOID CreateAllDirectories(PFLT_INSTANCE pInstance, PUNICODE_STRING pRootDirectory, PUNICODE_STRING pDirectory) { UNICODE_STRING totalDirectory; UNICODE_STRING path; USHORT dirSeperator = 0x005C; // Search for \ as a 16-bit unicode char USHORT i = 0; USHORT length = pDirectory->Length/2; USHORT prevDirPosition = 0; //RtlUnicodeStringInit(&path, L"\\??\\I:\\logs\\"); totalDirectory.Length = 0; totalDirectory.MaximumLength = pRootDirectory->MaximumLength + pDirectory->MaximumLength + 2; totalDirectory.Buffer = ExAllocatePoolWithTag(NonPagedPool, totalDirectory.MaximumLength, FILE_POOL_TAG); if(totalDirectory.Buffer == NULL) { return; } //RtlAppendUnicodeString( //RtlUnicodeStringCatString(&totalDirectory, L"\\??\\I:\\logs\\"); RtlUnicodeStringCat(&totalDirectory,pRootDirectory); for(i = 0; i < length; i++) { USHORT tempChar = pDirectory->Buffer[i]; if(dirSeperator == tempChar) { if(i != 0) { USHORT size = (i) - (prevDirPosition); PWSTR dir = ExAllocatePoolWithTag(NonPagedPool, sizeof(WCHAR)*(size+1), FILE_POOL_TAG); if(dir == NULL) { break; } RtlZeroMemory(dir, sizeof(WCHAR)*(size+1)); RtlCopyMemory(dir, pDirectory->Buffer+((prevDirPosition)), size*sizeof(WCHAR)); dir[size] = '\0'; RtlUnicodeStringCatString(&totalDirectory, dir); //DbgPrint("Creating dir: %wZ\n", &totalDirectory); CreateADirectory(pInstance, &totalDirectory); //RtlUnicodeStringCatString(&totalDirectory, L"\\"); ExFreePoolWithTag(dir, FILE_POOL_TAG); prevDirPosition = i; } } } ExFreePoolWithTag(totalDirectory.Buffer, FILE_POOL_TAG); }
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); }
NTSTATUS RegistryCallback( _In_ PVOID CallbackContext, _In_opt_ PVOID Argument1, _In_opt_ PVOID Argument2 ) { NTSTATUS status = STATUS_SUCCESS; ULONG ulCallbackCtx; REG_NOTIFY_CLASS ulType = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1; UNICODE_STRING usRegistryPath = { 0 }; BOOLEAN bSuccess = FALSE; LARGE_INTEGER unCurrentSystemTime; LARGE_INTEGER unCurrentLocalTime; PVOID pData = NULL; ULONG ulDataSize = 0; ULONG ulKeyValueType = REG_NONE; WCHAR wzProcessPath[MAX_STRING_LENGTH] = { 0 }; // 时间 KeQuerySystemTime(&unCurrentSystemTime); ExSystemTimeToLocalTime(&unCurrentSystemTime, &unCurrentLocalTime); ulCallbackCtx = (ULONG)(ULONG_PTR)CallbackContext; usRegistryPath.Length = 0; usRegistryPath.MaximumLength = 2048 * sizeof(WCHAR); usRegistryPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, usRegistryPath.MaximumLength, MEM_TAG); if (NULL == usRegistryPath.Buffer) { KdPrint(("[RegistryCallback] Failed to call ExAllocPollWithTag.\r\n")); return status; } switch (ulType) { case RegNtPreCreateKeyEx: { PREG_CREATE_KEY_INFORMATION_V1 pCreateInfo = (PREG_CREATE_KEY_INFORMATION_V1)Argument2; UNICODE_STRING usFilter = { 0 }; BOOLEAN bEqual = FALSE; WCHAR *wzFilters[] = { L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\DeviceClasses", L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses", L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters", L"\\REGISTRY\\MACHINE\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters" }; bSuccess = GetRegistryObjectCompleteName( &usRegistryPath, pCreateInfo->CompleteName, pCreateInfo->RootObject); if (bSuccess) { for (size_t nCount = 0; nCount < sizeof(wzFilters) / sizeof(ULONG_PTR); nCount++) { RtlInitUnicodeString(&usFilter, wzFilters[nCount]); if (RtlEqualUnicodeString(&usRegistryPath, &usFilter, TRUE)) { bEqual = TRUE; } } if (!bEqual) { //WCHAR wzProcessPath[MAX_STRING_LENGTH] = { 0 }; //GetProcessPathBySectionObject(PsGetCurrentProcessId(), wzProcessPath); //KdPrint(("[RegNtPreCreateKeyEx] [%ws] %wZ\r\n", wzProcessPath, &usRegistryPath)); } else { usRegistryPath.Length = 0; } } } break; case RegNtPreDeleteKey: { PREG_DELETE_KEY_INFORMATION pDeleteKey = (PREG_DELETE_KEY_INFORMATION)Argument2; bSuccess = GetRegistryObjectCompleteName( &usRegistryPath, NULL, pDeleteKey->Object); if (bSuccess) { // KdPrint(("[RegNtPreDeleteKey]: %wZ\r\n", &usRegistryPath)); } } break; case RegNtPreSetValueKey: { PREG_SET_VALUE_KEY_INFORMATION pSetKeyValue = (PREG_SET_VALUE_KEY_INFORMATION)Argument2; bSuccess = GetRegistryObjectCompleteName( &usRegistryPath, NULL, pSetKeyValue->Object); if (bSuccess && pSetKeyValue->ValueName->Length > 0 && (REG_SZ == pSetKeyValue->Type || REG_DWORD == pSetKeyValue->Type || REG_QWORD == pSetKeyValue->Type)) { RtlUnicodeStringCatString(&usRegistryPath, L"\\"); RtlUnicodeStringCat(&usRegistryPath, pSetKeyValue->ValueName); ulKeyValueType = pSetKeyValue->Type; ulDataSize = pSetKeyValue->DataSize; pData = pSetKeyValue->Data; } else { usRegistryPath.Length = 0; } } break; case RegNtPreDeleteValueKey: { PREG_DELETE_VALUE_KEY_INFORMATION pDeleteValueKey = (PREG_DELETE_VALUE_KEY_INFORMATION)Argument2; bSuccess = GetRegistryObjectCompleteName(&usRegistryPath, NULL, pDeleteValueKey->Object); if (bSuccess && (pDeleteValueKey->ValueName->Length > 0)) { RtlUnicodeStringCatString(&usRegistryPath, L"\\"); RtlUnicodeStringCat(&usRegistryPath, pDeleteValueKey->ValueName); } } break; default: break; } // 创建数据链表 if (usRegistryPath.Length != 0) { PEVENT_DATA_NODE pNode = InitListNode(); HANDLE hProcessId = NULL; hProcessId = PsGetCurrentProcessId(); GetProcessPathBySectionObject(hProcessId, wzProcessPath); ULONG ulProcessPathLength = (ULONG)(wcslen(wzProcessPath) * sizeof(WCHAR) + sizeof(WCHAR)); // 进程的长度 ULONG ulRegistryPathLength = usRegistryPath.Length + sizeof(WCHAR); // 注册表路径的长度 SIZE_T ulNumberOfBytes = sizeof(REGISTRY_EVENT) + ulProcessPathLength + ulRegistryPathLength + ulDataSize; // 总长度=进程+注册表+数据 // 进程路径 pNode->pstRegistryEvent = ExAllocatePoolWithTag(NonPagedPool, ulNumberOfBytes, MEM_TAG); // 给各节点数据赋值 pNode->pstRegistryEvent->hProcessId = hProcessId; pNode->pstRegistryEvent->enRegistryNotifyClass = ulType; pNode->pstRegistryEvent->ulDataLength = ulDataSize; pNode->pstRegistryEvent->ulProcessPathLength = ulProcessPathLength; pNode->pstRegistryEvent->ulRegistryPathLength = ulRegistryPathLength; pNode->pstRegistryEvent->ulKeyValueType = ulKeyValueType; RtlTimeToTimeFields(&unCurrentLocalTime, &pNode->pstRegistryEvent->time); // 时间信息 RtlCopyBytes(pNode->pstRegistryEvent->uData, wzProcessPath, ulProcessPathLength); // 拷贝进程信息 RtlCopyBytes(pNode->pstRegistryEvent->uData + ulProcessPathLength, usRegistryPath.Buffer, usRegistryPath.Length); // 追加注册表路径信息 pNode->pstRegistryEvent->uData[ulProcessPathLength + usRegistryPath.Length + 0] = '\0'; // 给注册表路径后面添加 \0 结束符 pNode->pstRegistryEvent->uData[ulProcessPathLength + usRegistryPath.Length + 1] = '\0'; RtlCopyBytes(pNode->pstRegistryEvent->uData + ulProcessPathLength + ulRegistryPathLength, pData, ulDataSize); // 追加修改的数据信息(如果不是修改值,这里可能为空) ExInterlockedInsertTailList(&g_ListHead, (PLIST_ENTRY)pNode, &g_Lock); KeSetEvent(&g_Event, 0, FALSE); KdPrint(("hProcessId = %ld", hProcessId)); } if (NULL != usRegistryPath.Buffer) { ExFreePoolWithTag(usRegistryPath.Buffer, MEM_TAG); } return status; }
BOOLEAN GetRegistryObjectCompleteName( PUNICODE_STRING pRegistryPath, PUNICODE_STRING pPartialRegistryPath, PVOID pRegistryObject ) { NTSTATUS status; BOOLEAN bFoundCompleteName = FALSE; ULONG ulReturLength; PUNICODE_STRING pObjectName = NULL; if ((!MmIsAddressValid(pRegistryObject)) || (pRegistryObject == NULL)) { return FALSE; } /* 如果 pPartialRegistryPath 不为 NULL,且符合绝对路径规则,则直接返回给外部使用*/ if (pPartialRegistryPath != NULL && pPartialRegistryPath->Length >= 4) { if ((((pPartialRegistryPath->Buffer[0] == '\\') || (pPartialRegistryPath->Buffer[0] == '%')) || ((pPartialRegistryPath->Buffer[0] == 'T') && (pPartialRegistryPath->Buffer[1] == 'R') && (pPartialRegistryPath->Buffer[2] == 'Y') && (pPartialRegistryPath->Buffer[3] == '\\')))) { RtlCopyUnicodeString(pRegistryPath, pPartialRegistryPath); bFoundCompleteName = TRUE; } } /* 如果不符合绝对路径规则,则查询 pRegistryObject 对应的注册表对象和 pPartialRegistryPath 拼接 */ if (!bFoundCompleteName) { status = ObQueryNameString(pRegistryObject, NULL, 0, &ulReturLength); if (status == STATUS_INFO_LENGTH_MISMATCH) { pObjectName = ExAllocatePoolWithTag(NonPagedPool, ulReturLength, MEM_TAG); status = ObQueryNameString(pRegistryObject, (POBJECT_NAME_INFORMATION)pObjectName, ulReturLength, &ulReturLength); if (NT_SUCCESS(status)) { /* 将查询到的注册表对象拷贝到传出参数中 */ RtlCopyUnicodeString(pRegistryPath, pObjectName); /* 如果 pPartialRegistryPath 不为 NULL,则是新建的项名 */ /* 如果为 NULL,则是删除项名,不用拷贝到路径后面。*/ if (NULL != pPartialRegistryPath) { status = RtlUnicodeStringCatString(pRegistryPath, L"\\"); if (!NT_SUCCESS(status)) { KdPrint(("Failed to call RtlUnicodeStringCatString, error code = 0x%08X\r\n", status)); } RtlUnicodeStringCat(pRegistryPath, pPartialRegistryPath); if (!NT_SUCCESS(status)) { KdPrint(("Failed to call RtlUnicodeStringCat, error code = 0x%08X\r\n", status)); } } bFoundCompleteName = TRUE; } ExFreePoolWithTag(pObjectName, MEM_TAG); } } return bFoundCompleteName; }
NTSTATUS RegistryCallback(IN PVOID CallbackContext, IN PVOID Argument1, IN PVOID Argument2) { NTSTATUS st=STATUS_SUCCESS; BOOLEAN exception = FALSE; BOOLEAN flag; int type; UNICODE_STRING registryPath; UCHAR* registryData = NULL; ULONG registryDataLength = 0; ULONG registryDataType = 0; /* Allocate a large 64kb string ... maximum path name allowed in windows */ registryPath.Length = 0; registryPath.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR); registryPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, registryPath.MaximumLength, REGISTRY_POOL_TAG); if(registryPath.Buffer == NULL) { return STATUS_SUCCESS; } //registryEvent.eventType = (REG_NOTIFY_CLASS)Argument1; type = (REG_NOTIFY_CLASS)Argument1; try { /* Large switch statement for all registry events ... fairly easy to understand */ switch(type) { case RegNtPreDeleteKey: { PREG_DELETE_KEY_INFORMATION deleteKey = (PREG_DELETE_KEY_INFORMATION)Argument2; PCM_KEY_BODY my_CM_KEY_BODY=(PCM_KEY_BODY)deleteKey->Object; GetProcessName(aProcessName); flag=GetRegistryObjectCompleteName(®istryPath, NULL, deleteKey->Object); if(flag) { RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE); DbgPrint("[RegCreated]ProcessID %d KeyName %s!\n",PID,astr.Buffer); st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; RtlFreeAnsiString(&astr); } break; } case RegNtPreDeleteValueKey: { PREG_DELETE_VALUE_KEY_INFORMATION deleteValueKey = (PREG_DELETE_VALUE_KEY_INFORMATION)Argument2; PCM_KEY_BODY my_CM_KEY_BODY=(PCM_KEY_BODY)deleteValueKey->Object; GetProcessName(aProcessName); flag=GetRegistryObjectCompleteName(®istryPath, NULL, deleteValueKey->Object); if((flag) && (deleteValueKey->ValueName->Length > 0)) { RtlUnicodeStringCatString(®istryPath,L"\\"); RtlUnicodeStringCat(®istryPath, deleteValueKey->ValueName); RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE); DbgPrint("[RegCreated]ProcessID %d KeyName %s!\n",PID,astr.Buffer); st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; RtlFreeAnsiString(&astr); } break; } case RegNtPreSetValueKey: { PREG_SET_VALUE_KEY_INFORMATION setValueKey = (PREG_SET_VALUE_KEY_INFORMATION)Argument2; PCM_KEY_BODY my_CM_KEY_BODY=(PCM_KEY_BODY)setValueKey->Object; GetProcessName(aProcessName); flag = GetRegistryObjectCompleteName(®istryPath, NULL, setValueKey->Object); if((flag) && (setValueKey->ValueName->Length > 0)) { registryDataType = setValueKey->Type; registryDataLength = setValueKey->DataSize; registryData = ExAllocatePoolWithTag(NonPagedPool, registryDataLength, REGISTRY_POOL_TAG); if(registryData != NULL) { RtlCopyBytes(registryData,setValueKey->Data,setValueKey->DataSize); } else { DbgPrint("RegistryMonitor: ERROR can't allocate memory for setvalue data\n"); } RtlUnicodeStringCatString(®istryPath,L"\\"); RtlUnicodeStringCat(®istryPath, setValueKey->ValueName); RtlUnicodeStringToAnsiString(&astr,®istryPath,TRUE); DbgPrint("[RegCreated]ProcessID %d KeyName %s!\n",PID,astr.Buffer); if (strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")) { st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; } else if (strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServices")) { st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; } else if (strstr(astr.Buffer," \\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce")) { st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; } else if (strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")) { st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; } else if (strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce")) { st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; } else if (strstr(astr.Buffer," \\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")) { st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; } else if (strstr(astr.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce")) { st=WaitForUserAnswer(); if (!NT_SUCCESS(st)) return STATUS_INVALID_PARAMETER; } RtlFreeAnsiString(&astr); } break; } default: break; } } except( EXCEPTION_EXECUTE_HANDLER ) { /* Do nothing if an exception occured ... event won't be queued */ exception = TRUE; } if(registryPath.Buffer != NULL) { ExFreePoolWithTag(registryPath.Buffer, REGISTRY_POOL_TAG); } /* Always return a success ... we aren't doing any filtering, just monitoring */ 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; } }