From 7f5eb34ac6454ea652a9157ec74fae2d35ef1b60 Mon Sep 17 00:00:00 2001 From: 87owo <85057800+87owo@users.noreply.github.com> Date: Thu, 1 Jan 2026 17:41:40 +0800 Subject: [PATCH] Add files via upload --- Plugins/Filter/DriverCommon.h | 77 +++++++---- Plugins/Filter/DriverEntry.cpp | 13 +- Plugins/Filter/ProtectBoot.cpp | 5 +- Plugins/Filter/ProtectFile.cpp | 215 ++++++++++++++++++++--------- Plugins/Filter/ProtectProcess.cpp | 13 +- Plugins/Filter/ProtectRegistry.cpp | 25 ++-- Plugins/Filter/ProtectRules.cpp | 96 ++++++++----- 7 files changed, 304 insertions(+), 140 deletions(-) diff --git a/Plugins/Filter/DriverCommon.h b/Plugins/Filter/DriverCommon.h index ef746d5..83548e3 100644 --- a/Plugins/Filter/DriverCommon.h +++ b/Plugins/Filter/DriverCommon.h @@ -2,9 +2,8 @@ #include #include #include -#include -#include -#include +#include +#include constexpr auto PYAS_PORT_NAME = L"\\PYAS_Output_Pipe"; constexpr auto MAX_PATH_LEN = 1024; @@ -13,61 +12,70 @@ 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_SET_SESSIONID -#define PROCESS_SET_SESSIONID (0x0004) -#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_QUOTA -#define PROCESS_SET_QUOTA (0x0100) -#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 PROCESS_SET_LIMITED_INFORMATION -#define PROCESS_SET_LIMITED_INFORMATION (0x2000) +#ifndef POOL_FLAG_NON_PAGED +#define POOL_FLAG_NON_PAGED 0x0000000000000040UI64 #endif -#ifndef PROCESS_ALL_ACCESS -#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF) +#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 { @@ -86,12 +94,15 @@ typedef struct _DRIVER_DATA { 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(); @@ -111,4 +122,18 @@ 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); \ No newline at end of file +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/Plugins/Filter/DriverEntry.cpp b/Plugins/Filter/DriverEntry.cpp index 973765c..db6c8a0 100644 --- a/Plugins/Filter/DriverEntry.cpp +++ b/Plugins/Filter/DriverEntry.cpp @@ -33,6 +33,8 @@ static NTSTATUS DriverUnload(FLT_FILTER_UNLOAD_FLAGS Flags) { UninitializeRegistryProtection(); UninitializeProcessProtection(); + ExWaitForRundownProtectionRelease(&GlobalData.PortRundown); + if (GlobalData.ServerPort) { FltCloseCommunicationPort(GlobalData.ServerPort); } @@ -49,9 +51,13 @@ static NTSTATUS PortConnect(PFLT_PORT ClientPort, PVOID ServerPortCookie, PVOID 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; @@ -67,12 +73,15 @@ static VOID PortDisconnect(PVOID ConnectionCookie) { 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_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 } }; @@ -106,6 +115,8 @@ extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING Reg ExInitializeFastMutex(&GlobalData.PortMutex); ExInitializeFastMutex(&GlobalData.TrackerMutex); + ExInitializeRundownProtection(&GlobalData.PortRundown); + status = FltRegisterFilter(DriverObject, &FilterRegistration, &GlobalData.FilterHandle); if (!NT_SUCCESS(status)) return status; diff --git a/Plugins/Filter/ProtectBoot.cpp b/Plugins/Filter/ProtectBoot.cpp index f2620f7..c1a0233 100644 --- a/Plugins/Filter/ProtectBoot.cpp +++ b/Plugins/Filter/ProtectBoot.cpp @@ -13,6 +13,8 @@ FLT_PREOP_CALLBACK_STATUS ProtectBoot_PreDeviceControl(PFLT_CALLBACK_DATA Data, 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 || @@ -22,7 +24,8 @@ FLT_PREOP_CALLBACK_STATUS ProtectBoot_PreDeviceControl(PFLT_CALLBACK_DATA Data, HANDLE Pid = PsGetCurrentProcessId(); if (!IsProcessTrusted(Pid) && !IsInstallerProcess(Pid)) { - SendMessageToUser(4001, (ULONG)(ULONG_PTR)Pid, L"Disk_Wiper_Attempt"); + 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; } diff --git a/Plugins/Filter/ProtectFile.cpp b/Plugins/Filter/ProtectFile.cpp index 3fb9c74..1f82bba 100644 --- a/Plugins/Filter/ProtectFile.cpp +++ b/Plugins/Filter/ProtectFile.cpp @@ -14,14 +14,15 @@ FLT_PREOP_CALLBACK_STATUS ProtectFile_PreCreate(PFLT_CALLBACK_DATA Data, PCFLT_R 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)) { + if (!NT_SUCCESS(status) || !nameInfo) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } @@ -32,63 +33,112 @@ FLT_PREOP_CALLBACK_STATUS ProtectFile_PreCreate(PFLT_CALLBACK_DATA Data, PCFLT_R } FileName = nameInfo->Name; + if (!FileName.Buffer || FileName.Length == 0) { + goto cleanup; + } - if (FileName.Buffer) { - HANDLE Pid = PsGetCurrentProcessId(); - BOOLEAN Trusted = IsProcessTrusted(Pid); + 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); - FltReleaseFileNameInformation(nameInfo); - Data->IoStatus.Status = STATUS_ACCESS_DENIED; - return FLT_PREOP_COMPLETE; - } + 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) && !wcsstr(FileName.Buffer, L"Volume"))) { + 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 (Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess & + (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE | WRITE_DAC | WRITE_OWNER)) { - if (!Trusted && !IsInstallerProcess(Pid)) { - SendMessageToUser(4001, (ULONG)(ULONG_PTR)Pid, L"Disk_Wiper_Attempt"); - FltReleaseFileNameInformation(nameInfo); - Data->IoStatus.Status = STATUS_ACCESS_DENIED; - return FLT_PREOP_COMPLETE; - } + 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); - FltReleaseFileNameInformation(nameInfo); - Data->IoStatus.Status = STATUS_ACCESS_DENIED; - return FLT_PREOP_COMPLETE; - } + 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); - FltReleaseFileNameInformation(nameInfo); - Data->IoStatus.Status = STATUS_ACCESS_DENIED; - return FLT_PREOP_COMPLETE; - } + 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; } } } } - FltReleaseFileNameInformation(nameInfo); +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; } @@ -96,48 +146,51 @@ FLT_PREOP_CALLBACK_STATUS ProtectFile_PreWrite(PFLT_CALLBACK_DATA Data, PCFLT_RE UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(CompletionContext); - if (KeGetCurrentIrql() > APC_LEVEL) return FLT_PREOP_SUCCESS_NO_CALLBACK; - if (Data->RequestorMode == KernelMode) return FLT_PREOP_SUCCESS_NO_CALLBACK; - if (Data->Iopb->IrpFlags & (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO)) { + 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 = STATUS_SUCCESS; + NTSTATUS status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); - 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)) { + if (NT_SUCCESS(status) && nameInfo) { status = FltParseFileNameInformation(nameInfo); - if (NT_SUCCESS(status)) { + if (NT_SUCCESS(status) && nameInfo->Name.Buffer) { + if (CheckFileExtensionRule(&nameInfo->Name)) { HANDLE Pid = PsGetCurrentProcessId(); + if (!IsProcessTrusted(Pid)) { - PVOID WriteBuffer = NULL; - ULONG WriteLength = Data->Iopb->Parameters.Write.Length; + PVOID SystemBuffer = NULL; + PMDL Mdl = Data->Iopb->Parameters.Write.MdlAddress; - if (WriteLength > 0) { - if (Data->Iopb->Parameters.Write.MdlAddress) { - WriteBuffer = MmGetSystemAddressForMdlSafe(Data->Iopb->Parameters.Write.MdlAddress, NormalPagePriority | MdlMappingNoExecute); - } - else { + if (!Mdl) { + if (Data->Iopb->Parameters.Write.WriteBuffer && KeGetCurrentIrql() <= APC_LEVEL) { if (NT_SUCCESS(FltLockUserBuffer(Data))) { - if (Data->Iopb->Parameters.Write.MdlAddress) { - WriteBuffer = MmGetSystemAddressForMdlSafe(Data->Iopb->Parameters.Write.MdlAddress, NormalPagePriority | MdlMappingNoExecute); - } + Mdl = Data->Iopb->Parameters.Write.MdlAddress; } } } - if (WriteBuffer) { - if (CheckRansomActivity(Pid, &nameInfo->Name, WriteBuffer, WriteLength, TRUE)) { - SendMessageToUser(5001, (ULONG)(ULONG_PTR)Pid, nameInfo->Name.Buffer); - FltReleaseFileNameInformation(nameInfo); - Data->IoStatus.Status = STATUS_ACCESS_DENIED; - return FLT_PREOP_COMPLETE; + 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; + } } } } @@ -145,5 +198,39 @@ FLT_PREOP_CALLBACK_STATUS ProtectFile_PreWrite(PFLT_CALLBACK_DATA Data, PCFLT_RE } 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/Plugins/Filter/ProtectProcess.cpp b/Plugins/Filter/ProtectProcess.cpp index 3ee8f57..8fed8fd 100644 --- a/Plugins/Filter/ProtectProcess.cpp +++ b/Plugins/Filter/ProtectProcess.cpp @@ -7,9 +7,9 @@ OB_OPERATION_REGISTRATION ObCallbacks[1]; static BOOLEAN IsSystemImage(PUNICODE_STRING FullImageName) { if (!FullImageName || !FullImageName->Buffer) return FALSE; - if (wcsstr(FullImageName->Buffer, L"\\Windows\\System32\\") || - wcsstr(FullImageName->Buffer, L"\\Windows\\SysWOW64\\") || - wcsstr(FullImageName->Buffer, L"\\Windows\\WinSxS\\")) { + 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; @@ -18,6 +18,7 @@ static BOOLEAN IsSystemImage(PUNICODE_STRING FullImageName) { 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; @@ -25,7 +26,7 @@ VOID ImageLoadNotify(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INF if (IsTargetProtected(ProcessId)) { if (CheckFileExtensionRule(FullImageName)) { - SendMessageToUser(6001, (ULONG)(ULONG_PTR)ProcessId, FullImageName->Buffer); + SendMessageToUser(6001, (ULONG)(ULONG_PTR)ProcessId, FullImageName->Buffer, FullImageName->Length); } } } @@ -36,11 +37,15 @@ static OB_PREOP_CALLBACK_STATUS PreOpenProcess(PVOID RegistrationContext, POB_PR 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); diff --git a/Plugins/Filter/ProtectRegistry.cpp b/Plugins/Filter/ProtectRegistry.cpp index 9648e30..fc0c29a 100644 --- a/Plugins/Filter/ProtectRegistry.cpp +++ b/Plugins/Filter/ProtectRegistry.cpp @@ -5,27 +5,34 @@ 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; + PCUNICODE_STRING KeyName = NULL; if (!NT_SUCCESS(CmCallbackGetKeyObjectIDEx(&Cookie, Info->Object, NULL, &KeyName, 0))) { return STATUS_SUCCESS; } - if (CheckRegistryRule(KeyName)) { - HANDLE Pid = PsGetCurrentProcessId(); - if (!IsProcessTrusted(Pid)) { - if (!IsInstallerProcess(Pid)) { - SendMessageToUser(3001, (ULONG)(ULONG_PTR)Pid, KeyName->Buffer); - CmCallbackReleaseKeyObjectIDEx(KeyName); - return STATUS_ACCESS_DENIED; + 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; + } } } } - CmCallbackReleaseKeyObjectIDEx(KeyName); + + if (KeyName) { + CmCallbackReleaseKeyObjectIDEx(KeyName); + } } return STATUS_SUCCESS; } diff --git a/Plugins/Filter/ProtectRules.cpp b/Plugins/Filter/ProtectRules.cpp index 431253e..e17a7b6 100644 --- a/Plugins/Filter/ProtectRules.cpp +++ b/Plugins/Filter/ProtectRules.cpp @@ -2,7 +2,7 @@ constexpr auto MAX_TRACKERS = 64; constexpr auto RANSOM_TIME_WINDOW_MS = 3000; -constexpr auto RANSOM_COUNT_THRESHOLD = 3; +constexpr auto RANSOM_COUNT_THRESHOLD = 5; constexpr auto HIGH_ENTROPY_THRESHOLD = 15; typedef struct _RANSOM_TRACKER { @@ -16,7 +16,11 @@ RANSOM_TRACKER RansomTrackers[MAX_TRACKERS]; static BOOLEAN HasSuffix(PCUNICODE_STRING String, PCWSTR Suffix) { if (!String || !String->Buffer || !Suffix) return FALSE; - SIZE_T SuffixLenBytes = wcslen(Suffix) * sizeof(WCHAR); + SIZE_T SuffixLenBytes = 0; + while (Suffix[SuffixLenBytes / sizeof(WCHAR)] != L'\0') { + SuffixLenBytes += sizeof(WCHAR); + } + if (String->Length < SuffixLenBytes) return FALSE; UNICODE_STRING SuffixPart{}; @@ -31,11 +35,13 @@ static BOOLEAN HasSuffix(PCUNICODE_STRING String, PCWSTR Suffix) { } 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 (String < StringEnd && *String) { + while ((PUCHAR)String < (PUCHAR)StringEnd) { WCHAR pChar = *Pattern; WCHAR sChar = *String; @@ -58,7 +64,7 @@ BOOLEAN WildcardMatch(PCWSTR Pattern, PCWSTR String, USHORT StringLengthBytes) { } while (*Pattern == L'*') Pattern++; - return !*Pattern && (String >= StringEnd || !*String); + return !*Pattern && ((PUCHAR)String >= (PUCHAR)StringEnd); } const PCWSTR RegistryBlockList[] = { @@ -212,23 +218,29 @@ BOOLEAN IsTargetProtected(HANDLE ProcessId) { } 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; - PUNICODE_STRING imageFileName; status = SeLocateProcessImageName(Process, &imageFileName); if (NT_SUCCESS(status) && imageFileName) { - for (int i = 0; i < sizeof(TrustedInstallerNames) / sizeof(TrustedInstallerNames[0]); i++) { - if (HasSuffix(imageFileName, TrustedInstallerNames[i])) { - isTrusted = TRUE; - break; + 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); @@ -329,6 +341,11 @@ BOOLEAN CheckRansomActivity(HANDLE ProcessId, PUNICODE_STRING FileName, PVOID Bu ExAcquireFastMutex(&GlobalData.TrackerMutex); + if (IsWrite && !SuspiciousWrite) { + ExReleaseFastMutex(&GlobalData.TrackerMutex); + return FALSE; + } + PRANSOM_TRACKER Tracker = NULL; PRANSOM_TRACKER EmptySlot = NULL; @@ -365,7 +382,7 @@ BOOLEAN CheckRansomActivity(HANDLE ProcessId, PUNICODE_STRING FileName, PVOID Bu ULONG Weight = 1; if (IsWrite) { - Weight = SuspiciousWrite ? RANSOM_COUNT_THRESHOLD : 1; + Weight = SuspiciousWrite ? 2 : 1; } Tracker->ActivityCount += Weight; @@ -378,38 +395,47 @@ BOOLEAN CheckRansomActivity(HANDLE ProcessId, PUNICODE_STRING FileName, PVOID Bu return Result; } -NTSTATUS SendMessageToUser(ULONG Code, ULONG Pid, PWCHAR Path) { - PFLT_PORT LocalClientPort = NULL; - - ExAcquireFastMutex(&GlobalData.PortMutex); - LocalClientPort = GlobalData.ClientPort; - ExReleaseFastMutex(&GlobalData.PortMutex); - - if (!LocalClientPort) { - return STATUS_PORT_DISCONNECTED; - } +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) { - - ULONG CopyLen = 0; - while (CopyLen < MAX_PATH_LEN - 1 && Path[CopyLen] != L'\0') { - __try { - msg.Path[CopyLen] = Path[CopyLen]; - CopyLen++; - } - __except (EXCEPTION_EXECUTE_HANDLER) { - break; - } + if (Path && PathSize > 0) { + size_t MaxSize = sizeof(msg.Path) - sizeof(WCHAR); + size_t BytesToCopy = PathSize; + if (BytesToCopy > MaxSize) { + BytesToCopy = MaxSize; } - msg.Path[CopyLen] = L'\0'; + + __try { + RtlCopyMemory(msg.Path, Path, BytesToCopy); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return STATUS_ACCESS_VIOLATION; + } + msg.Path[BytesToCopy / sizeof(WCHAR)] = L'\0'; } - LARGE_INTEGER timeout{}; - timeout.QuadPart = -(5 * 10000); - return FltSendMessage(GlobalData.FilterHandle, &LocalClientPort, &msg, sizeof(msg), NULL, NULL, &timeout); + 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