diff --git a/Plugins/Filter/DriverEntry.c b/Plugins/Filter/DriverEntry.c index b4ba27f..4033fea 100644 --- a/Plugins/Filter/DriverEntry.c +++ b/Plugins/Filter/DriverEntry.c @@ -10,9 +10,10 @@ PDRIVER_OBJECT DiskDrvObj = NULL; KEVENT g_LogDrainEvent; BOOLEAN g_Unloading = FALSE; BOOLEAN g_CmRegActive = FALSE; +EX_RUNDOWN_REF g_Rundown; +PDEVICE_OBJECT g_GuardDevice = NULL; volatile LONG g_LogWorkCount = 0; - static UNICODE_STRING g_DeviceName; static WCHAR g_DeviceNameBuf[64]; static UNICODE_STRING g_SymLink = RTL_CONSTANT_STRING(L"\\??\\PYAS_Driver"); @@ -79,7 +80,7 @@ static NTSTATUS AttachDiskFilters(PDRIVER_OBJECT DriverObject) } status = IoEnumerateDeviceObjectList(DiskDrvObj, list, done * sizeof(PDEVICE_OBJECT), &done); if (!NT_SUCCESS(status)) { - ExFreePool(list); + ExFreePool2(list, 'dskT', NULL, 0); ObDereferenceObject(DiskDrvObj); DiskDrvObj = NULL; return status; @@ -89,6 +90,7 @@ static NTSTATUS AttachDiskFilters(PDRIVER_OBJECT DriverObject) status = IoCreateDevice(DriverObject, 0, NULL, lower->DeviceType, lower->Characteristics, FALSE, &filter); if (!NT_SUCCESS(status)) continue; + filter->Flags |= (lower->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE)); status = IoAttachDeviceToDeviceStackSafe(filter, lower, &attached); if (!NT_SUCCESS(status) || !attached) { @@ -103,22 +105,28 @@ static NTSTATUS AttachDiskFilters(PDRIVER_OBJECT DriverObject) } for (ULONG i = 0; i < done; ++i) ObDereferenceObject(list[i]); - ExFreePool(list); + ExFreePool2(list, 'dskT', NULL, 0); return STATUS_SUCCESS; } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(RegistryPath); - + KeInitializeSpinLock(&g_ProtectLock); ExInitializeFastMutex(&HookMutex); KeInitializeEvent(&g_LogDrainEvent, NotificationEvent, TRUE); g_Unloading = FALSE; g_CmRegActive = FALSE; - + InterlockedExchange(&g_LogWorkCount, 0); - + ExInitializeRundownProtection(&g_Rundown); + { + UNICODE_STRING guardName = RTL_CONSTANT_STRING(L"\\Device\\PYAS_Driver_Guard"); + NTSTATUS gs = IoCreateDevice(DriverObject, 0, &guardName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_GuardDevice); + if (!NT_SUCCESS(gs)) + return STATUS_DEVICE_BUSY; + } { LARGE_INTEGER t = KeQueryPerformanceCounter(NULL); g_DeviceName.Buffer = g_DeviceNameBuf; @@ -126,26 +134,47 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) RtlStringCchPrintfW(g_DeviceName.Buffer, RTL_NUMBER_OF(g_DeviceNameBuf), L"\\Device\\PYAS_Driver_%p_%I64x", DriverObject, t.QuadPart); g_DeviceName.Length = (USHORT)(wcslen(g_DeviceName.Buffer) * sizeof(WCHAR)); } - NTSTATUS status = IoCreateDevice(DriverObject, 0, &g_DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_ControlDeviceObject); - if (!NT_SUCCESS(status)) + if (!NT_SUCCESS(status)) return status; - + DriverObject->DriverUnload = DriverUnload; - for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i) + for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i) DriverObject->MajorFunction[i] = CombinedDispatch; - g_ControlDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; - IoDeleteSymbolicLink(&g_SymLink); - if (NT_SUCCESS(IoCreateSymbolicLink(&g_SymLink, &g_DeviceName))) - g_SymLinkCreated = TRUE; - - UNICODE_STRING alt = RTL_CONSTANT_STRING(L"385100"); - status = CmRegisterCallbackEx(RegistryProtectCallback, &alt, DriverObject, NULL, &g_CmRegHandle, NULL); - if (NT_SUCCESS(status)) - g_CmRegActive = TRUE; - + { + UINT i = 0; + for (; i < 50; ++i) { + status = IoCreateSymbolicLink(&g_SymLink, &g_DeviceName); + if (NT_SUCCESS(status)) + break; + LARGE_INTEGER d = { 0 }; + d.QuadPart = -10LL * 1000LL * 10LL; + KeDelayExecutionThread(KernelMode, FALSE, &d); + IoDeleteSymbolicLink(&g_SymLink); + } + if (!NT_SUCCESS(status)) { + IoDeleteDevice(g_ControlDeviceObject); + g_ControlDeviceObject = NULL; + if (g_GuardDevice) { + IoDeleteDevice(g_GuardDevice); + g_GuardDevice = NULL; + } + return status; + } + } + g_SymLinkCreated = TRUE; + { + static WCHAR regAltBuf[32]; + static UNICODE_STRING regAlt; + LARGE_INTEGER t = KeQueryPerformanceCounter(NULL); + RtlStringCchPrintfW(regAltBuf, RTL_NUMBER_OF(regAltBuf), L"385100.%I64x", t.QuadPart); + RtlInitUnicodeString(®Alt, regAltBuf); + status = CmRegisterCallbackEx(RegistryProtectCallback, ®Alt, DriverObject, NULL, &g_CmRegHandle, NULL); + if (NT_SUCCESS(status)) + g_CmRegActive = TRUE; + } InitImageProtect(); InitInjectProtect(); AttachDiskFilters(DriverObject); @@ -156,15 +185,20 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); g_Unloading = TRUE; - if (g_CmRegActive) { - CmUnRegisterCallback(g_CmRegHandle); - g_CmRegActive = FALSE; + ExWaitForRundownProtectionRelease(&g_Rundown); + if (g_SymLinkCreated) { + IoDeleteSymbolicLink(&g_SymLink); + g_SymLinkCreated = FALSE; + } + if (g_CmRegActive) { + CmUnRegisterCallback(g_CmRegHandle); + g_CmRegActive = FALSE; } UninitInjectProtect(); UninitImageProtect(); if (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) != 0) { KeResetEvent(&g_LogDrainEvent); - while (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) != 0) + while (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) != 0) KeWaitForSingleObject(&g_LogDrainEvent, Executive, KernelMode, FALSE, NULL); } for (ULONG i = 0; i < g_MbrFilterCount; ++i) { @@ -175,15 +209,28 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject) } } g_MbrFilterCount = 0; - IoDeleteSymbolicLink(&g_SymLink); - g_SymLinkCreated = FALSE; - - if (g_ControlDeviceObject) { - IoDeleteDevice(g_ControlDeviceObject); - g_ControlDeviceObject = NULL; + for (;;) { + if (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) == 0 && g_MbrFilterCount == 0 && g_ControlDeviceObject == NULL && DiskDrvObj == NULL) + break; + LARGE_INTEGER d = { 0 }; + d.QuadPart = -10LL * 1000LL * 50LL; + KeDelayExecutionThread(KernelMode, FALSE, &d); + if (DiskDrvObj == NULL && g_ControlDeviceObject != NULL) { + IoDeleteDevice(g_ControlDeviceObject); + g_ControlDeviceObject = NULL; + } + if (DiskDrvObj) { + ObDereferenceObject(DiskDrvObj); + DiskDrvObj = NULL; + } } - if (DiskDrvObj) { - ObDereferenceObject(DiskDrvObj); - DiskDrvObj = NULL; + { + LARGE_INTEGER sd = { 0 }; + sd.QuadPart = -10LL * 1000LL * 300LL; + KeDelayExecutionThread(KernelMode, FALSE, &sd); + } + if (g_GuardDevice) { + IoDeleteDevice(g_GuardDevice); + g_GuardDevice = NULL; } } diff --git a/Plugins/Filter/DriverEntry.h b/Plugins/Filter/DriverEntry.h index ec5b0f9..d530eae 100644 --- a/Plugins/Filter/DriverEntry.h +++ b/Plugins/Filter/DriverEntry.h @@ -6,6 +6,9 @@ #define PIPE_NAME L"\\??\\pipe\\PYAS_Output_Pipe" #define MAX_MBR_TARGETS 52 +#ifndef POOL_FLAG_NON_PAGED +#define POOL_FLAG_NON_PAGED 0x00000001 +#endif #ifndef PROCESS_CREATE_THREAD #define PROCESS_CREATE_THREAD 0x0002 #endif @@ -33,6 +36,9 @@ #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 #endif @@ -57,12 +63,71 @@ extern POBJECT_TYPE* IoDriverObjectType; extern FAST_MUTEX HookMutex; extern PDRIVER_OBJECT DiskDrvObj; extern PCSTR PsGetProcessImageFileName(PEPROCESS Process); +extern EX_RUNDOWN_REF g_Rundown; +extern PDEVICE_OBJECT g_GuardDevice; + +typedef PVOID(NTAPI* _pyas_ExAllocatePool2)(ULONG, SIZE_T, ULONG); +typedef VOID(NTAPI* _pyas_ExFreePool2)(PVOID, ULONG, PVOID, ULONG); +typedef PVOID(NTAPI* _pyas_ExAllocatePoolWithTag)(POOL_TYPE, SIZE_T, ULONG); +typedef VOID(NTAPI* _pyas_ExFreePoolWithTag)(PVOID, ULONG); + +static __forceinline PVOID PYAS_ExAllocatePool2(ULONG f, SIZE_T s, ULONG t) { + static _pyas_ExAllocatePool2 p2 = 0; + if (!p2) { + UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExAllocatePool2"); + p2 = (_pyas_ExAllocatePool2)MmGetSystemRoutineAddress(&n); + } + if (p2) + return p2(f, s, t); + static _pyas_ExAllocatePoolWithTag p1 = 0; + if (!p1) { + UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExAllocatePoolWithTag"); + p1 = (_pyas_ExAllocatePoolWithTag)MmGetSystemRoutineAddress(&n); + } + if (p1) + return p1((f & POOL_FLAG_NON_PAGED) ? NonPagedPoolNx : PagedPool, s, t); + return NULL; +} + +static __forceinline VOID PYAS_ExFreePool2(PVOID a, ULONG t, PVOID h, ULONG f) { + UNREFERENCED_PARAMETER(h); + UNREFERENCED_PARAMETER(f); + static _pyas_ExFreePool2 p2 = 0; + if (!p2) { + UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExFreePool2"); + p2 = (_pyas_ExFreePool2)MmGetSystemRoutineAddress(&n); + } + if (p2) { + p2(a, t, h, f); + return; + } + static _pyas_ExFreePoolWithTag p1 = 0; + if (!p1) { + UNICODE_STRING n = RTL_CONSTANT_STRING(L"ExFreePoolWithTag"); + p1 = (_pyas_ExFreePoolWithTag)MmGetSystemRoutineAddress(&n); + } + if (p1) { + p1(a, t); + return; + } +} + +#define ExAllocatePool2 PYAS_ExAllocatePool2 +#define ExFreePool2 PYAS_ExFreePool2 VOID DriverUnload(PDRIVER_OBJECT DriverObject); VOID SendPipeLog(PCSTR msg, SIZE_T len); VOID UninitImageProtect(VOID); VOID UninitInjectProtect(VOID); +NTSYSAPI NTSTATUS NTAPI ZwQueryInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _Out_writes_bytes_opt_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength +); + NTSTATUS ObReferenceObjectByName( IN PUNICODE_STRING ObjectName, IN ULONG Attributes, diff --git a/Plugins/Filter/DriverPipe.c b/Plugins/Filter/DriverPipe.c index 643dc7b..cb9e932 100644 --- a/Plugins/Filter/DriverPipe.c +++ b/Plugins/Filter/DriverPipe.c @@ -26,8 +26,8 @@ static VOID PipeLogWork(PDEVICE_OBJECT DeviceObject, PVOID Context) ZwClose(h); } IoFreeWorkItem(ctx->Item); - ExFreePool(ctx->Buf); - ExFreePool(ctx); + ExFreePool2(ctx->Buf, 'golP', NULL, 0); + ExFreePool2(ctx, 'golP', NULL, 0); if (InterlockedDecrement(&g_LogWorkCount) == 0 && g_Unloading) KeSetEvent(&g_LogDrainEvent, IO_NO_INCREMENT, FALSE); } @@ -48,15 +48,14 @@ VOID SendPipeLog(PCSTR msg, SIZE_T len) ctx->Len = len; ctx->Buf = (PCHAR)ExAllocatePool2(POOL_FLAG_NON_PAGED, ctx->Len, 'golP'); if (!ctx->Buf) { - ExFreePool(ctx); + ExFreePool2(ctx, 'golP', NULL, 0); return; } - RtlCopyMemory(ctx->Buf, msg, ctx->Len); ctx->Item = IoAllocateWorkItem(g_ControlDeviceObject); if (!ctx->Item) { - ExFreePool(ctx->Buf); - ExFreePool(ctx); + ExFreePool2(ctx->Buf, 'golP', NULL, 0); + ExFreePool2(ctx, 'golP', NULL, 0); return; } InterlockedIncrement(&g_LogWorkCount); diff --git a/Plugins/Filter/ProtectBoot.c b/Plugins/Filter/ProtectBoot.c index a4273b6..fba8828 100644 --- a/Plugins/Filter/ProtectBoot.c +++ b/Plugins/Filter/ProtectBoot.c @@ -14,40 +14,49 @@ NTSTATUS FileProtectDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INVALID_DEVICE_REQUEST; } - if (g_Unloading) { + if (!ExAcquireRundownProtection(&g_Rundown)) { IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(lower, Irp); } + if (g_Unloading) { + IoSkipCurrentIrpStackLocation(Irp); + NTSTATUS st = IoCallDriver(lower, Irp); + ExReleaseRundownProtection(&g_Rundown); + return st; + } PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); if (stack->MajorFunction == IRP_MJ_POWER) { PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); - return PoCallDriver(lower, Irp); + NTSTATUS st = PoCallDriver(lower, Irp); + ExReleaseRundownProtection(&g_Rundown); + return st; } HANDLE pid = PsGetCurrentProcessId(); ULONG currentPid = (ULONG)(ULONG_PTR)pid; if (currentPid == 0 || currentPid == 4) { IoSkipCurrentIrpStackLocation(Irp); - return IoCallDriver(lower, Irp); + NTSTATUS st = IoCallDriver(lower, Irp); + ExReleaseRundownProtection(&g_Rundown); + return st; } BOOLEAN blocked = FALSE, is_white = FALSE; CHAR logbuf[1024] = { 0 }; - + WCHAR exeBuf[512] = { 0 }; UNICODE_STRING exeName = { 0 }; exeName.Buffer = exeBuf; exeName.MaximumLength = sizeof(exeBuf); exeName.Length = 0; - + if (KeGetCurrentIrql() == PASSIVE_LEVEL) { - if (GetProcessImagePathByPid(pid, &exeName)) + if (GetProcessImagePathByPid(pid, &exeName)) is_white = IsWhitelist(&exeName); else { PEPROCESS eproc = PsGetCurrentProcess(); PCSTR n = PsGetProcessImageFileName(eproc); size_t l = n ? strlen(n) : 0; - - for (size_t i = 0; i < l && i < RTL_NUMBER_OF(exeBuf) - 1; i++) + for (size_t i = 0; i < l && i < RTL_NUMBER_OF(exeBuf) - 1; i++) exeBuf[i] = (WCHAR)n[i]; exeBuf[l] = 0; exeName.Length = (USHORT)(l * sizeof(WCHAR)); @@ -65,8 +74,7 @@ NTSTATUS FileProtectDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) } } if (isDisk) { - if (mj == IRP_MJ_WRITE || mj == IRP_MJ_SET_INFORMATION || mj == IRP_MJ_DEVICE_CONTROL || mj == IRP_MJ_INTERNAL_DEVICE_CONTROL) - blocked = TRUE; + if (mj == IRP_MJ_WRITE || mj == IRP_MJ_SET_INFORMATION || mj == IRP_MJ_DEVICE_CONTROL || mj == IRP_MJ_INTERNAL_DEVICE_CONTROL) blocked = TRUE; } } if (blocked) { @@ -74,40 +82,42 @@ NTSTATUS FileProtectDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) CHAR target[64] = "None"; ULONG ret = 0; POBJECT_NAME_INFORMATION oni = (POBJECT_NAME_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, 1024, 'nOmD'); - + if (oni && NT_SUCCESS(ObQueryNameString(lower, oni, 1024, &ret)) && oni->Name.Buffer && oni->Name.Length >= sizeof(WCHAR) * 2) { USHORT len = oni->Name.Length / sizeof(WCHAR); ULONG dr = 0; BOOLEAN hasDr = FALSE; - + for (USHORT i = 0; i + 2 < len; i++) { if (oni->Name.Buffer[i] == L'D' && oni->Name.Buffer[i + 1] == L'R') { USHORT j = i + 2; ULONG x = 0; - + while (j < len && oni->Name.Buffer[j] >= L'0' && oni->Name.Buffer[j] <= L'9') { - x = x * 10 + (oni->Name.Buffer[j] - L'0'); - j++; + x = x * 10 + (oni->Name.Buffer[j] - L'0'); + j++; } dr = x; hasDr = TRUE; break; } } - if (hasDr) + if (hasDr) RtlStringCchPrintfA(target, sizeof(target), "Disk\\Device\\DR%u", dr); } - if (oni) - ExFreePool(oni); + if (oni) + ExFreePool2(oni, 'nOmD', NULL, 0); RtlStringCchPrintfA(logbuf, sizeof(logbuf), "BOOT_BLOCK | %u | %wZ | %s", currentPid, &exeName, target); SendPipeLog(logbuf, strlen(logbuf)); - ZwTerminateProcess(NtCurrentProcess(), STATUS_ACCESS_DENIED); } Irp->IoStatus.Status = STATUS_ACCESS_DENIED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); + ExReleaseRundownProtection(&g_Rundown); return STATUS_ACCESS_DENIED; } IoSkipCurrentIrpStackLocation(Irp); - return IoCallDriver(lower, Irp); + NTSTATUS st = IoCallDriver(lower, Irp); + ExReleaseRundownProtection(&g_Rundown); + return st; } diff --git a/Plugins/Filter/ProtectImage.c b/Plugins/Filter/ProtectImage.c index b7ca233..1ea3c8d 100644 --- a/Plugins/Filter/ProtectImage.c +++ b/Plugins/Filter/ProtectImage.c @@ -91,48 +91,56 @@ static VOID ImageLoadNotify(IN PUNICODE_STRING FullImageName, IN HANDLE ProcessI return; if (ProcessId == (HANDLE)0 || ProcessId == (HANDLE)4) return; - if (KeGetCurrentIrql() != PASSIVE_LEVEL) + if (KeGetCurrentIrql() != PASSIVE_LEVEL) return; - + if (!ExAcquireRundownProtection(&g_Rundown)) + return; + WCHAR exeBuf[512] = { 0 }; UNICODE_STRING exeName = { 0 }; exeName.Buffer = exeBuf; exeName.MaximumLength = sizeof(exeBuf); exeName.Length = 0; - + if (!GetProcessImagePathByPid(ProcessId, &exeName)) { PEPROCESS eproc = PsGetCurrentProcess(); PCSTR n = PsGetProcessImageFileName(eproc); size_t l = n ? strlen(n) : 0; - for (size_t i = 0; i < l && i < RTL_NUMBER_OF(exeBuf) - 1; i++) + + for (size_t i = 0; i < l && i < RTL_NUMBER_OF(exeBuf) - 1; i++) exeBuf[i] = (WCHAR)n[i]; exeBuf[l] = 0; exeName.Length = (USHORT)(l * sizeof(WCHAR)); } + if (exeName.Length & 1) exeName.Length--; { - if (exeName.Length & 1) - exeName.Length--; size_t elen = exeName.Length / sizeof(WCHAR); if ((elen >= 14 && _wcsnicmp(exeName.Buffer + elen - 14, L"powershell.exe", 14) == 0) || - (elen >= 8 && _wcsnicmp(exeName.Buffer + elen - 8, L"pwsh.exe", 8) == 0)) - return; + (elen >= 8 && _wcsnicmp(exeName.Buffer + elen - 8, L"pwsh.exe", 8) == 0)) { + ExReleaseRundownProtection(&g_Rundown); + return; + } + } + if (IsWhitelist(&exeName)) { + ExReleaseRundownProtection(&g_Rundown); + return; } - if (IsWhitelist(&exeName)) - return; - CHAR logbuf[1024] = { 0 }; if (FullImageName && FullImageName->Buffer) { if ((StrStrI(FullImageName->Buffer, L"clr.dll") || StrStrI(FullImageName->Buffer, L"mscorwks.dll")) && !IsFrameworkClrPath(FullImageName->Buffer)) { RtlStringCchPrintfA(logbuf, sizeof(logbuf), "CLR_BLOCK | %u | %wZ | %wZ", (ULONG)(ULONG_PTR)ProcessId, &exeName, FullImageName); SendPipeLog(logbuf, strlen(logbuf)); - ZwTerminateProcess(NtCurrentProcess(), STATUS_ACCESS_DENIED); + ExReleaseRundownProtection(&g_Rundown); + return; } } if (CheckShellcodeWalkStack(8)) { RtlStringCchPrintfA(logbuf, sizeof(logbuf), "SHELLCODE_BLOCK | %u | %wZ | None", (ULONG)(ULONG_PTR)ProcessId, &exeName); SendPipeLog(logbuf, strlen(logbuf)); - ZwTerminateProcess(NtCurrentProcess(), STATUS_ACCESS_DENIED); + ExReleaseRundownProtection(&g_Rundown); + return; } + ExReleaseRundownProtection(&g_Rundown); } NTSTATUS InitImageProtect(VOID) { diff --git a/Plugins/Filter/ProtectInject.c b/Plugins/Filter/ProtectInject.c index 2a7a685..8c88f61 100644 --- a/Plugins/Filter/ProtectInject.c +++ b/Plugins/Filter/ProtectInject.c @@ -11,53 +11,58 @@ static OB_PREOP_CALLBACK_STATUS PreProcessCallback(PVOID RegistrationContext, PO UNREFERENCED_PARAMETER(RegistrationContext); if (g_Unloading) return OB_PREOP_SUCCESS; - if (!Info || Info->KernelHandle) + if (!Info || Info->KernelHandle) return OB_PREOP_SUCCESS; if (!Info->Object) return OB_PREOP_SUCCESS; if (Info->Operation != OB_OPERATION_HANDLE_CREATE && Info->Operation != OB_OPERATION_HANDLE_DUPLICATE) return OB_PREOP_SUCCESS; - + if (!ExAcquireRundownProtection(&g_Rundown)) + return OB_PREOP_SUCCESS; + HANDLE cur = PsGetCurrentProcessId(); - if (cur == (HANDLE)0 || cur == (HANDLE)4) - return OB_PREOP_SUCCESS; - + if (cur == (HANDLE)0 || cur == (HANDLE)4) { + ExReleaseRundownProtection(&g_Rundown); + return OB_PREOP_SUCCESS; + } HANDLE target = PsGetProcessId((PEPROCESS)Info->Object); - if (target == cur) + if (target == cur) { + ExReleaseRundownProtection(&g_Rundown); return OB_PREOP_SUCCESS; - + } ACCESS_MASK* desired = (Info->Operation == OB_OPERATION_HANDLE_CREATE) ? &Info->Parameters->CreateHandleInformation.DesiredAccess : &Info->Parameters->DuplicateHandleInformation.DesiredAccess; ACCESS_MASK mask = PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE; - PCSTR tn = PsGetProcessImageFileName((PEPROCESS)Info->Object); if (tn && (_stricmp(tn, "lsass.exe") == 0)) mask |= PROCESS_VM_READ; - - if ((*desired & mask) == 0) + + if ((*desired & mask) == 0) { + ExReleaseRundownProtection(&g_Rundown); return OB_PREOP_SUCCESS; - + } BOOLEAN logok = (KeGetCurrentIrql() == PASSIVE_LEVEL); WCHAR cbuf[512] = { 0 }, tbuf[512] = { 0 }; UNICODE_STRING cexe = { 0 }, texe = { 0 }; - cexe.Buffer = cbuf; - cexe.MaximumLength = sizeof(cbuf); - texe.Buffer = tbuf; - texe.MaximumLength = sizeof(tbuf); - - if (logok) + cexe.Buffer = cbuf; cexe.MaximumLength = sizeof(cbuf); + texe.Buffer = tbuf; texe.MaximumLength = sizeof(tbuf); + + if (logok) GetProcessImagePathByPid(cur, &cexe); - if (logok && IsWhitelist(&cexe)) - return OB_PREOP_SUCCESS; - + if (logok && IsWhitelist(&cexe)) { + ExReleaseRundownProtection(&g_Rundown); + return OB_PREOP_SUCCESS; + } ACCESS_MASK old = *desired; *desired &= ~mask; if ((*desired) != old && logok) { GetProcessImagePathByPid(target, &texe); + if (cexe.Length == 0) { PEPROCESS eproc = PsGetCurrentProcess(); PCSTR n = PsGetProcessImageFileName(eproc); size_t l = n ? strlen(n) : 0; - for (size_t i = 0; i < l && i < RTL_NUMBER_OF(cbuf) - 1; i++) + + for (size_t i = 0; i < l && i < RTL_NUMBER_OF(cbuf) - 1; i++) cbuf[i] = (WCHAR)n[i]; cbuf[l] = 0; cexe.Length = (USHORT)(l * sizeof(WCHAR)); @@ -65,57 +70,61 @@ static OB_PREOP_CALLBACK_STATUS PreProcessCallback(PVOID RegistrationContext, PO CHAR logbuf[1024] = { 0 }; RtlStringCchPrintfA(logbuf, sizeof(logbuf), "INJECT_BLOCK | %u | %wZ | %wZ", (ULONG)(ULONG_PTR)cur, &cexe, &texe); SendPipeLog(logbuf, strlen(logbuf)); - ZwTerminateProcess(NtCurrentProcess(), STATUS_ACCESS_DENIED); } + ExReleaseRundownProtection(&g_Rundown); return OB_PREOP_SUCCESS; } -static OB_PREOP_CALLBACK_STATUS PreThreadCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION Info) { +static OB_PREOP_CALLBACK_STATUS PreThreadCallback(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION Info) +{ UNREFERENCED_PARAMETER(RegistrationContext); - - if (!Info || Info->KernelHandle) + if (!Info || Info->KernelHandle) return OB_PREOP_SUCCESS; - if (Info->Object == NULL) + if (Info->Object == NULL) return OB_PREOP_SUCCESS; if (Info->Operation != OB_OPERATION_HANDLE_CREATE && Info->Operation != OB_OPERATION_HANDLE_DUPLICATE) return OB_PREOP_SUCCESS; - + if (!ExAcquireRundownProtection(&g_Rundown)) + return OB_PREOP_SUCCESS; + HANDLE cur = PsGetCurrentProcessId(); - if (cur == (HANDLE)0 || cur == (HANDLE)4) - return OB_PREOP_SUCCESS; - + if (cur == (HANDLE)0 || cur == (HANDLE)4) { + ExReleaseRundownProtection(&g_Rundown); + return OB_PREOP_SUCCESS; + } HANDLE owner = PsGetThreadProcessId((PETHREAD)Info->Object); - if (owner == cur) - return OB_PREOP_SUCCESS; - + if (owner == cur) { + ExReleaseRundownProtection(&g_Rundown); + return OB_PREOP_SUCCESS; + } ACCESS_MASK tmask = THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_IMPERSONATE | THREAD_DIRECT_IMPERSONATION; ACCESS_MASK* desired = (Info->Operation == OB_OPERATION_HANDLE_CREATE) ? &Info->Parameters->CreateHandleInformation.DesiredAccess : &Info->Parameters->DuplicateHandleInformation.DesiredAccess; - if ((*desired & tmask) == 0) + if ((*desired & tmask) == 0) { + ExReleaseRundownProtection(&g_Rundown); return OB_PREOP_SUCCESS; - + } BOOLEAN logok = (KeGetCurrentIrql() == PASSIVE_LEVEL); WCHAR cbuf[512] = { 0 }; UNICODE_STRING cexe = { 0 }; - cexe.Buffer = cbuf; cexe.MaximumLength = sizeof(cbuf); - - if (logok) + + if (logok) GetProcessImagePathByPid(cur, &cexe); - if (logok) { - if (IsWhitelist(&cexe)) - return OB_PREOP_SUCCESS; + if (logok && IsWhitelist(&cexe)) { + ExReleaseRundownProtection(&g_Rundown); + return OB_PREOP_SUCCESS; } ACCESS_MASK old = *desired; *desired &= ~tmask; if ((*desired) != old && logok) { CHAR logbuf[1024] = { 0 }; - + if (cexe.Length == 0) { PEPROCESS eproc = PsGetCurrentProcess(); PCSTR n = PsGetProcessImageFileName(eproc); size_t l = n ? strlen(n) : 0; - + for (size_t i = 0; i < l && i < RTL_NUMBER_OF(cbuf) - 1; i++) cbuf[i] = (WCHAR)n[i]; cbuf[l] = 0; @@ -123,14 +132,19 @@ static OB_PREOP_CALLBACK_STATUS PreThreadCallback(PVOID RegistrationContext, POB } RtlStringCchPrintfA(logbuf, sizeof(logbuf), "THREAD_BLOCK | %u | %wZ | %u", (ULONG)(ULONG_PTR)cur, &cexe, (ULONG)(ULONG_PTR)owner); SendPipeLog(logbuf, strlen(logbuf)); - ZwTerminateProcess(NtCurrentProcess(), STATUS_ACCESS_DENIED); } + ExReleaseRundownProtection(&g_Rundown); return OB_PREOP_SUCCESS; } -NTSTATUS InitInjectProtect(VOID) { - UNICODE_STRING alt; - RtlInitUnicodeString(&alt, L"385000"); +NTSTATUS InitInjectProtect(VOID) +{ + static WCHAR obAltBuf[32]; + static UNICODE_STRING obAlt; + LARGE_INTEGER t = KeQueryPerformanceCounter(NULL); + RtlStringCchPrintfW(obAltBuf, RTL_NUMBER_OF(obAltBuf), L"385000.%I64x", t.QuadPart); + RtlInitUnicodeString(&obAlt, obAltBuf); + g_ObOps = (POB_OPERATION_REGISTRATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(OB_OPERATION_REGISTRATION) * 2, 'bOpr'); if (!g_ObOps) return STATUS_INSUFFICIENT_RESOURCES; @@ -146,26 +160,27 @@ NTSTATUS InitInjectProtect(VOID) { RtlZeroMemory(&g_ObReg, sizeof(g_ObReg)); g_ObReg.Version = OB_FLT_REGISTRATION_VERSION; g_ObReg.OperationRegistrationCount = 2; - g_ObReg.Altitude = alt; + g_ObReg.Altitude = obAlt; g_ObReg.RegistrationContext = NULL; g_ObReg.OperationRegistration = g_ObOps; NTSTATUS s = ObRegisterCallbacks(&g_ObReg, &g_ObRegHandle); if (!NT_SUCCESS(s)) { - ExFreePool(g_ObOps); + ExFreePool2(g_ObOps, 'bOpr', NULL, 0); g_ObOps = NULL; RtlZeroMemory(&g_ObReg, sizeof(g_ObReg)); } return s; } -VOID UninitInjectProtect(VOID) { +VOID UninitInjectProtect(VOID) +{ if (g_ObRegHandle) { ObUnRegisterCallbacks(g_ObRegHandle); g_ObRegHandle = NULL; } - if (g_ObOps) { - ExFreePool(g_ObOps); + if (g_ObOps) { + ExFreePool2(g_ObOps, 'bOpr', NULL, 0); g_ObOps = NULL; } RtlZeroMemory(&g_ObReg, sizeof(g_ObReg)); diff --git a/Plugins/Filter/ProtectReg.c b/Plugins/Filter/ProtectReg.c index 72ae9ee..dd18c9d 100644 --- a/Plugins/Filter/ProtectReg.c +++ b/Plugins/Filter/ProtectReg.c @@ -15,7 +15,7 @@ static BOOLEAN QueryRegPathFromObject(PVOID KeyObject, PUNICODE_STRING OutPath, s = ObQueryNameString(KeyObject, p, len, &len); if (!NT_SUCCESS(s) || !p->Name.Buffer || p->Name.Length == 0) { - ExFreePool(p); + ExFreePool2(p, 'rgeR', NULL, 0); return FALSE; } *OutInfo = p; @@ -28,33 +28,36 @@ static BOOLEAN QueryRegPathFromObject(PVOID KeyObject, PUNICODE_STRING OutPath, NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2) { UNREFERENCED_PARAMETER(ctx); - if (g_Unloading) + if (g_Unloading) return STATUS_SUCCESS; - + if (!ExAcquireRundownProtection(&g_Rundown)) + return STATUS_SUCCESS; + REG_NOTIFY_CLASS type = (REG_NOTIFY_CLASS)(ULONG_PTR)arg1; NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING checkReg = { 0 }; POBJECT_NAME_INFORMATION nameInfo = NULL; - + UNICODE_STRING exe = { 0 }; WCHAR exeBuf[260] = { 0 }; exe.Buffer = exeBuf; exe.MaximumLength = sizeof(exeBuf); exe.Length = 0; - + HANDLE pid = PsGetCurrentProcessId(); - if (pid == (HANDLE)0 || pid == (HANDLE)4) - return STATUS_SUCCESS; - + if (pid == (HANDLE)0 || pid == (HANDLE)4) { + ExReleaseRundownProtection(&g_Rundown); + return STATUS_SUCCESS; + } PUNICODE_STRING valueName = NULL; BOOLEAN need_log = FALSE; CHAR logbuf[1024] = { 0 }; BOOLEAN canQuery = (KeGetCurrentIrql() == PASSIVE_LEVEL); - + if (type == RegNtPreSetValueKey) { PREG_SET_VALUE_KEY_INFORMATION s = (PREG_SET_VALUE_KEY_INFORMATION)arg2; valueName = s->ValueName; - if (canQuery) + if (canQuery) QueryRegPathFromObject(s->Object, &checkReg, &nameInfo); } else if (type == RegNtPreDeleteValueKey) { @@ -65,7 +68,7 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2) } else if (type == RegNtPreDeleteKey) { PREG_DELETE_KEY_INFORMATION d = (PREG_DELETE_KEY_INFORMATION)arg2; - if (canQuery) + if (canQuery) QueryRegPathFromObject(d->Object, &checkReg, &nameInfo); } else if (type == RegNtPreRenameKey) { @@ -75,12 +78,12 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2) } else if (type == RegNtPreCreateKeyEx) { PREG_CREATE_KEY_INFORMATION c = (PREG_CREATE_KEY_INFORMATION)arg2; - if (c->CompleteName) + if (c->CompleteName) checkReg = *c->CompleteName; } else if (type == RegNtPreReplaceKey) { PREG_REPLACE_KEY_INFORMATION rk = (PREG_REPLACE_KEY_INFORMATION)arg2; - if (canQuery) + if (canQuery) QueryRegPathFromObject(rk->Object, &checkReg, &nameInfo); } else if (type == RegNtPreSaveKey) { @@ -90,7 +93,7 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2) } else if (type == RegNtPreRestoreKey) { PREG_RESTORE_KEY_INFORMATION res = (PREG_RESTORE_KEY_INFORMATION)arg2; - if (canQuery) + if (canQuery) QueryRegPathFromObject(res->Object, &checkReg, &nameInfo); } else if (type == RegNtPreLoadKey) { @@ -100,17 +103,17 @@ NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2) } if (checkReg.Buffer || (valueName && valueName->Buffer)) { GetProcessImagePathByPid(pid, &exe); + if (IsRegistryBlock(&checkReg, valueName, &exe)) { RtlStringCchPrintfA(logbuf, sizeof(logbuf), "REG_BLOCK | %u | %wZ | %wZ", (ULONG)(ULONG_PTR)pid, &exe, &checkReg); need_log = TRUE; status = STATUS_ACCESS_DENIED; - if (canQuery) - ZwTerminateProcess(NtCurrentProcess(), STATUS_ACCESS_DENIED); } } if (nameInfo) - ExFreePool(nameInfo); + ExFreePool2(nameInfo, 'rgeR', NULL, 0); if (need_log) SendPipeLog(logbuf, strlen(logbuf)); + ExReleaseRundownProtection(&g_Rundown); return status; } diff --git a/Plugins/Filter/ProtectRules.c b/Plugins/Filter/ProtectRules.c index 92f5a31..925b14c 100644 --- a/Plugins/Filter/ProtectRules.c +++ b/Plugins/Filter/ProtectRules.c @@ -260,17 +260,49 @@ static wchar_t* MatchListGetRule(PUNICODE_STRING s, wchar_t** list) return 0; } +static __forceinline BOOLEAN USOK(PUNICODE_STRING s) +{ + return s && s->Buffer && s->Length; +} + BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe) { - if (exe && exe->Buffer && exe->Length) { + if (USOK(exe)) { if (IsWhitelist(exe)) return FALSE; } - if (key && key->Buffer && key->Length) { + if (USOK(exe) && USOK(key)) { + size_t elen = exe->Length / sizeof(WCHAR); + size_t klen = key->Length / sizeof(WCHAR); + if (((elen >= 12 && _wcsnicmp(exe->Buffer + elen - 12, L"services.exe", 12) == 0) || + (elen >= 11 && _wcsnicmp(exe->Buffer + elen - 11, L"svchost.exe", 11) == 0) || + (elen >= 6 && _wcsnicmp(exe->Buffer + elen - 6, L"sc.exe", 6) == 0))) { + if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\SYSTEM\\CurrentControlSet\\Services\\**")) + return FALSE; + } + if ((elen >= 14 && _wcsnicmp(exe->Buffer + elen - 14, L"powershell.exe", 14) == 0) || + (elen >= 8 && _wcsnicmp(exe->Buffer + elen - 8, L"pwsh.exe", 8) == 0)) { + if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Internet Settings\\ZoneMap") || + WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Internet Settings\\ZoneMap\\**")) + return FALSE; + } + if ((elen >= 11 && _wcsnicmp(exe->Buffer + elen - 11, L"msiexec.exe", 11) == 0) || + (elen >= 20 && _wcsnicmp(exe->Buffer + elen - 20, L"TrustedInstaller.exe", 20) == 0)) { + if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Installer\\**") || + WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Uninstall\\**") || + WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\SYSTEM\\CurrentControlSet\\Services\\**")) + return FALSE; + } + if (elen >= 12 && _wcsnicmp(exe->Buffer + elen - 12, L"schtasks.exe", 12) == 0) { + if (WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\**")) + return FALSE; + } + } + if (USOK(key)) { if (MatchBlockReg(key)) return TRUE; } - if (valueName && valueName->Buffer && valueName->Length) { + if (USOK(valueName)) { SIZE_T n = valueName->Length / sizeof(WCHAR); for (SIZE_T i = 0; g_BlockReg[i]; ++i) { wchar_t* pat = g_BlockReg[i]; @@ -291,40 +323,40 @@ BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath) if (!NT_SUCCESS(status)) return FALSE; -#if (NTDDI_VERSION >= NTDDI_WIN10_RS1) - UNICODE_STRING* image = NULL; - status = SeLocateProcessImageName(process, &image); - - if (NT_SUCCESS(status) && image) { - if (ProcessImagePath->MaximumLength >= image->Length + sizeof(WCHAR)) { + HANDLE h = NULL; + status = ObOpenObjectByPointer(process, OBJ_KERNEL_HANDLE, NULL, PROCESS_QUERY_LIMITED_INFORMATION, *PsProcessType, KernelMode, &h); + if (!NT_SUCCESS(status)) { + ObDereferenceObject(process); + return FALSE; + } + ULONG len = 0; + status = ZwQueryInformationProcess(h, ProcessImageFileName, NULL, 0, &len); + if (status != STATUS_INFO_LENGTH_MISMATCH || len == 0) { + ZwClose(h); + ObDereferenceObject(process); + return FALSE; + } + PVOID buf = ExAllocatePool2(POOL_FLAG_NON_PAGED, len, 'iPgN'); + if (!buf) { + ZwClose(h); + ObDereferenceObject(process); + return FALSE; + } + status = ZwQueryInformationProcess(h, ProcessImageFileName, buf, len, &len); + if (NT_SUCCESS(status)) { + PUNICODE_STRING image = (PUNICODE_STRING)buf; + if (image->Buffer && image->Length > 0 && ProcessImagePath->MaximumLength >= image->Length + sizeof(WCHAR)) { RtlCopyMemory(ProcessImagePath->Buffer, image->Buffer, image->Length); ProcessImagePath->Length = image->Length; ProcessImagePath->Buffer[image->Length / sizeof(WCHAR)] = 0; - ExFreePool(image); + ExFreePool2(buf, 'iPgN', NULL, 0); + ZwClose(h); ObDereferenceObject(process); return TRUE; } - ExFreePool(image); - } -#endif - { - PCSTR nameA = PsGetProcessImageFileName(process); - if (nameA) { - ANSI_STRING as; - UNICODE_STRING us = { 0 }; - RtlInitAnsiString(&as, nameA); - - if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&us, &as, TRUE)) && ProcessImagePath->MaximumLength >= us.Length + sizeof(WCHAR)) { - RtlCopyMemory(ProcessImagePath->Buffer, us.Buffer, us.Length); - ProcessImagePath->Length = us.Length; - ProcessImagePath->Buffer[us.Length / sizeof(WCHAR)] = 0; - RtlFreeUnicodeString(&us); - ObDereferenceObject(process); - return TRUE; - } - RtlFreeUnicodeString(&us); - } } + ExFreePool2(buf, 'iPgN', NULL, 0); + ZwClose(h); ObDereferenceObject(process); return FALSE; }