diff --git a/DriverCommon.h b/DriverCommon.h new file mode 100644 index 0000000..83548e3 --- /dev/null +++ b/DriverCommon.h @@ -0,0 +1,139 @@ +#pragma once +#include +#include +#include +#include +#include + +constexpr auto PYAS_PORT_NAME = L"\\PYAS_Output_Pipe"; +constexpr auto MAX_PATH_LEN = 1024; +constexpr auto PYAS_POOL_TAG = 'SAYP'; + +#ifndef PROCESS_TERMINATE +#define PROCESS_TERMINATE (0x0001) +#endif +#ifndef PROCESS_CREATE_THREAD +#define PROCESS_CREATE_THREAD (0x0002) +#endif +#ifndef PROCESS_VM_OPERATION +#define PROCESS_VM_OPERATION (0x0008) +#endif +#ifndef PROCESS_VM_READ +#define PROCESS_VM_READ (0x0010) +#endif +#ifndef PROCESS_VM_WRITE +#define PROCESS_VM_WRITE (0x0020) +#endif +#ifndef PROCESS_DUP_HANDLE +#define PROCESS_DUP_HANDLE (0x0040) +#endif +#ifndef PROCESS_CREATE_PROCESS +#define PROCESS_CREATE_PROCESS (0x0080) +#endif +#ifndef PROCESS_SET_INFORMATION +#define PROCESS_SET_INFORMATION (0x0200) +#endif +#ifndef PROCESS_QUERY_INFORMATION +#define PROCESS_QUERY_INFORMATION (0x0400) +#endif +#ifndef PROCESS_SUSPEND_RESUME +#define PROCESS_SUSPEND_RESUME (0x0800) +#endif +#ifndef PROCESS_QUERY_LIMITED_INFORMATION +#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) +#endif + +#ifndef POOL_FLAG_NON_PAGED +#define POOL_FLAG_NON_PAGED 0x0000000000000040UI64 +#endif + +#ifndef FSCTL_MANAGE_BYPASS_IO +#define FSCTL_MANAGE_BYPASS_IO CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 188, METHOD_NEITHER, FILE_ANY_ACCESS) + +typedef enum _FS_BPIO_OPERATIONS { + FS_BPIO_OP_ENABLE = 1, + FS_BPIO_OP_DISABLE = 2, + FS_BPIO_OP_QUERY = 3, + FS_BPIO_OP_VOLUME_STACK_PAUSE = 4, + FS_BPIO_OP_VOLUME_STACK_RESUME = 5, + FS_BPIO_OP_STREAM_PAUSE = 6, + FS_BPIO_OP_STREAM_RESUME = 7, + FS_BPIO_OP_GET_INFO = 8 +} FS_BPIO_OPERATIONS; + +typedef struct _FS_BPIO_INPUT { + FS_BPIO_OPERATIONS Operation; + ULONG InFlags; + ULONGLONG Reserved1; + ULONGLONG Reserved2; +} FS_BPIO_INPUT, * PFS_BPIO_INPUT; + +typedef struct _FS_BPIO_OUTPUT { + FS_BPIO_OPERATIONS Operation; + ULONG OutFlags; + ULONGLONG Reserved1; + ULONGLONG Reserved2; + NTSTATUS Status; +} FS_BPIO_OUTPUT, * PFS_BPIO_OUTPUT; + +#endif + +typedef struct _PYAS_MESSAGE { + ULONG MessageCode; + ULONG ProcessId; + WCHAR Path[MAX_PATH_LEN]; +} PYAS_MESSAGE, * PPYAS_MESSAGE; + +typedef struct _DRIVER_DATA { + PDRIVER_OBJECT DriverObject; + PFLT_FILTER FilterHandle; + PFLT_PORT ServerPort; + PFLT_PORT ClientPort; + PEPROCESS PyasProcess; + ULONG PyasPid; + LARGE_INTEGER Cookie; + FAST_MUTEX PortMutex; + FAST_MUTEX TrackerMutex; + EX_RUNDOWN_REF PortRundown; +} DRIVER_DATA, * PDRIVER_DATA; + +extern DRIVER_DATA GlobalData; + +FLT_PREOP_CALLBACK_STATUS ProtectFile_PreCreate(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext); +FLT_PREOP_CALLBACK_STATUS ProtectFile_PreWrite(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext); +FLT_PREOP_CALLBACK_STATUS ProtectFile_PreSetInfo(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext); +FLT_PREOP_CALLBACK_STATUS ProtectFile_FileSystemControl(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext); +FLT_PREOP_CALLBACK_STATUS ProtectBoot_PreDeviceControl(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext); + +NTSTATUS InitializeProcessProtection(); +VOID UninitializeProcessProtection(); +NTSTATUS InitializeRegistryProtection(PDRIVER_OBJECT DriverObject); +VOID UninitializeRegistryProtection(); + +VOID ImageLoadNotify(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo); + +BOOLEAN IsProcessTrusted(HANDLE ProcessId); +BOOLEAN IsTargetProtected(HANDLE ProcessId); +BOOLEAN IsInstallerProcess(HANDLE ProcessId); +BOOLEAN WildcardMatch(PCWSTR Pattern, PCWSTR String, USHORT StringLengthBytes); + +BOOLEAN CheckRegistryRule(PCUNICODE_STRING KeyName); +BOOLEAN CheckFileExtensionRule(PCUNICODE_STRING FileName); +BOOLEAN CheckProtectedPathRule(PCUNICODE_STRING FileName); +BOOLEAN CheckRansomActivity(HANDLE ProcessId, PUNICODE_STRING FileName, PVOID Buffer, ULONG Length, BOOLEAN IsWrite); + +NTSTATUS SendMessageToUser(ULONG Code, ULONG Pid, PWCHAR Path, USHORT PathSize); + +FORCEINLINE PVOID PyasAllocate(SIZE_T Size) { +#if (NTDDI_VERSION >= NTDDI_WIN10_VB) + return ExAllocatePool2(POOL_FLAG_NON_PAGED, Size, PYAS_POOL_TAG); +#else + PVOID Buffer = ExAllocatePoolWithTag(NonPagedPoolNx, Size, PYAS_POOL_TAG); + if (Buffer) RtlZeroMemory(Buffer, Size); + return Buffer; +#endif +} + +FORCEINLINE VOID PyasFree(PVOID Ptr) { + if (Ptr) ExFreePoolWithTag(Ptr, PYAS_POOL_TAG); +} \ No newline at end of file diff --git a/DriverEntry.cpp b/DriverEntry.cpp new file mode 100644 index 0000000..db6c8a0 --- /dev/null +++ b/DriverEntry.cpp @@ -0,0 +1,141 @@ +#include "DriverCommon.h" + +DRIVER_DATA GlobalData; + +static NTSTATUS InstanceSetup(PCFLT_RELATED_OBJECTS FltObjects, FLT_INSTANCE_SETUP_FLAGS Flags, DEVICE_TYPE VolumeDeviceType, FLT_FILESYSTEM_TYPE VolumeFilesystemType) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(VolumeDeviceType); + UNREFERENCED_PARAMETER(VolumeFilesystemType); + return STATUS_SUCCESS; +} + +static NTSTATUS InstanceQueryTeardown(PCFLT_RELATED_OBJECTS FltObjects, FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(Flags); + return STATUS_SUCCESS; +} + +static VOID InstanceTeardownStart(PCFLT_RELATED_OBJECTS FltObjects, FLT_INSTANCE_TEARDOWN_FLAGS Flags) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(Flags); +} + +static VOID InstanceTeardownComplete(PCFLT_RELATED_OBJECTS FltObjects, FLT_INSTANCE_TEARDOWN_FLAGS Flags) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(Flags); +} + +static NTSTATUS DriverUnload(FLT_FILTER_UNLOAD_FLAGS Flags) { + UNREFERENCED_PARAMETER(Flags); + + PsRemoveLoadImageNotifyRoutine(ImageLoadNotify); + UninitializeRegistryProtection(); + UninitializeProcessProtection(); + + ExWaitForRundownProtectionRelease(&GlobalData.PortRundown); + + if (GlobalData.ServerPort) { + FltCloseCommunicationPort(GlobalData.ServerPort); + } + if (GlobalData.FilterHandle) { + FltUnregisterFilter(GlobalData.FilterHandle); + } + return STATUS_SUCCESS; +} + +static NTSTATUS PortConnect(PFLT_PORT ClientPort, PVOID ServerPortCookie, PVOID ConnectionContext, ULONG SizeOfContext, PVOID* ConnectionPortCookie) { + UNREFERENCED_PARAMETER(ServerPortCookie); + UNREFERENCED_PARAMETER(ConnectionContext); + UNREFERENCED_PARAMETER(SizeOfContext); + UNREFERENCED_PARAMETER(ConnectionPortCookie); + + ExAcquireFastMutex(&GlobalData.PortMutex); + + GlobalData.ClientPort = ClientPort; + GlobalData.PyasPid = (ULONG)(ULONG_PTR)PsGetCurrentProcessId(); + GlobalData.PyasProcess = PsGetCurrentProcess(); + + ExReInitializeRundownProtection(&GlobalData.PortRundown); + + ExReleaseFastMutex(&GlobalData.PortMutex); + + return STATUS_SUCCESS; +} + +static VOID PortDisconnect(PVOID ConnectionCookie) { + UNREFERENCED_PARAMETER(ConnectionCookie); + + ExAcquireFastMutex(&GlobalData.PortMutex); + GlobalData.ClientPort = NULL; + GlobalData.PyasPid = 0; + if (GlobalData.PyasProcess) { + GlobalData.PyasProcess = NULL; + } + ExReleaseFastMutex(&GlobalData.PortMutex); + + ExWaitForRundownProtectionRelease(&GlobalData.PortRundown); +} + +CONST FLT_OPERATION_REGISTRATION Callbacks[] = { + { IRP_MJ_CREATE, 0, ProtectFile_PreCreate, NULL }, + { IRP_MJ_WRITE, 0, ProtectFile_PreWrite, NULL }, + { IRP_MJ_SET_INFORMATION, 0, ProtectFile_PreSetInfo, NULL }, + { IRP_MJ_FILE_SYSTEM_CONTROL, 0, ProtectFile_FileSystemControl, NULL }, + { IRP_MJ_DEVICE_CONTROL, 0, ProtectBoot_PreDeviceControl, NULL }, + { IRP_MJ_OPERATION_END } +}; + +CONST FLT_REGISTRATION FilterRegistration = { + sizeof(FLT_REGISTRATION), + FLT_REGISTRATION_VERSION, + 0, + NULL, + Callbacks, + DriverUnload, + InstanceSetup, + InstanceQueryTeardown, + InstanceTeardownStart, + InstanceTeardownComplete, + NULL, + NULL, + NULL +}; + +extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { + UNREFERENCED_PARAMETER(RegistryPath); + + NTSTATUS status = STATUS_SUCCESS; + PSECURITY_DESCRIPTOR sd = NULL; + OBJECT_ATTRIBUTES oa = { 0 }; + UNICODE_STRING name = { 0 }; + + RtlZeroMemory(&GlobalData, sizeof(GlobalData)); + GlobalData.DriverObject = DriverObject; + ExInitializeFastMutex(&GlobalData.PortMutex); + ExInitializeFastMutex(&GlobalData.TrackerMutex); + + ExInitializeRundownProtection(&GlobalData.PortRundown); + + status = FltRegisterFilter(DriverObject, &FilterRegistration, &GlobalData.FilterHandle); + if (!NT_SUCCESS(status)) return status; + + status = FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS); + if (NT_SUCCESS(status)) { + RtlInitUnicodeString(&name, PYAS_PORT_NAME); + InitializeObjectAttributes(&oa, &name, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, sd); + status = FltCreateCommunicationPort(GlobalData.FilterHandle, &GlobalData.ServerPort, &oa, NULL, PortConnect, PortDisconnect, NULL, 1); + FltFreeSecurityDescriptor(sd); + } + + if (!NT_SUCCESS(status)) { + FltUnregisterFilter(GlobalData.FilterHandle); + return status; + } + + InitializeProcessProtection(); + InitializeRegistryProtection(DriverObject); + PsSetLoadImageNotifyRoutine(ImageLoadNotify); + + return FltStartFiltering(GlobalData.FilterHandle); +} \ No newline at end of file diff --git a/ProtectBoot.cpp b/ProtectBoot.cpp new file mode 100644 index 0000000..c1a0233 --- /dev/null +++ b/ProtectBoot.cpp @@ -0,0 +1,34 @@ +#include "DriverCommon.h" + +#ifndef IOCTL_DISK_FORMAT_TRACKS +#define IOCTL_DISK_FORMAT_TRACKS CTL_CODE(IOCTL_DISK_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#endif +#ifndef IOCTL_DISK_FORMAT_TRACKS_EX +#define IOCTL_DISK_FORMAT_TRACKS_EX CTL_CODE(IOCTL_DISK_BASE, 0x000b, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#endif + +FLT_PREOP_CALLBACK_STATUS ProtectBoot_PreDeviceControl(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(CompletionContext); + + if (Data->RequestorMode == KernelMode) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + if (KeGetCurrentIrql() > APC_LEVEL) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + ULONG IoControlCode = Data->Iopb->Parameters.DeviceIoControl.Common.IoControlCode; + + if (IoControlCode == IOCTL_DISK_SET_DRIVE_LAYOUT_EX || + IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT || + IoControlCode == IOCTL_DISK_FORMAT_TRACKS || + IoControlCode == IOCTL_DISK_FORMAT_TRACKS_EX) { + + HANDLE Pid = PsGetCurrentProcessId(); + if (!IsProcessTrusted(Pid) && !IsInstallerProcess(Pid)) { + UNICODE_STRING MsgStr = RTL_CONSTANT_STRING(L"Disk_Wiper_Attempt"); + SendMessageToUser(4001, (ULONG)(ULONG_PTR)Pid, MsgStr.Buffer, MsgStr.Length); + Data->IoStatus.Status = STATUS_ACCESS_DENIED; + return FLT_PREOP_COMPLETE; + } + } + return FLT_PREOP_SUCCESS_NO_CALLBACK; +} \ No newline at end of file diff --git a/ProtectFile.cpp b/ProtectFile.cpp new file mode 100644 index 0000000..1f82bba --- /dev/null +++ b/ProtectFile.cpp @@ -0,0 +1,236 @@ +#include "DriverCommon.h" + +static BOOLEAN IsHoneyToken(PUNICODE_STRING Path) { + if (!Path || !Path->Buffer) return FALSE; + if (WildcardMatch(L"*PYAS_Honey*", Path->Buffer, Path->Length) || + WildcardMatch(L"*Backup_Secret*", Path->Buffer, Path->Length)) { + return TRUE; + } + return FALSE; +} + +FLT_PREOP_CALLBACK_STATUS ProtectFile_PreCreate(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(CompletionContext); + + if (Data->RequestorMode == KernelMode) return FLT_PREOP_SUCCESS_NO_CALLBACK; + if (KeGetCurrentIrql() > APC_LEVEL) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + PFLT_FILE_NAME_INFORMATION nameInfo = NULL; + UNICODE_STRING FileName = { 0 }; + NTSTATUS status = STATUS_SUCCESS; + FLT_PREOP_CALLBACK_STATUS callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; + + status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); + if (!NT_SUCCESS(status) || !nameInfo) { + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + status = FltParseFileNameInformation(nameInfo); + if (!NT_SUCCESS(status)) { + FltReleaseFileNameInformation(nameInfo); + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + FileName = nameInfo->Name; + if (!FileName.Buffer || FileName.Length == 0) { + goto cleanup; + } + + HANDLE Pid = PsGetCurrentProcessId(); + BOOLEAN Trusted = IsProcessTrusted(Pid); + + if (IsHoneyToken(&FileName)) { + if (!Trusted) { + if (Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess & (FILE_WRITE_DATA | DELETE)) { + SendMessageToUser(5001, (ULONG)(ULONG_PTR)Pid, FileName.Buffer, FileName.Length); + Data->IoStatus.Status = STATUS_ACCESS_DENIED; + callbackStatus = FLT_PREOP_COMPLETE; + goto cleanup; + } + } + } + + if (WildcardMatch(L"\\Device\\PhysicalDrive*", FileName.Buffer, FileName.Length) || + (WildcardMatch(L"\\Device\\Harddisk*", FileName.Buffer, FileName.Length) && !WildcardMatch(L"*Volume*", FileName.Buffer, FileName.Length))) { + + if (Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess & + (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE | WRITE_DAC | WRITE_OWNER)) { + + if (!Trusted && !IsInstallerProcess(Pid)) { + UNICODE_STRING MsgStr = RTL_CONSTANT_STRING(L"Disk_Wiper_Attempt"); + SendMessageToUser(4001, (ULONG)(ULONG_PTR)Pid, MsgStr.Buffer, MsgStr.Length); + Data->IoStatus.Status = STATUS_ACCESS_DENIED; + callbackStatus = FLT_PREOP_COMPLETE; + goto cleanup; + } + } + } + + if (CheckProtectedPathRule(&FileName)) { + if (!Trusted) { + if (Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess & (FILE_WRITE_DATA | DELETE | WRITE_DAC | GENERIC_WRITE)) { + SendMessageToUser(2001, (ULONG)(ULONG_PTR)Pid, FileName.Buffer, FileName.Length); + Data->IoStatus.Status = STATUS_ACCESS_DENIED; + callbackStatus = FLT_PREOP_COMPLETE; + goto cleanup; + } + } + } + + if (CheckFileExtensionRule(&FileName)) { + if (!Trusted) { + if (Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess & (DELETE | FILE_DELETE_CHILD)) { + if (CheckRansomActivity(Pid, &FileName, NULL, 0, FALSE)) { + SendMessageToUser(5001, (ULONG)(ULONG_PTR)Pid, FileName.Buffer, FileName.Length); + Data->IoStatus.Status = STATUS_ACCESS_DENIED; + callbackStatus = FLT_PREOP_COMPLETE; + goto cleanup; + } + } + } + } + +cleanup: + if (nameInfo) { + FltReleaseFileNameInformation(nameInfo); + } + return callbackStatus; +} + +FLT_PREOP_CALLBACK_STATUS ProtectFile_PreSetInfo(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(CompletionContext); + + if (Data->RequestorMode == KernelMode) return FLT_PREOP_SUCCESS_NO_CALLBACK; + if (KeGetCurrentIrql() > APC_LEVEL) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + FILE_INFORMATION_CLASS infoClass = Data->Iopb->Parameters.SetFileInformation.FileInformationClass; + + if (infoClass != FileDispositionInformation && + infoClass != FileRenameInformation && + infoClass != FileRenameInformationEx) { + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + PFLT_FILE_NAME_INFORMATION nameInfo = NULL; + NTSTATUS status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); + + if (!NT_SUCCESS(status) || !nameInfo) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + status = FltParseFileNameInformation(nameInfo); + if (!NT_SUCCESS(status) || !nameInfo->Name.Buffer) { + FltReleaseFileNameInformation(nameInfo); + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + HANDLE Pid = PsGetCurrentProcessId(); + if (!IsProcessTrusted(Pid)) { + if (CheckFileExtensionRule(&nameInfo->Name) || CheckProtectedPathRule(&nameInfo->Name)) { + if (CheckRansomActivity(Pid, &nameInfo->Name, NULL, 0, FALSE)) { + SendMessageToUser(5001, (ULONG)(ULONG_PTR)Pid, nameInfo->Name.Buffer, nameInfo->Name.Length); + Data->IoStatus.Status = STATUS_ACCESS_DENIED; + FltReleaseFileNameInformation(nameInfo); + return FLT_PREOP_COMPLETE; + } + } + } + + if (nameInfo) { + FltReleaseFileNameInformation(nameInfo); + } + return FLT_PREOP_SUCCESS_NO_CALLBACK; +} + +FLT_PREOP_CALLBACK_STATUS ProtectFile_PreWrite(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(CompletionContext); + + if (Data->RequestorMode == KernelMode) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + if (Data->Iopb->IrpFlags & (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE)) { + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + ULONG WriteLength = Data->Iopb->Parameters.Write.Length; + if (WriteLength == 0) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + PFLT_FILE_NAME_INFORMATION nameInfo = NULL; + NTSTATUS status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); + + FLT_PREOP_CALLBACK_STATUS callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; + + if (NT_SUCCESS(status) && nameInfo) { + status = FltParseFileNameInformation(nameInfo); + if (NT_SUCCESS(status) && nameInfo->Name.Buffer) { + + if (CheckFileExtensionRule(&nameInfo->Name)) { + HANDLE Pid = PsGetCurrentProcessId(); + + if (!IsProcessTrusted(Pid)) { + + PVOID SystemBuffer = NULL; + PMDL Mdl = Data->Iopb->Parameters.Write.MdlAddress; + + if (!Mdl) { + if (Data->Iopb->Parameters.Write.WriteBuffer && KeGetCurrentIrql() <= APC_LEVEL) { + if (NT_SUCCESS(FltLockUserBuffer(Data))) { + Mdl = Data->Iopb->Parameters.Write.MdlAddress; + } + } + } + + if (Mdl) { + SystemBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority | MdlMappingNoExecute); + } + + if (SystemBuffer) { + if (CheckRansomActivity(Pid, &nameInfo->Name, SystemBuffer, WriteLength, TRUE)) { + if (!IsInstallerProcess(Pid)) { + SendMessageToUser(5001, (ULONG)(ULONG_PTR)Pid, nameInfo->Name.Buffer, nameInfo->Name.Length); + Data->IoStatus.Status = STATUS_ACCESS_DENIED; + callbackStatus = FLT_PREOP_COMPLETE; + } + } + } + } + } + } + FltReleaseFileNameInformation(nameInfo); + } + return callbackStatus; +} + +FLT_PREOP_CALLBACK_STATUS ProtectFile_FileSystemControl(PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID* CompletionContext) { + UNREFERENCED_PARAMETER(FltObjects); + UNREFERENCED_PARAMETER(CompletionContext); + + if (Data->Iopb->Parameters.FileSystemControl.Common.FsControlCode != FSCTL_MANAGE_BYPASS_IO) { + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + PFS_BPIO_INPUT InputBuffer = (PFS_BPIO_INPUT)Data->Iopb->Parameters.FileSystemControl.Neither.InputBuffer; + if (!InputBuffer) return FLT_PREOP_SUCCESS_NO_CALLBACK; + + __try { + if (InputBuffer->Operation == FS_BPIO_OP_ENABLE) { + PFLT_FILE_NAME_INFORMATION nameInfo = NULL; + if (NT_SUCCESS(FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo)) && nameInfo) { + if (NT_SUCCESS(FltParseFileNameInformation(nameInfo))) { + if (CheckFileExtensionRule(&nameInfo->Name) || CheckProtectedPathRule(&nameInfo->Name)) { + + Data->IoStatus.Status = STATUS_NOT_SUPPORTED; + FltReleaseFileNameInformation(nameInfo); + return FLT_PREOP_COMPLETE; + } + } + FltReleaseFileNameInformation(nameInfo); + } + } + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return FLT_PREOP_SUCCESS_NO_CALLBACK; + } + + return FLT_PREOP_SUCCESS_NO_CALLBACK; +} \ No newline at end of file diff --git a/ProtectProcess.cpp b/ProtectProcess.cpp new file mode 100644 index 0000000..8fed8fd --- /dev/null +++ b/ProtectProcess.cpp @@ -0,0 +1,86 @@ +#include "DriverCommon.h" + +PVOID ObRegistrationHandle = NULL; +OB_CALLBACK_REGISTRATION ObRegistration; +OB_OPERATION_REGISTRATION ObCallbacks[1]; + +static BOOLEAN IsSystemImage(PUNICODE_STRING FullImageName) { + if (!FullImageName || !FullImageName->Buffer) return FALSE; + + if (WildcardMatch(L"*\\Windows\\System32\\*", FullImageName->Buffer, FullImageName->Length) || + WildcardMatch(L"*\\Windows\\SysWOW64\\*", FullImageName->Buffer, FullImageName->Length) || + WildcardMatch(L"*\\Windows\\WinSxS\\*", FullImageName->Buffer, FullImageName->Length)) { + return TRUE; + } + return FALSE; +} + +VOID ImageLoadNotify(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo) { + UNREFERENCED_PARAMETER(ImageInfo); + + if (KeGetCurrentIrql() > APC_LEVEL) return; + if (!FullImageName || !FullImageName->Buffer) return; + if (ProcessId == (HANDLE)0) return; + + if (IsSystemImage(FullImageName)) return; + + if (IsTargetProtected(ProcessId)) { + if (CheckFileExtensionRule(FullImageName)) { + SendMessageToUser(6001, (ULONG)(ULONG_PTR)ProcessId, FullImageName->Buffer, FullImageName->Length); + } + } +} + +static OB_PREOP_CALLBACK_STATUS PreOpenProcess(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation) { + UNREFERENCED_PARAMETER(RegistrationContext); + + if (OperationInformation->KernelHandle) return OB_PREOP_SUCCESS; + + PEPROCESS TargetProcess = (PEPROCESS)OperationInformation->Object; + if (!TargetProcess) return OB_PREOP_SUCCESS; + + HANDLE TargetPid = PsGetProcessId(TargetProcess); + HANDLE SourcePid = PsGetCurrentProcessId(); + + if (SourcePid == TargetPid) return OB_PREOP_SUCCESS; + if (IsProcessTrusted(SourcePid)) return OB_PREOP_SUCCESS; + + // Low frequency path, acceptable to check installer here + if (IsInstallerProcess(SourcePid)) return OB_PREOP_SUCCESS; + + BOOLEAN bProtected = IsTargetProtected(TargetPid); + + if (bProtected) { + ACCESS_MASK DenyMask = PROCESS_TERMINATE | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD | PROCESS_VM_READ | PROCESS_DUP_HANDLE; + + OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~DenyMask; + OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess &= ~DenyMask; + } + + return OB_PREOP_SUCCESS; +} + +NTSTATUS InitializeProcessProtection() { + static UNICODE_STRING Altitude = { 0 }; + RtlInitUnicodeString(&Altitude, L"320000"); + + ObCallbacks[0].ObjectType = PsProcessType; + ObCallbacks[0].Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE; + ObCallbacks[0].PreOperation = PreOpenProcess; + ObCallbacks[0].PostOperation = NULL; + + ObRegistration.Version = OB_FLT_REGISTRATION_VERSION; + ObRegistration.OperationRegistrationCount = 1; + ObRegistration.Altitude = Altitude; + ObRegistration.RegistrationContext = NULL; + ObRegistration.OperationRegistration = ObCallbacks; + + return ObRegisterCallbacks(&ObRegistration, &ObRegistrationHandle); +} + +VOID UninitializeProcessProtection() { + if (ObRegistrationHandle) { + ObUnRegisterCallbacks(ObRegistrationHandle); + ObRegistrationHandle = NULL; + } +} \ No newline at end of file diff --git a/ProtectRegistry.cpp b/ProtectRegistry.cpp new file mode 100644 index 0000000..fc0c29a --- /dev/null +++ b/ProtectRegistry.cpp @@ -0,0 +1,51 @@ +#include "DriverCommon.h" + +LARGE_INTEGER Cookie; + +static NTSTATUS RegistryCallback(PVOID CallbackContext, PVOID Argument1, PVOID Argument2) { + UNREFERENCED_PARAMETER(CallbackContext); + + if (KeGetCurrentIrql() > APC_LEVEL) return STATUS_SUCCESS; + + REG_NOTIFY_CLASS Class = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1; + + if (Class == RegNtPreSetValueKey || Class == RegNtPreDeleteKey || Class == RegNtPreCreateKey) { + REG_SET_VALUE_KEY_INFORMATION* Info = (REG_SET_VALUE_KEY_INFORMATION*)Argument2; + PCUNICODE_STRING KeyName = NULL; + + if (!NT_SUCCESS(CmCallbackGetKeyObjectIDEx(&Cookie, Info->Object, NULL, &KeyName, 0))) { + return STATUS_SUCCESS; + } + + if (KeyName && KeyName->Buffer) { + if (CheckRegistryRule(KeyName)) { + HANDLE Pid = PsGetCurrentProcessId(); + if (!IsProcessTrusted(Pid)) { + if (!IsInstallerProcess(Pid)) { + SendMessageToUser(3001, (ULONG)(ULONG_PTR)Pid, KeyName->Buffer, KeyName->Length); + CmCallbackReleaseKeyObjectIDEx(KeyName); + return STATUS_ACCESS_DENIED; + } + } + } + } + + if (KeyName) { + CmCallbackReleaseKeyObjectIDEx(KeyName); + } + } + return STATUS_SUCCESS; +} + +NTSTATUS InitializeRegistryProtection(PDRIVER_OBJECT DriverObject) { + UNICODE_STRING Altitude; + RtlInitUnicodeString(&Altitude, L"320000"); + return CmRegisterCallbackEx(RegistryCallback, &Altitude, DriverObject, NULL, &Cookie, NULL); +} + +VOID UninitializeRegistryProtection() { + if (Cookie.QuadPart != 0) { + CmUnRegisterCallback(Cookie); + Cookie.QuadPart = 0; + } +} \ No newline at end of file diff --git a/ProtectRules.cpp b/ProtectRules.cpp new file mode 100644 index 0000000..49da682 --- /dev/null +++ b/ProtectRules.cpp @@ -0,0 +1,474 @@ +#include "DriverCommon.h" + +constexpr auto MAX_TRACKERS = 64; +constexpr auto RANSOM_TIME_WINDOW_MS = 3000; +constexpr auto RANSOM_COUNT_THRESHOLD = 5; +constexpr auto HIGH_ENTROPY_THRESHOLD = 15; + +typedef struct _RANSOM_TRACKER { + HANDLE ProcessId; + ULONG ActivityCount; + LARGE_INTEGER LastActivityTime; +} RANSOM_TRACKER, * PRANSOM_TRACKER; + +RANSOM_TRACKER RansomTrackers[MAX_TRACKERS]; + +static BOOLEAN HasSuffix(PCUNICODE_STRING String, PCWSTR Suffix) { + if (!String || !String->Buffer || !Suffix) return FALSE; + + SIZE_T SuffixLenBytes = 0; + while (Suffix[SuffixLenBytes / sizeof(WCHAR)] != L'\0') { + SuffixLenBytes += sizeof(WCHAR); + } + + if (String->Length < SuffixLenBytes) return FALSE; + + UNICODE_STRING SuffixPart{}; + SuffixPart.Buffer = (PWCH)((PUCHAR)String->Buffer + String->Length - SuffixLenBytes); + SuffixPart.Length = (USHORT)SuffixLenBytes; + SuffixPart.MaximumLength = (USHORT)SuffixLenBytes; + + UNICODE_STRING TargetSuffix; + RtlInitUnicodeString(&TargetSuffix, Suffix); + + return RtlEqualUnicodeString(&SuffixPart, &TargetSuffix, TRUE); +} + +BOOLEAN WildcardMatch(PCWSTR Pattern, PCWSTR String, USHORT StringLengthBytes) { + if (!Pattern || !String) return FALSE; + + PCWSTR mp = NULL; + PCWSTR cp = NULL; + PCWSTR StringEnd = (PCWSTR)((PUCHAR)String + StringLengthBytes); + + while ((PUCHAR)String < (PUCHAR)StringEnd) { + WCHAR pChar = *Pattern; + WCHAR sChar = *String; + + if (pChar == L'*') { + if (!*++Pattern) return TRUE; + mp = Pattern; + cp = String + 1; + } + else if ((RtlDowncaseUnicodeChar(pChar) == RtlDowncaseUnicodeChar(sChar)) || pChar == L'?') { + Pattern++; + String++; + } + else if (mp) { + Pattern = mp; + String = cp++; + } + else { + return FALSE; + } + } + + while (*Pattern == L'*') Pattern++; + return !*Pattern && ((PUCHAR)String >= (PUCHAR)StringEnd); +} + +const PCWSTR RegistryBlockList[] = { + L"\\REGISTRY\\MACHINE\\BCD00000000\\*", + L"\\REGISTRY\\MACHINE\\SAM\\*", + L"\\REGISTRY\\MACHINE\\SECURITY\\*", + L"\\REGISTRY\\USER\\*_Classes\\*\\shell\\open\\command\\*", + L"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\NetWire\\*", + L"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\Remcos*\\*", + L"\\REGISTRY\\USER\\S-1-*\\SOFTWARE\\DC3_FEXEC\\*", + L"*\\DisableAntiSpyware", + L"*\\DisableWindowsUpdateAccess", + L"*\\EnableLUA", + L"*\\ConsentPromptBehaviorAdmin", + L"*\\NoControlPanel", + L"*\\NoDrives", + L"*\\NoFileMenu", + L"*\\NoFind", + L"*\\NoStartMenuPinnedList", + L"*\\NoSetFolders", + L"*\\NoSetFolderOptions", + L"*\\NoViewOnDrive", + L"*\\NoClose", + L"*\\NoDesktop", + L"*\\NoLogoff", + L"*\\NoFolderOptions", + L"*\\RestrictRun", + L"*\\NoViewContextMenu", + L"*\\HideClock", + L"*\\NoStartMenuMyGames", + L"*\\NoStartMenuMyMusic", + L"*\\DisableCMD", + L"*\\NoAddingComponents", + L"*\\NoWinKeys", + L"*\\NoStartMenuLogOff", + L"*\\NoSimpleNetIDList", + L"*\\NoLowDiskSpaceChecks", + L"*\\DisableLockWorkstation", + L"*\\Restrict_Run", + L"*\\DisableTaskMgr", + L"*\\DisableRegistryTools", + L"*\\DisableChangePassword", + L"*\\Wallpaper", + L"*\\NoComponents", + L"*\\NoStartMenuMorePrograms", + L"*\\NoActiveDesktop", + L"*\\NoSetActiveDesktop", + L"*\\NoRecentDocsMenu", + L"*\\NoWindowsUpdate", + L"*\\NoChangeStartMenu", + L"*\\NoFavoritesMenu", + L"*\\NoRecentDocsHistory", + L"*\\NoSetTaskbar", + L"*\\NoSMHelp", + L"*\\NoTrayContextMenu", + L"*\\NoManageMyComputerVerb", + L"*\\NoRealMode", + L"*\\NoRun", + L"*\\ClearRecentDocsOnExit", + L"*\\NoActiveDesktopChanges", + L"*\\NoStartMenuNetworkPlaces", + L"*\\NoLockScreen", + L"*\\HideFastUserSwitching", + L"*\\ConsentPromptBehaviorUser", + L"*\\EnableSecureUIAPaths", + L"*\\NoSRM", + L"*\\NoInteractiveServices", + L"*\\ShutdownWithoutLogon", + L"*\\AutoAdminLogon", + L"*\\ImagePath", + L"*\\BootExecute", + L"*\\SubSystems", + L"*\\FirmwareBootDevice", + L"*\\BootDriverFlags", + L"*\\SystemStartOptions", + L"*\\CrashDumpEnabled", + L"*\\DisableAutomaticRestartOnFailure", + L"*\\SystemBiosVersion", + L"*\\NoTheme", + L"*\\PendingFileRenameOperations", + L"*\\SystemSetupInProgress", + L"*\\CmdLine", + L"*\\SetupType", + L"*\\AutoReboot", + L"*\\Userinit", + L"*\\UIHost", + L"*\\Debugger", + L"*\\DefaultUserName", + L"*\\DefaultPassword", + L"*\\AltDefaultUserName", + L"*\\AltDefaultPassword", + L"*\\DisableCAD", + L"*\\LegalNoticeCaption", + L"*\\LegalNoticeText", + L"*\\Run", + L"*\\RunOnce", + L"*\\Image File Execution Options\\*" +}; + +const PCWSTR DangerousExtensions[] = { + L".exe", L".dll", L".sys", L".com", L".scr", + L".zip", L".7z", L".rar", L".tar", L".gz", + L".js", L".bat", L".cmd", L".ps1", L".vbs", + L".ppt", L".pptx", L".wps", L".txt", L".rtf", + L".pdf", L".xls", L".xlsx", L".doc", L".docx", + L".jpg", L".jpeg", L".png", L".webp", L".gif", + L".mp3", L".wav", L".aac", L".ogg", L".flac", + L".mp4", L".avi", L".mov", L".wmv", L".mkv", + L".aux", L".cur", L".mui", L".ttf", L".efi" +}; + +const PCWSTR NaturallyCompressedExtensions[] = { + L".zip", L".7z", L".rar", L".tar", L".gz", + L".jpg", L".jpeg", L".png", L".webp", L".gif", + L".mp3", L".wav", L".aac", L".ogg", L".flac", + L".mp4", L".avi", L".mov", L".wmv", L".mkv", + L".exe", L".dll", L".sys", L".mui", + L".docx", L".xlsx", L".pptx", L".odt", L".ods" +}; + +const PCWSTR ProtectedPaths[] = { + L"*\\System32\\drivers\\etc\\hosts", + L"*\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\*", + L"\\Device\\HarddiskVolume*\\Windows\\System32\\*.exe", + L"\\Device\\HarddiskVolume*\\Windows\\System32\\*.dll", + L"\\Device\\HarddiskVolume*\\Windows\\SysWOW64\\*.exe", + L"\\Device\\HarddiskVolume*\\Windows\\SysWOW64\\*.dll", + L"\\Device\\HarddiskVolume*\\bootmgr", + L"\\Device\\HarddiskVolume*\\EFI\\*", + L"*\\PYAS.exe", + L"*\\PYAS_Driver.sys" +}; + +const PCWSTR TrustedInstallerNames[] = { + L"TrustedInstaller.exe", + L"msiexec.exe", + L"svchost.exe", + L"TiWorker.exe", + L"taskhostw.exe" +}; + +BOOLEAN IsProcessTrusted(HANDLE ProcessId) { + if ((ULONG)(ULONG_PTR)ProcessId == GlobalData.PyasPid) return TRUE; + if (ProcessId == (HANDLE)4) return TRUE; + return FALSE; +} + +BOOLEAN IsTargetProtected(HANDLE ProcessId) { + if ((ULONG)(ULONG_PTR)ProcessId == GlobalData.PyasPid) return TRUE; + return FALSE; +} + +BOOLEAN IsInstallerProcess(HANDLE ProcessId) { + if (KeGetCurrentIrql() > APC_LEVEL) return FALSE; + + NTSTATUS status; + BOOLEAN isTrusted = FALSE; + PEPROCESS Process = NULL; + PUNICODE_STRING imageFileName = NULL; + + status = PsLookupProcessByProcessId(ProcessId, &Process); + if (!NT_SUCCESS(status)) return FALSE; + + status = SeLocateProcessImageName(Process, &imageFileName); + + if (NT_SUCCESS(status) && imageFileName) { + if (imageFileName->Buffer) { + for (int i = 0; i < sizeof(TrustedInstallerNames) / sizeof(TrustedInstallerNames[0]); i++) { + if (HasSuffix(imageFileName, TrustedInstallerNames[i])) { + isTrusted = TRUE; + break; + } + } + } + + ExFreePool(imageFileName); + } + + ObDereferenceObject(Process); + return isTrusted; +} + +BOOLEAN CheckRegistryRule(PCUNICODE_STRING KeyName) { + if (!KeyName || !KeyName->Buffer) return FALSE; + for (int i = 0; i < sizeof(RegistryBlockList) / sizeof(RegistryBlockList[0]); i++) { + if (WildcardMatch(RegistryBlockList[i], KeyName->Buffer, KeyName->Length)) return TRUE; + } + return FALSE; +} + +BOOLEAN CheckFileExtensionRule(PCUNICODE_STRING FileName) { + if (!FileName || !FileName->Buffer) return FALSE; + + for (int i = 0; i < sizeof(DangerousExtensions) / sizeof(DangerousExtensions[0]); i++) { + if (HasSuffix(FileName, DangerousExtensions[i])) { + return TRUE; + } + } + return FALSE; +} + +BOOLEAN CheckProtectedPathRule(PCUNICODE_STRING FileName) { + if (!FileName || !FileName->Buffer) return FALSE; + + for (int i = 0; i < sizeof(ProtectedPaths) / sizeof(ProtectedPaths[0]); i++) { + if (WildcardMatch(ProtectedPaths[i], FileName->Buffer, FileName->Length)) return TRUE; + } + return FALSE; +} + +static BOOLEAN IsHighEntropy(PVOID Buffer, ULONG Length) { + if (!Buffer || Length < 256) return FALSE; + + ULONG Histogram[256] = { 0 }; + PUCHAR Ptr = (PUCHAR)Buffer; + ULONG ScanLen = (Length > 1024) ? 1024 : Length; + + __try { + for (ULONG i = 0; i < ScanLen; i++) { + Histogram[Ptr[i]]++; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return FALSE; + } + + ULONG MaxFreq = 0; + for (int i = 0; i < 256; i++) { + if (Histogram[i] > MaxFreq) MaxFreq = Histogram[i]; + } + + ULONG ExpectedAvg = ScanLen / 256; + if (MaxFreq < (ExpectedAvg + HIGH_ENTROPY_THRESHOLD)) { + return TRUE; + } + return FALSE; +} + +static BOOLEAN IsNaturallyCompressed(PCUNICODE_STRING FileName) { + if (!FileName || !FileName->Buffer) return FALSE; + + for (int i = 0; i < sizeof(NaturallyCompressedExtensions) / sizeof(NaturallyCompressedExtensions[0]); i++) { + if (HasSuffix(FileName, NaturallyCompressedExtensions[i])) { + return TRUE; + } + } + return FALSE; +} + +static BOOLEAN IsNoisyRansomPath(PCUNICODE_STRING FileName) { + if (!FileName || !FileName->Buffer) return FALSE; + + if (WildcardMatch(L"*\\Windows\\Temp\\*", FileName->Buffer, FileName->Length) || + WildcardMatch(L"*\\AppData\\Local\\*", FileName->Buffer, FileName->Length) || + WildcardMatch(L"*\\Windows\\SystemTemp\\*", FileName->Buffer, FileName->Length) || + WildcardMatch(L"*$Recycle.Bin*", FileName->Buffer, FileName->Length)) { + return TRUE; + } + return FALSE; +} + +static BOOLEAN IsExplorerProcess(HANDLE ProcessId) { + if (KeGetCurrentIrql() > APC_LEVEL) return FALSE; + + NTSTATUS status; + BOOLEAN isExplorer = FALSE; + PEPROCESS Process = NULL; + PUNICODE_STRING imageFileName = NULL; + + status = PsLookupProcessByProcessId(ProcessId, &Process); + if (!NT_SUCCESS(status)) return FALSE; + + status = SeLocateProcessImageName(Process, &imageFileName); + + if (NT_SUCCESS(status) && imageFileName) { + if (imageFileName->Buffer) { + if (HasSuffix(imageFileName, L"explorer.exe")) { + isExplorer = TRUE; + } + } + ExFreePool(imageFileName); + } + + ObDereferenceObject(Process); + return isExplorer; +} + +BOOLEAN CheckRansomActivity(HANDLE ProcessId, PUNICODE_STRING FileName, PVOID Buffer, ULONG Length, BOOLEAN IsWrite) { + if (IsNoisyRansomPath(FileName)) return FALSE; + + if (!IsWrite) { + if (IsExplorerProcess(ProcessId)) { + return FALSE; + } + } + + LARGE_INTEGER Now = { 0 }; + KeQuerySystemTime(&Now); + BOOLEAN Result = FALSE; + BOOLEAN SuspiciousWrite = FALSE; + + if (IsWrite && Buffer && Length > 0) { + if (!IsNaturallyCompressed(FileName) && IsHighEntropy(Buffer, Length)) { + SuspiciousWrite = TRUE; + } + } + + ExAcquireFastMutex(&GlobalData.TrackerMutex); + + if (IsWrite && !SuspiciousWrite) { + ExReleaseFastMutex(&GlobalData.TrackerMutex); + return FALSE; + } + + PRANSOM_TRACKER Tracker = NULL; + PRANSOM_TRACKER EmptySlot = NULL; + + for (int i = 0; i < MAX_TRACKERS; i++) { + if (RansomTrackers[i].ProcessId == ProcessId) { + Tracker = &RansomTrackers[i]; + break; + } + if (RansomTrackers[i].ProcessId == NULL && !EmptySlot) { + EmptySlot = &RansomTrackers[i]; + } + } + + if (!Tracker) { + if (EmptySlot) { + Tracker = EmptySlot; + Tracker->ProcessId = ProcessId; + Tracker->ActivityCount = 0; + Tracker->LastActivityTime = Now; + } + else { + ExReleaseFastMutex(&GlobalData.TrackerMutex); + return FALSE; + } + } + + LARGE_INTEGER Diff = { 0 }; + Diff.QuadPart = Now.QuadPart - Tracker->LastActivityTime.QuadPart; + + if (Diff.QuadPart > (RANSOM_TIME_WINDOW_MS * 10000LL)) { + Tracker->ActivityCount = 0; + Tracker->LastActivityTime = Now; + } + + ULONG Weight = 1; + if (IsWrite) { + Weight = SuspiciousWrite ? 2 : 1; + } + + Tracker->ActivityCount += Weight; + + if (Tracker->ActivityCount >= RANSOM_COUNT_THRESHOLD) { + Result = TRUE; + } + + ExReleaseFastMutex(&GlobalData.TrackerMutex); + return Result; +} + +NTSTATUS SendMessageToUser(ULONG Code, ULONG Pid, PWCHAR Path, USHORT PathSize) { + if (KeGetCurrentIrql() > APC_LEVEL) return STATUS_UNSUCCESSFUL; + + PYAS_MESSAGE msg; + RtlZeroMemory(&msg, sizeof(msg)); + msg.MessageCode = Code; + msg.ProcessId = Pid; + + if (Path && PathSize > 0) { + size_t MaxSize = sizeof(msg.Path) - sizeof(WCHAR); + size_t BytesToCopy = PathSize; + if (BytesToCopy > MaxSize) { + BytesToCopy = MaxSize; + } + + __try { + RtlCopyMemory(msg.Path, Path, BytesToCopy); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return STATUS_ACCESS_VIOLATION; + } + msg.Path[BytesToCopy / sizeof(WCHAR)] = L'\0'; + } + + if (!ExAcquireRundownProtection(&GlobalData.PortRundown)) { + return STATUS_PORT_DISCONNECTED; + } + + NTSTATUS status = STATUS_SUCCESS; + + if (GlobalData.ClientPort) { + LARGE_INTEGER timeout{}; + timeout.QuadPart = -(5 * 10000); + PFLT_PORT Port = GlobalData.ClientPort; + + status = FltSendMessage(GlobalData.FilterHandle, &Port, &msg, sizeof(msg), NULL, NULL, &timeout); + } + else { + status = STATUS_PORT_DISCONNECTED; + } + + ExReleaseRundownProtection(&GlobalData.PortRundown); + return status; +} \ No newline at end of file