Add files via upload
This commit is contained in:
1 parent
ba4369f829
commit
7f5eb34ac6
7 files changed
+304
-140
No files matched your search
@@ -2,9 +2,8 @@
|
||||
#include <fltKernel.h>
|
||||
#include <ntddk.h>
|
||||
#include <ntdddisk.h>
|
||||
#include <ntddscsi.h>
|
||||
#include <dontuse.h>
|
||||
#include <suppress.h>
|
||||
#include <ntddscsi.h>
|
||||
#include <ntstrsafe.h>
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+151
-64
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user