From 8295e6bb5bdefa7dd9a9cc5e7899a105ecff06a2 Mon Sep 17 00:00:00 2001 From: PYDT <85057800+87owo@users.noreply.github.com> Date: Fri, 22 Aug 2025 23:13:46 +0800 Subject: [PATCH] Add files via upload --- Plugins/Filter/DriverEntry.c | 47 +++-- Plugins/Filter/DriverEntry.h | 5 + Plugins/Filter/ProtectFile.c | 2 +- Plugins/Filter/ProtectImage.c | 44 +--- Plugins/Filter/ProtectInject.c | 2 +- Plugins/Filter/ProtectMatch.c | 372 +++++++++++++++++++++++++++++++++ Plugins/Filter/ProtectMatch.h | 22 ++ Plugins/Filter/ProtectReg.c | 2 +- Plugins/Filter/ProtectRemote.c | 96 +++++++++ Plugins/Filter/ProtectRules.c | 293 +++++++------------------- Plugins/Filter/ProtectRules.h | 30 ++- Plugins/Filter/ProtectScreen.c | 80 +++++++ 12 files changed, 708 insertions(+), 287 deletions(-) create mode 100644 Plugins/Filter/ProtectMatch.c create mode 100644 Plugins/Filter/ProtectMatch.h create mode 100644 Plugins/Filter/ProtectRemote.c create mode 100644 Plugins/Filter/ProtectScreen.c diff --git a/Plugins/Filter/DriverEntry.c b/Plugins/Filter/DriverEntry.c index 867dbcb..0886503 100644 --- a/Plugins/Filter/DriverEntry.c +++ b/Plugins/Filter/DriverEntry.c @@ -171,19 +171,19 @@ static NTSTATUS AttachFsFilters(PDRIVER_OBJECT DriverObject) 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)) + if (!NT_SUCCESS(gs)) return STATUS_DEVICE_BUSY; } { @@ -194,12 +194,13 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 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); { @@ -208,6 +209,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) status = IoCreateSymbolicLink(&g_SymLink, &g_DeviceName); if (NT_SUCCESS(status)) break; + LARGE_INTEGER d = { 0 }; d.QuadPart = -10LL * 1000LL * 10LL; KeDelayExecutionThread(KernelMode, FALSE, &d); @@ -216,10 +218,7 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) if (!NT_SUCCESS(status)) { IoDeleteDevice(g_ControlDeviceObject); g_ControlDeviceObject = NULL; - if (g_GuardDevice) { - IoDeleteDevice(g_GuardDevice); - g_GuardDevice = NULL; - } + if (g_GuardDevice) { IoDeleteDevice(g_GuardDevice); g_GuardDevice = NULL; } return status; } } @@ -230,32 +229,40 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 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)) + if (NT_SUCCESS(status)) g_CmRegActive = TRUE; } InitImageProtect(); InitInjectProtect(); + InitRemoteProtect(); + InitScreenProtect(); AttachFsFilters(DriverObject); AttachDiskFilters(DriverObject); + return STATUS_SUCCESS; } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); + g_Unloading = TRUE; if (g_SymLinkCreated) { IoDeleteSymbolicLink(&g_SymLink); - g_SymLinkCreated = FALSE; + g_SymLinkCreated = FALSE; } - if (g_CmRegActive) { - CmUnRegisterCallback(g_CmRegHandle); - g_CmRegActive = FALSE; + if (g_CmRegActive) { + CmUnRegisterCallback(g_CmRegHandle); + g_CmRegActive = FALSE; } UninitInjectProtect(); UninitImageProtect(); + UninitRemoteProtect(); + UninitScreenProtect(); ExWaitForRundownProtectionRelease(&g_Rundown); + if (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) != 0) { KeResetEvent(&g_LogDrainEvent); while (InterlockedCompareExchange(&g_LogWorkCount, 0, 0) != 0) @@ -269,16 +276,16 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject) } } g_MbrFilterCount = 0; - if (DiskDrvObj) { - ObDereferenceObject(DiskDrvObj); - DiskDrvObj = NULL; + if (DiskDrvObj) { + ObDereferenceObject(DiskDrvObj); + DiskDrvObj = NULL; } - if (g_ControlDeviceObject) { + if (g_ControlDeviceObject) { IoDeleteDevice(g_ControlDeviceObject); g_ControlDeviceObject = NULL; } if (g_GuardDevice) { IoDeleteDevice(g_GuardDevice); - g_GuardDevice = NULL; + g_GuardDevice = NULL; } } diff --git a/Plugins/Filter/DriverEntry.h b/Plugins/Filter/DriverEntry.h index e4c576b..4a6d889 100644 --- a/Plugins/Filter/DriverEntry.h +++ b/Plugins/Filter/DriverEntry.h @@ -97,6 +97,7 @@ static __forceinline PVOID PYAS_ExAllocatePool2(ULONG f, SIZE_T s, ULONG t) { 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"); @@ -124,6 +125,8 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject); VOID SendPipeLog(PCSTR msg, SIZE_T len); VOID UninitImageProtect(VOID); VOID UninitInjectProtect(VOID); +VOID UninitRemoteProtect(VOID); +VOID UninitScreenProtect(VOID); NTSYSAPI NTSTATUS NTAPI ZwQueryInformationProcess( _In_ HANDLE ProcessHandle, @@ -148,5 +151,7 @@ NTSTATUS FileProtectDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS RegistryProtectCallback(PVOID ctx, PVOID arg1, PVOID arg2); NTSTATUS InitImageProtect(VOID); NTSTATUS InitInjectProtect(VOID); +NTSTATUS InitRemoteProtect(VOID); +NTSTATUS InitScreenProtect(VOID); BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath); diff --git a/Plugins/Filter/ProtectFile.c b/Plugins/Filter/ProtectFile.c index 4c69216..e95c695 100644 --- a/Plugins/Filter/ProtectFile.c +++ b/Plugins/Filter/ProtectFile.c @@ -1,6 +1,6 @@ #include #include "DriverEntry.h" -#include "ProtectRules.h" +#include "ProtectMatch.h" static BOOLEAN GetFilePathFromFileObject(PFILE_OBJECT fo, PUNICODE_STRING out) { diff --git a/Plugins/Filter/ProtectImage.c b/Plugins/Filter/ProtectImage.c index 9c523a3..06a306a 100644 --- a/Plugins/Filter/ProtectImage.c +++ b/Plugins/Filter/ProtectImage.c @@ -1,35 +1,15 @@ #include #include "DriverEntry.h" -#include "ProtectRules.h" +#include "ProtectMatch.h" static BOOLEAN g_ImageNotifyEnabled = FALSE; -static BOOLEAN StrStrI(const wchar_t* s, const wchar_t* sub) -{ - if (!s || !sub) - return FALSE; - size_t n = wcslen(s), m = wcslen(sub); - if (m == 0 || n < m) - return FALSE; - for (size_t i = 0; i + m <= n; i++) { - size_t j = 0; - for (; j < m; j++) { - WCHAR a = s[i + j], b = sub[j]; - if (a >= L'A' && a <= L'Z') a += 32; - if (b >= L'A' && b <= L'Z') b += 32; - if (a != b) break; - } - if (j == m) - return TRUE; - } - return FALSE; -} - static BOOLEAN CheckVadExec(PVOID a) { MEMORY_BASIC_INFORMATION mbi = { 0 }; SIZE_T ret = 0; NTSTATUS s = ZwQueryVirtualMemory(NtCurrentProcess(), a, MemoryBasicInformation, &mbi, sizeof(mbi), &ret); + if (!NT_SUCCESS(s)) return FALSE; if (mbi.State != MEM_COMMIT) @@ -48,9 +28,11 @@ static BOOLEAN WalkForShellcode(ULONG h) ULONG c = RtlWalkFrameChain(frames, MAXWALK, 1); if (c == 0) return FALSE; + ULONG limit = RTL_NUMBER_OF(frames); ULONG count = c < limit ? c : limit; ULONG d = h < count ? h : count; + for (ULONG i = 0; i < d; i++) { PVOID p = frames[i]; if (p && CheckVadExec(p)) @@ -67,25 +49,13 @@ static BOOLEAN WalkForShellcode(ULONG h) return FALSE; } -static BOOLEAN IsFrameworkClrPath(const wchar_t* s) -{ - if (!s) - return FALSE; - if (!StrStrI(s, L"\\Windows\\Microsoft.NET\\")) - return FALSE; - if (!StrStrI(s, L"\\Framework\\") && !StrStrI(s, L"\\Framework64\\")) - return FALSE; - if (StrStrI(s, L"\\clr.dll") || StrStrI(s, L"\\mscorwks.dll")) - return TRUE; - return FALSE; -} - static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2) { ANSI_STRING a1 = { 0 }, a2 = { 0 }; CHAR buf[1024] = { 0 }; RtlUnicodeStringToAnsiString(&a1, s1, TRUE); - if (s2) RtlUnicodeStringToAnsiString(&a2, s2, TRUE); + if (s2) + RtlUnicodeStringToAnsiString(&a2, s2, TRUE); RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : ""); SendPipeLog(buf, strlen(buf)); RtlFreeAnsiString(&a1); @@ -134,7 +104,7 @@ static VOID ImageLoadNotify(IN PUNICODE_STRING FullImageName, IN HANDLE ProcessI return; } if (FullImageName && FullImageName->Buffer) { - if ((StrStrI(FullImageName->Buffer, L"clr.dll") || StrStrI(FullImageName->Buffer, L"mscorwks.dll")) && !IsFrameworkClrPath(FullImageName->Buffer)) { + if (MatchClrFromNonFramework(FullImageName)) { LogAnsi3("CLR_BLOCK", (ULONG)(ULONG_PTR)ProcessId, &exe, FullImageName); ExReleaseRundownProtection(&g_Rundown); return; diff --git a/Plugins/Filter/ProtectInject.c b/Plugins/Filter/ProtectInject.c index 4f6b5ae..74b94ce 100644 --- a/Plugins/Filter/ProtectInject.c +++ b/Plugins/Filter/ProtectInject.c @@ -1,6 +1,6 @@ #include #include "DriverEntry.h" -#include "ProtectRules.h" +#include "ProtectMatch.h" static PVOID g_ObRegHandle = NULL; static POB_OPERATION_REGISTRATION g_ObOps = NULL; diff --git a/Plugins/Filter/ProtectMatch.c b/Plugins/Filter/ProtectMatch.c new file mode 100644 index 0000000..df30d0c --- /dev/null +++ b/Plugins/Filter/ProtectMatch.c @@ -0,0 +1,372 @@ +#include +#include "DriverEntry.h" +#include "ProtectRules.h" +#include "ProtectMatch.h" + +static BOOLEAN WildMatchN(const wchar_t* str, SIZE_T n, const wchar_t* pat) +{ + if (*pat == 0) + return n == 0; + + if (*pat == L'*') { + if (pat[1] == L'*') { + for (SIZE_T i = 0; i <= n; ++i) + if (WildMatchN(str + i, n - i, pat + 2)) + return TRUE; + return FALSE; + } + SIZE_T i = 0; + for (; i < n && str[i] != L'\\'; ++i) + if (WildMatchN(str + i, n - i, pat + 1)) + return TRUE; + return WildMatchN(str + i, n - i, pat + 1); + } + if (*pat == L'?') + return n > 0 && str[0] != L'\\' && WildMatchN(str + 1, n - 1, pat + 1); + if (n == 0) + return FALSE; + + WCHAR sc = str[0], pc = *pat; + if (sc >= L'A' && sc <= L'Z') + sc += 32; + if (pc >= L'A' && pc <= L'Z') + pc += 32; + return sc == pc && WildMatchN(str + 1, n - 1, pat + 1); +} + +static BOOLEAN MatchList(PUNICODE_STRING s, wchar_t** list) +{ + if (!s || !s->Buffer || s->Length == 0) + return FALSE; + + size_t s_len = s->Length / sizeof(WCHAR); + for (SIZE_T i = 0; list[i]; ++i) { + wchar_t* pat = list[i]; + size_t pat_len = wcslen(pat); + if (wcschr(pat, L'*') || wcschr(pat, L'?')) { + if (WildMatchN(s->Buffer, s_len, pat)) + return TRUE; + } + else { + if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) + return TRUE; + if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0) + return TRUE; + if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) + return TRUE; + } + } + return FALSE; +} + +static wchar_t* MatchListGetRule(PUNICODE_STRING s, wchar_t** list) +{ + if (!s || !s->Buffer || s->Length == 0) + return 0; + + size_t s_len = s->Length / sizeof(WCHAR); + for (SIZE_T i = 0; list[i]; ++i) { + wchar_t* pat = list[i]; + size_t pat_len = wcslen(pat); + if (wcschr(pat, L'*') || wcschr(pat, L'?')) { + if (WildMatchN(s->Buffer, s_len, pat)) + return pat; + } + else { + if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) + return pat; + if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0) + return pat; + if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) + return pat; + } + } + return 0; +} + +static __forceinline BOOLEAN USOK(PUNICODE_STRING s) +{ + return s && s->Buffer && s->Length; +} + +static BOOLEAN StrStrIW(const wchar_t* s, const wchar_t* sub) +{ + if (!s || !sub) + return FALSE; + + SIZE_T n = wcslen(s), m = wcslen(sub); + if (m == 0 || n < m) + return FALSE; + + for (SIZE_T i = 0; i + m <= n; i++) { + SIZE_T j = 0; + for (; j < m; j++) { + WCHAR a = s[i + j], b = sub[j]; + if (a >= L'A' && a <= L'Z') a += 32; + if (b >= L'A' && b <= L'Z') b += 32; + if (a != b) break; + } + if (j == m) + return TRUE; + } + return FALSE; +} + +static BOOLEAN EndsWithNameUS(PUNICODE_STRING s, const wchar_t* name) +{ + if (!USOK(s) || !name) + return FALSE; + SIZE_T n = s->Length / sizeof(WCHAR); + SIZE_T m = wcslen(name); + if (n < m) + return FALSE; + return _wcsnicmp(s->Buffer + (n - m), name, m) == 0; +} + +BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe) +{ + if (USOK(key)) { + size_t klen0 = key->Length / sizeof(WCHAR); + if (WildMatchN(key->Buffer, klen0, L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Services\\**")) + return FALSE; + } + if (USOK(exe)) { + if (IsWhitelist(exe)) + return FALSE; + } + 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\\**") || + WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Notifications\\Data") || + WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Notifications\\Data\\**")) + 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 (USOK(valueName)) { + SIZE_T n = valueName->Length / sizeof(WCHAR); + for (SIZE_T i = 0; i < (SIZE_T)-1 && g_BlockReg[i]; ++i) { + wchar_t* pat = g_BlockReg[i]; + if (wcschr(pat, L'\\') || wcschr(pat, L'*') || wcschr(pat, L'?')) + continue; + size_t m = wcslen(pat); + if (n == m && _wcsnicmp(valueName->Buffer, pat, m) == 0) + return TRUE; + } + } + return FALSE; +} + +BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath) +{ + PEPROCESS process = NULL; + NTSTATUS status = PsLookupProcessByProcessId(pid, &process); + if (!NT_SUCCESS(status)) + return FALSE; + + 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; + ExFreePool2(buf, 'iPgN', NULL, 0); + ZwClose(h); + ObDereferenceObject(process); + return TRUE; + } + } + ExFreePool2(buf, 'iPgN', NULL, 0); + ZwClose(h); + ObDereferenceObject(process); + return FALSE; +} + +BOOLEAN IsWhitelist(PUNICODE_STRING s) +{ + if (MatchList(s, g_WhitelistExcept)) + return FALSE; + return MatchList(s, g_Whitelist); +} + +BOOLEAN MatchBlockReg(PUNICODE_STRING s) +{ + return MatchList(s, g_BlockReg); +} + +wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s) +{ + return MatchListGetRule(s, g_BlockReg); +} + +BOOLEAN MatchBlockFile(PUNICODE_STRING s) +{ + return MatchList(s, g_BlockFile); +} + +BOOLEAN MatchBlockRansom(PUNICODE_STRING s) +{ + return MatchList(s, g_BlockRansom); +} + +wchar_t* GetMatchedBlockFileRule(PUNICODE_STRING s) +{ + return MatchListGetRule(s, g_BlockFile); +} + +BOOLEAN HasBlockedSuffix(PUNICODE_STRING s) +{ + if (!USOK(s)) + return FALSE; + SIZE_T n = s->Length / sizeof(WCHAR); + for (SIZE_T i = 0; g_Blocksuffix[i]; ++i) { + wchar_t* ext = g_Blocksuffix[i]; + SIZE_T m = wcslen(ext); + if (n >= m && _wcsnicmp(s->Buffer + (n - m), ext, m) == 0) + return TRUE; + } + return FALSE; +} + +BOOLEAN MatchRemoteSuspectBin(PUNICODE_STRING img) +{ + for (SIZE_T i = 0; g_RemoteSuspectBins[i]; ++i) + if (EndsWithNameUS(img, g_RemoteSuspectBins[i])) + return TRUE; + return FALSE; +} + +BOOLEAN MatchRemoteCommand(PUNICODE_STRING cmd, PUNICODE_STRING img) +{ + if (!USOK(cmd)) + return FALSE; + + const wchar_t* s = cmd->Buffer; + for (SIZE_T i = 0; g_RemoteCmdIndicatorsHttp[i]; ++i) + if (StrStrIW(s, g_RemoteCmdIndicatorsHttp[i])) + return TRUE; + + for (SIZE_T i = 0; g_RemoteCmdIndicatorsGeneric[i]; ++i) + if (StrStrIW(s, g_RemoteCmdIndicatorsGeneric[i])) + return TRUE; + + if (USOK(img) && EndsWithNameUS(img, L"cmd.exe")) { + for (SIZE_T i = 0; g_RemoteCmdFromCmdExe[i]; ++i) + if (StrStrIW(s, g_RemoteCmdFromCmdExe[i])) + return TRUE; + } + if (USOK(img) && EndsWithNameUS(img, L"rundll32.exe")) { + for (SIZE_T i = 0; g_RemoteCmdFromRundll32Exe[i]; ++i) + if (StrStrIW(s, g_RemoteCmdFromRundll32Exe[i])) + return TRUE; + } + if (USOK(img) && EndsWithNameUS(img, L"regsvr32.exe")) { + BOOLEAN need = FALSE, http = FALSE; + for (SIZE_T i = 0; g_RemoteCmdRegsvr32Need[i]; ++i) + if (StrStrIW(s, g_RemoteCmdRegsvr32Need[i])) { + need = TRUE; + break; + } + for (SIZE_T i = 0; g_RemoteCmdIndicatorsHttp[i]; ++i) + if (StrStrIW(s, g_RemoteCmdIndicatorsHttp[i])) { + http = TRUE; + break; + } + if (need && http) + return TRUE; + } + + if (USOK(img) && EndsWithNameUS(img, L"mshta.exe")) { + for (SIZE_T i = 0; g_RemoteCmdFromMshtaExe[i]; ++i) + if (StrStrIW(s, g_RemoteCmdFromMshtaExe[i])) + return TRUE; + } + return FALSE; +} + +BOOLEAN MatchScreenCapModule(PUNICODE_STRING mod) +{ + for (SIZE_T i = 0; g_ScreenCapModules[i]; ++i) + if (EndsWithNameUS(mod, g_ScreenCapModules[i])) + return TRUE; + return FALSE; +} + +BOOLEAN MatchSuspiciousProcPath(PUNICODE_STRING img) +{ + if (!USOK(img)) + return FALSE; + + const wchar_t* s = img->Buffer; + if (StrStrIW(s, L"\\Users\\")) { + for (SIZE_T i = 0; g_ScreenUserSubdirs[i]; ++i) + if (StrStrIW(s, g_ScreenUserSubdirs[i])) + return TRUE; + } + for (SIZE_T i = 0; g_ScreenOtherProcNeedles[i]; ++i) + if (StrStrIW(s, g_ScreenOtherProcNeedles[i])) + return TRUE; + return FALSE; +} + +BOOLEAN MatchClrFromNonFramework(PUNICODE_STRING fullImageName) +{ + if (!USOK(fullImageName)) + return FALSE; + + const wchar_t* s = fullImageName->Buffer; + BOOLEAN isClr = StrStrIW(s, L"\\clr.dll") || StrStrIW(s, L"\\mscorwks.dll"); + + if (!isClr) + return FALSE; + if (!StrStrIW(s, L"\\Windows\\Microsoft.NET\\")) + return TRUE; + if (!StrStrIW(s, L"\\Framework\\") && !StrStrIW(s, L"\\Framework64\\")) + return TRUE; + return FALSE; +} diff --git a/Plugins/Filter/ProtectMatch.h b/Plugins/Filter/ProtectMatch.h new file mode 100644 index 0000000..b4e3dbb --- /dev/null +++ b/Plugins/Filter/ProtectMatch.h @@ -0,0 +1,22 @@ +#pragma once +#include + +wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s); +wchar_t* GetMatchedBlockFileRule(PUNICODE_STRING s); + +BOOLEAN IsWhitelist(PUNICODE_STRING s); +BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath); + +BOOLEAN MatchBlockReg(PUNICODE_STRING s); +BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe); + +BOOLEAN MatchBlockFile(PUNICODE_STRING s); +BOOLEAN MatchBlockRansom(PUNICODE_STRING s); +BOOLEAN HasBlockedSuffix(PUNICODE_STRING s); + +BOOLEAN MatchRemoteSuspectBin(PUNICODE_STRING img); +BOOLEAN MatchRemoteCommand(PUNICODE_STRING cmd, PUNICODE_STRING img); + +BOOLEAN MatchScreenCapModule(PUNICODE_STRING mod); +BOOLEAN MatchSuspiciousProcPath(PUNICODE_STRING img); +BOOLEAN MatchClrFromNonFramework(PUNICODE_STRING fullImageName); diff --git a/Plugins/Filter/ProtectReg.c b/Plugins/Filter/ProtectReg.c index 1ad83f9..40d8d77 100644 --- a/Plugins/Filter/ProtectReg.c +++ b/Plugins/Filter/ProtectReg.c @@ -1,6 +1,6 @@ #include -#include "ProtectRules.h" #include "DriverEntry.h" +#include "ProtectMatch.h" static BOOLEAN QueryRegPathFromObject(PVOID KeyObject, PUNICODE_STRING OutPath, POBJECT_NAME_INFORMATION* OutInfo) { diff --git a/Plugins/Filter/ProtectRemote.c b/Plugins/Filter/ProtectRemote.c new file mode 100644 index 0000000..bdf1ef2 --- /dev/null +++ b/Plugins/Filter/ProtectRemote.c @@ -0,0 +1,96 @@ +#include +#include "DriverEntry.h" +#include "ProtectMatch.h" + +static BOOLEAN g_RemoteNotifyEnabled = FALSE; + +static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2) +{ + ANSI_STRING a1 = { 0 }, a2 = { 0 }; + CHAR buf[1024] = { 0 }; + RtlUnicodeStringToAnsiString(&a1, s1, TRUE); + if (s2) + RtlUnicodeStringToAnsiString(&a2, s2, TRUE); + RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : ""); + SendPipeLog(buf, strlen(buf)); + RtlFreeAnsiString(&a1); + RtlFreeAnsiString(&a2); +} + +static VOID ProcessNotifyEx(PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo) +{ + UNREFERENCED_PARAMETER(Process); + UNREFERENCED_PARAMETER(ProcessId); + + if (!CreateInfo) + return; + if (g_Unloading) + return; + if (KeGetCurrentIrql() != PASSIVE_LEVEL) + return; + if (!ExAcquireRundownProtection(&g_Rundown)) + return; + + HANDLE ppid = CreateInfo->CreatingThreadId.UniqueProcess; + if (ppid == (HANDLE)0 || ppid == (HANDLE)4) { + ExReleaseRundownProtection(&g_Rundown); + return; + } + UNICODE_STRING parent = { 0 }; + WCHAR pbuf[512] = { 0 }; + parent.Buffer = pbuf; + parent.MaximumLength = sizeof(pbuf); + + if (!GetProcessImagePathByPid(ppid, &parent)) { + 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(pbuf) - 1; i++) + pbuf[i] = (WCHAR)n[i]; + pbuf[l] = 0; + parent.Length = (USHORT)(l * sizeof(WCHAR)); + } + if (IsWhitelist(&parent)) { + ExReleaseRundownProtection(&g_Rundown); + return; + } + UNICODE_STRING img = { 0 }; + if (CreateInfo->ImageFileName) + img = *CreateInfo->ImageFileName; + UNICODE_STRING cmd = { 0 }; + if (CreateInfo->CommandLine) + cmd = *CreateInfo->CommandLine; + + BOOLEAN suspect = FALSE; + if (MatchRemoteSuspectBin(&img) && MatchRemoteCommand(&cmd, &img)) + suspect = TRUE; + + if (suspect) { + CreateInfo->CreationStatus = STATUS_ACCESS_DENIED; + if (cmd.Buffer && cmd.Length) + LogAnsi3("REMOTE_BLOCK", (ULONG)(ULONG_PTR)ppid, &parent, &cmd); + else if (img.Buffer && img.Length) + LogAnsi3("REMOTE_BLOCK", (ULONG)(ULONG_PTR)ppid, &parent, &img); + else { + UNICODE_STRING none = RTL_CONSTANT_STRING(L"None"); + LogAnsi3("REMOTE_BLOCK", (ULONG)(ULONG_PTR)ppid, &parent, &none); + } + } + ExReleaseRundownProtection(&g_Rundown); +} + +NTSTATUS InitRemoteProtect(VOID) +{ + NTSTATUS s = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyEx, FALSE); + if (NT_SUCCESS(s)) + g_RemoteNotifyEnabled = TRUE; + return s; +} + +VOID UninitRemoteProtect(VOID) +{ + if (g_RemoteNotifyEnabled) { + PsSetCreateProcessNotifyRoutineEx(ProcessNotifyEx, TRUE); + g_RemoteNotifyEnabled = FALSE; + } +} diff --git a/Plugins/Filter/ProtectRules.c b/Plugins/Filter/ProtectRules.c index 6210aa1..0f81ac2 100644 --- a/Plugins/Filter/ProtectRules.c +++ b/Plugins/Filter/ProtectRules.c @@ -1,5 +1,4 @@ #include -#include "DriverEntry.h" #include "ProtectRules.h" wchar_t* g_Whitelist[] = { @@ -209,228 +208,88 @@ wchar_t* g_BlockReg[] = { NULL }; -static BOOLEAN WildMatchN(const wchar_t* str, SIZE_T n, const wchar_t* pat) -{ - if (*pat == 0) - return n == 0; - if (*pat == L'*') { - if (pat[1] == L'*') { - for (SIZE_T i = 0; i <= n; ++i) - if (WildMatchN(str + i, n - i, pat + 2)) - return TRUE; - return FALSE; - } - SIZE_T i = 0; - for (; i < n && str[i] != L'\\'; ++i) - if (WildMatchN(str + i, n - i, pat + 1)) - return TRUE; - return WildMatchN(str + i, n - i, pat + 1); - } - if (*pat == L'?') - return n > 0 && str[0] != L'\\' && WildMatchN(str + 1, n - 1, pat + 1); - if (n == 0) - return FALSE; - WCHAR sc = str[0], pc = *pat; - if (sc >= L'A' && sc <= L'Z') - sc += 32; - if (pc >= L'A' && pc <= L'Z') - pc += 32; - return sc == pc && WildMatchN(str + 1, n - 1, pat + 1); -} +wchar_t* g_RemoteSuspectBins[] = { + L"powershell.exe", + L"pwsh.exe", + L"wscript.exe", + L"cscript.exe", + L"mshta.exe", + L"rundll32.exe", + L"regsvr32.exe", + L"cmd.exe", + L"bitsadmin.exe", + L"msbuild.exe", + L"installutil.exe", + L"wmic.exe", + NULL +}; -static BOOLEAN MatchList(PUNICODE_STRING s, wchar_t** list) -{ - if (!s || !s->Buffer || s->Length == 0) - return FALSE; - size_t s_len = s->Length / sizeof(WCHAR); - for (SIZE_T i = 0; list[i]; ++i) { - wchar_t* pat = list[i]; - size_t pat_len = wcslen(pat); - if (wcschr(pat, L'*') || wcschr(pat, L'?')) { - if (WildMatchN(s->Buffer, s_len, pat)) - return TRUE; - } - else { - if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) - return TRUE; - if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0) - return TRUE; - if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) - return TRUE; - } - } - return FALSE; -} +wchar_t* g_RemoteCmdIndicatorsHttp[] = { + L"http://", + L"https://", + NULL +}; -static wchar_t* MatchListGetRule(PUNICODE_STRING s, wchar_t** list) -{ - if (!s || !s->Buffer || s->Length == 0) - return 0; - size_t s_len = s->Length / sizeof(WCHAR); - for (SIZE_T i = 0; list[i]; ++i) { - wchar_t* pat = list[i]; - size_t pat_len = wcslen(pat); - if (wcschr(pat, L'*') || wcschr(pat, L'?')) { - if (WildMatchN(s->Buffer, s_len, pat)) - return pat; - } - else { - if (s_len == pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) - return pat; - if (s_len > pat_len && _wcsnicmp(s->Buffer + s_len - pat_len, pat, pat_len) == 0) - return pat; - if (s_len > pat_len && _wcsnicmp(s->Buffer, pat, pat_len) == 0) - return pat; - } - } - return 0; -} +wchar_t* g_RemoteCmdIndicatorsGeneric[] = { + L"-enc", + L" -e ", + L"-encodedcommand", + L"frombase64string(", + L"iex(", + L"downloadstring(", + NULL +}; -static __forceinline BOOLEAN USOK(PUNICODE_STRING s) -{ - return s && s->Buffer && s->Length; -} +wchar_t* g_RemoteCmdFromCmdExe[] = { + L"powershell", + L"pwsh", + L"mshta", + L"rundll32", + L"wscript", + L"cscript", + NULL +}; -BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe) -{ - if (USOK(exe)) { - if (IsWhitelist(exe)) - return FALSE; - } - 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\\**") || - WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Notifications\\Data") || - WildMatchN(key->Buffer, klen, L"\\REGISTRY\\**\\CurrentVersion\\Notifications\\Data\\**")) - 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 (USOK(valueName)) { - SIZE_T n = valueName->Length / sizeof(WCHAR); - for (SIZE_T i = 0; g_BlockReg[i]; ++i) { - wchar_t* pat = g_BlockReg[i]; - if (wcschr(pat, L'\\') || wcschr(pat, L'*') || wcschr(pat, L'?')) - continue; - size_t m = wcslen(pat); - if (n == m && _wcsnicmp(valueName->Buffer, pat, m) == 0) - return TRUE; - } - } - return FALSE; -} +wchar_t* g_RemoteCmdFromRundll32Exe[] = { + L".dll,", + L"javascript:", + L"http", + NULL +}; -BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath) -{ - PEPROCESS process = NULL; - NTSTATUS status = PsLookupProcessByProcessId(pid, &process); - if (!NT_SUCCESS(status)) - return FALSE; +wchar_t* g_RemoteCmdRegsvr32Need[] = { + L"/i:", + NULL +}; - 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; - ExFreePool2(buf, 'iPgN', NULL, 0); - ZwClose(h); - ObDereferenceObject(process); - return TRUE; - } - } - ExFreePool2(buf, 'iPgN', NULL, 0); - ZwClose(h); - ObDereferenceObject(process); - return FALSE; -} +wchar_t* g_RemoteCmdFromMshtaExe[] = { + L"http://", + L"https://", + NULL +}; -BOOLEAN IsWhitelist(PUNICODE_STRING s) -{ - if (MatchList(s, g_WhitelistExcept)) - return FALSE; - return MatchList(s, g_Whitelist); -} +wchar_t* g_ScreenCapModules[] = { + L"windows.graphics.capture.dll", + L"dxgi.dll", + L"d3d11.dll", + L"dwmapi.dll", + L"dcomp.dll", + L"mfreadwrite.dll", + L"mfplat.dll", + L"opengl32.dll", + L"gdi32full.dll", + L"win32u.dll", + NULL +}; -BOOLEAN MatchBlockReg(PUNICODE_STRING s) -{ - return MatchList(s, g_BlockReg); -} +wchar_t* g_ScreenUserSubdirs[] = { + L"\\AppData\\", + L"\\Temp\\", + L"\\Downloads\\", + NULL +}; -wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s) -{ - return MatchListGetRule(s, g_BlockReg); -} - -BOOLEAN MatchBlockFile(PUNICODE_STRING s) -{ - return MatchList(s, g_BlockFile); -} - -BOOLEAN MatchBlockRansom(PUNICODE_STRING s) -{ - return MatchList(s, g_BlockRansom); -} - -wchar_t* GetMatchedBlockFileRule(PUNICODE_STRING s) -{ - return MatchListGetRule(s, g_BlockFile); -} - -BOOLEAN HasBlockedSuffix(PUNICODE_STRING s) -{ - if (!USOK(s)) - return FALSE; - SIZE_T n = s->Length / sizeof(WCHAR); - for (SIZE_T i = 0; g_Blocksuffix[i]; ++i) { - wchar_t* ext = g_Blocksuffix[i]; - SIZE_T m = wcslen(ext); - if (n >= m && _wcsnicmp(s->Buffer + (n - m), ext, m) == 0) - return TRUE; - } - return FALSE; -} \ No newline at end of file +wchar_t* g_ScreenOtherProcNeedles[] = { + L"\\ProgramData\\", + NULL +}; diff --git a/Plugins/Filter/ProtectRules.h b/Plugins/Filter/ProtectRules.h index b81484c..2b7e90c 100644 --- a/Plugins/Filter/ProtectRules.h +++ b/Plugins/Filter/ProtectRules.h @@ -1,15 +1,25 @@ #pragma once #include -wchar_t* GetMatchedBlockRegRule(PUNICODE_STRING s); -BOOLEAN MatchBlockReg(PUNICODE_STRING s); -BOOLEAN IsWhitelist(PUNICODE_STRING s); -BOOLEAN GetProcessImagePathByPid(HANDLE pid, PUNICODE_STRING ProcessImagePath); -BOOLEAN IsRegistryBlock(PUNICODE_STRING key, PUNICODE_STRING valueName, PUNICODE_STRING exe); - -BOOLEAN MatchBlockFile(PUNICODE_STRING s); -BOOLEAN MatchBlockRansom(PUNICODE_STRING s); -BOOLEAN HasBlockedSuffix(PUNICODE_STRING s); -wchar_t* GetMatchedBlockFileRule(PUNICODE_STRING s); +extern wchar_t* g_Whitelist[]; +extern wchar_t* g_WhitelistExcept[]; extern wchar_t* g_AttachDisk[]; +extern wchar_t* g_BlockFile[]; +extern wchar_t* g_BlockRansom[]; +extern wchar_t* g_Blocksuffix[]; + +extern wchar_t* g_BlockReg[]; + +extern wchar_t* g_RemoteSuspectBins[]; + +extern wchar_t* g_RemoteCmdIndicatorsHttp[]; +extern wchar_t* g_RemoteCmdIndicatorsGeneric[]; +extern wchar_t* g_RemoteCmdFromCmdExe[]; +extern wchar_t* g_RemoteCmdFromRundll32Exe[]; +extern wchar_t* g_RemoteCmdRegsvr32Need[]; +extern wchar_t* g_RemoteCmdFromMshtaExe[]; + +extern wchar_t* g_ScreenCapModules[]; +extern wchar_t* g_ScreenUserSubdirs[]; +extern wchar_t* g_ScreenOtherProcNeedles[]; diff --git a/Plugins/Filter/ProtectScreen.c b/Plugins/Filter/ProtectScreen.c new file mode 100644 index 0000000..00d5bba --- /dev/null +++ b/Plugins/Filter/ProtectScreen.c @@ -0,0 +1,80 @@ +#include +#include "DriverEntry.h" +#include "ProtectMatch.h" + +static BOOLEAN g_ScreenImgCb = FALSE; + +static VOID LogAnsi3(PCSTR tag, ULONG upid, PUNICODE_STRING s1, PUNICODE_STRING s2) +{ + ANSI_STRING a1 = { 0 }, a2 = { 0 }; + CHAR buf[1024] = { 0 }; + RtlUnicodeStringToAnsiString(&a1, s1, TRUE); + if (s2) + RtlUnicodeStringToAnsiString(&a2, s2, TRUE); + RtlStringCchPrintfA(buf, RTL_NUMBER_OF(buf), "%s | %u | %s | %s", tag, upid, a1.Buffer ? a1.Buffer : "", a2.Buffer ? a2.Buffer : ""); + SendPipeLog(buf, strlen(buf)); + RtlFreeAnsiString(&a1); + RtlFreeAnsiString(&a2); +} + +static VOID ImageLoadNotify(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo) +{ + UNREFERENCED_PARAMETER(ImageInfo); + if (g_Unloading) + return; + if (KeGetCurrentIrql() != PASSIVE_LEVEL) + return; + if (!ExAcquireRundownProtection(&g_Rundown)) + return; + if (!FullImageName || !FullImageName->Buffer || FullImageName->Length == 0) { + ExReleaseRundownProtection(&g_Rundown); + return; + } + + UNICODE_STRING proc = { 0 }; + WCHAR pbuf[512] = { 0 }; + proc.Buffer = pbuf; + proc.MaximumLength = sizeof(pbuf); + + if (!GetProcessImagePathByPid(ProcessId, &proc)) { + PEPROCESS eproc = NULL; + if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &eproc))) { + PCSTR n = PsGetProcessImageFileName(eproc); + SIZE_T l = n ? strlen(n) : 0; + for (SIZE_T i = 0; i < l && i < RTL_NUMBER_OF(pbuf) - 1; i++) + pbuf[i] = (WCHAR)n[i]; + pbuf[l] = 0; + proc.Length = (USHORT)(l * sizeof(WCHAR)); + ObDereferenceObject(eproc); + } + } + if (proc.Length == 0) { + ExReleaseRundownProtection(&g_Rundown); + return; + } + if (IsWhitelist(&proc)) { + ExReleaseRundownProtection(&g_Rundown); + return; + } + + BOOLEAN suspicious = MatchSuspiciousProcPath(&proc); + if (suspicious && MatchScreenCapModule(FullImageName)) + LogAnsi3("SCREEN_BLOCK", (ULONG)(ULONG_PTR)ProcessId, &proc, FullImageName); + + ExReleaseRundownProtection(&g_Rundown); +} + +NTSTATUS InitScreenProtect(VOID) +{ + NTSTATUS s = PsSetLoadImageNotifyRoutine(ImageLoadNotify); + if (NT_SUCCESS(s)) g_ScreenImgCb = TRUE; + return s; +} + +VOID UninitScreenProtect(VOID) +{ + if (g_ScreenImgCb) { + PsRemoveLoadImageNotifyRoutine(ImageLoadNotify); + g_ScreenImgCb = FALSE; + } +}