refactor the callbacks

This commit is contained in:
lhodges1 2023-10-06 19:30:14 +11:00
parent 45a23b7177
commit 1e2de300c2
7 changed files with 200 additions and 172 deletions

View file

@ -6,9 +6,6 @@
#include "pool.h"
#include "thread.h"
CALLBACK_CONFIGURATION configuration = { 0 };
STATIC
VOID
ObPostOpCallbackRoutine(
_In_ PVOID RegistrationContext,
@ -18,7 +15,6 @@ ObPostOpCallbackRoutine(
}
STATIC
OB_PREOP_CALLBACK_STATUS
ObPreOpCallbackRoutine(
_In_ PVOID RegistrationContext,
@ -46,9 +42,14 @@ ObPreOpCallbackRoutine(
LPCSTR process_creator_name;
LPCSTR target_process_name;
LPCSTR protected_process_name;
PCALLBACK_CONFIGURATION configuration = NULL;
KeAcquireGuardedMutex(&configuration.mutex);
GetCallbackConfigStructure(&configuration);
if (!configuration)
return OB_PREOP_SUCCESS;
KeAcquireGuardedMutex(&configuration->mutex);
GetProtectedProcessId(&protected_process_id);
GetProtectedProcessEProcess(&protected_process);
@ -110,7 +111,7 @@ ObPreOpCallbackRoutine(
end:
KeReleaseGuardedMutex(&configuration.mutex);
KeReleaseGuardedMutex(&configuration->mutex);
return OB_PREOP_SUCCESS;
}
@ -404,68 +405,4 @@ EnumerateProcessListWithCallbackFunction(
process_list_entry = process_list_entry->Flink;
} while (process_list_entry != process_list_head->Blink);
}
NTSTATUS
InitiateDriverCallbacks()
{
NTSTATUS status;
/*
* This mutex ensures we don't unregister our ObRegisterCallbacks while
* the callback function is running since this might cause some funny stuff
* to happen. Better to be safe then sorry :)
*/
KeInitializeGuardedMutex(&configuration.mutex);
OB_CALLBACK_REGISTRATION callback_registration = { 0 };
OB_OPERATION_REGISTRATION operation_registration = { 0 };
operation_registration.ObjectType = PsProcessType;
operation_registration.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
operation_registration.PreOperation = ObPreOpCallbackRoutine;
operation_registration.PostOperation = ObPostOpCallbackRoutine;
callback_registration.Version = OB_FLT_REGISTRATION_VERSION;
callback_registration.OperationRegistration = &operation_registration;
callback_registration.OperationRegistrationCount = 1;
callback_registration.RegistrationContext = NULL;
status = ObRegisterCallbacks(
&callback_registration,
&configuration.registration_handle
);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to launch obregisters with status %x", status);
return status;
}
//status = PsSetCreateProcessNotifyRoutine(
// ProcessCreateNotifyRoutine,
// FALSE
//);
//if ( !NT_SUCCESS( status ) )
// DEBUG_ERROR( "Failed to launch ps create notif routines with status %x", status );
return status;
}
VOID
UnregisterCallbacksOnProcessTermination()
{
DEBUG_LOG("Process closed, unregistering callbacks");
KeAcquireGuardedMutex(&configuration.mutex);
if (configuration.registration_handle == NULL)
{
KeReleaseGuardedMutex(&configuration.mutex);
return;
}
ObUnRegisterCallbacks(configuration.registration_handle);
configuration.registration_handle = NULL;
KeReleaseGuardedMutex(&configuration.mutex);
}

View file

@ -19,13 +19,6 @@ typedef struct _OPEN_HANDLE_FAILURE_REPORT
}OPEN_HANDLE_FAILURE_REPORT, * POPEN_HANDLE_FAILURE_REPORT;
typedef struct _CALLBACKS_CONFIGURATION
{
PVOID registration_handle;
KGUARDED_MUTEX mutex;
}CALLBACK_CONFIGURATION, * PCALLBACK_CONFIGURATION;
//handle access masks
//https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
#define PROCESS_CREATE_PROCESS 0x0080
@ -58,14 +51,12 @@ ExUnlockHandleTableEntry(
IN PHANDLE_TABLE_ENTRY HandleTableEntry
);
STATIC
VOID
ObPostOpCallbackRoutine(
_In_ PVOID RegistrationContext,
_In_ POB_POST_OPERATION_INFORMATION OperationInformation
);
STATIC
OB_PREOP_CALLBACK_STATUS
ObPreOpCallbackRoutine(
_In_ PVOID RegistrationContext,
@ -89,10 +80,4 @@ EnumerateProcessHandles(
_In_ PEPROCESS Process
);
NTSTATUS
InitiateDriverCallbacks();
VOID
UnregisterCallbacksOnProcessTermination();
#endif

View file

@ -13,9 +13,6 @@
/*
* This structure is strictly for driver related stuff
* that should only be written at driver entry.
*
* Note that the lock isnt really needed here but Im using one
* just in case c:
*/
#define MAXIMUM_APC_CONTEXTS 10
@ -30,6 +27,7 @@ typedef struct _DRIVER_CONFIG
UNICODE_STRING registry_path;
SYSTEM_INFORMATION system_information;
PVOID apc_contexts[MAXIMUM_APC_CONTEXTS];
PCALLBACK_CONFIGURATION callback_config;
KGUARDED_MUTEX lock;
}DRIVER_CONFIG, * PDRIVER_CONFIG;
@ -51,6 +49,131 @@ typedef struct _PROCESS_CONFIG
DRIVER_CONFIG driver_config = { 0 };
PROCESS_CONFIG process_config = { 0 };
#define POOL_TAG_CONFIG 'conf'
NTSTATUS
EnableCallbackRoutinesOnProcessRun()
{
NTSTATUS status;
KeAcquireGuardedMutex(&driver_config.lock);
KeAcquireGuardedMutex(&driver_config.callback_config->mutex);
OB_CALLBACK_REGISTRATION callback_registration = { 0 };
OB_OPERATION_REGISTRATION operation_registration = { 0 };
operation_registration.ObjectType = PsProcessType;
operation_registration.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
operation_registration.PreOperation = ObPreOpCallbackRoutine;
operation_registration.PostOperation = ObPostOpCallbackRoutine;
callback_registration.Version = OB_FLT_REGISTRATION_VERSION;
callback_registration.OperationRegistration = &operation_registration;
callback_registration.OperationRegistrationCount = 1;
callback_registration.RegistrationContext = NULL;
status = ObRegisterCallbacks(
&callback_registration,
&driver_config.callback_config->registration_handle
);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to launch obregisters with status %x", status);
goto end;
}
//status = PsSetCreateProcessNotifyRoutine(
// ProcessCreateNotifyRoutine,
// FALSE
//);
//if ( !NT_SUCCESS( status ) )
// DEBUG_ERROR( "Failed to launch ps create notif routines with status %x", status );
end:
KeReleaseGuardedMutex(&driver_config.callback_config->mutex);
KeReleaseGuardedMutex(&driver_config.lock);
return status;
}
STATIC
NTSTATUS
AllocateCallbackStructure()
{
KeAcquireGuardedMutex(&driver_config.lock);
driver_config.callback_config =
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(CALLBACK_CONFIGURATION), POOL_TAG_CONFIG);
if (!driver_config.callback_config)
{
KeReleaseGuardedMutex(&driver_config.lock);
return STATUS_MEMORY_NOT_ALLOCATED;
}
/*
* This mutex ensures we don't unregister our ObRegisterCallbacks while
* the callback function is running since this might cause some funny stuff
* to happen. Better to be safe then sorry :)
*/
KeInitializeGuardedMutex(&driver_config.callback_config->mutex);
KeReleaseGuardedMutex(&driver_config.lock);
return STATUS_SUCCESS;
}
/*
* The question is, What happens if we attempt to register our callbacks after we
* unregister them but before we free the pool? Hm.. No Good.
*
* Okay to solve this well acquire the driver lock aswell, we could also just
* store the structure in the .data section but i ceebs atm.
*
* This definitely doesn't seem optimal, but it works ...
*/
STATIC
VOID
CleanupDriverCallbacksOnDriverUnload()
{
/* UnRegisterCallbacksOnProcessTermination holds the driver lock, so must acquire it after */
UnregisterCallbacksOnProcessTermination();
KeAcquireGuardedMutex(&driver_config.lock);
ExFreePoolWithTag(driver_config.callback_config, POOL_TAG_CONFIG);
KeAcquireGuardedMutex(&driver_config.lock);
}
VOID
UnregisterCallbacksOnProcessTermination()
{
KeAcquireGuardedMutex(&driver_config.lock);
KeAcquireGuardedMutex(&driver_config.callback_config->mutex);
if (driver_config.callback_config->registration_handle)
{
ObUnRegisterCallbacks(driver_config.callback_config->registration_handle);
driver_config.callback_config->registration_handle = NULL;
}
KeReleaseGuardedMutex(&driver_config.callback_config->mutex);
KeReleaseGuardedMutex(&driver_config.lock);
}
/*
* Can return a null value if we attempt to read the value is underway whilst we are
* freeing the structure, hence the use of the 2 locks.
*/
VOID
GetCallbackConfigStructure(
_Out_ PCALLBACK_CONFIGURATION* CallbackConfiguration
)
{
KeAcquireGuardedMutex(&driver_config.lock);
KeAcquireGuardedMutex(&driver_config.callback_config->mutex);
*CallbackConfiguration = driver_config.callback_config;
KeReleaseGuardedMutex(&driver_config.callback_config->mutex);
KeReleaseGuardedMutex(&driver_config.lock);
}
/*
* The driver config structure holds an array of pointers to APC context structures. These
* APC context structures are unique to each APC operation that this driver will perform. For
@ -580,6 +703,15 @@ InitialiseDriverConfigOnDriverEntry(
return status;
}
status = AllocateCallbackStructure();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("AllocateCallbackStructure failed with status %x", status);
FreeDriverConfigurationStringBuffers();
return status;
}
DEBUG_LOG("Motherboard serial: %s", driver_config.system_information.motherboard_serial);
DEBUG_LOG("Drive 0 serial: %s", driver_config.system_information.drive_0_serial);
@ -592,8 +724,8 @@ InitialiseProcessConfigOnProcessLaunch(
)
{
NTSTATUS status;
PDRIVER_INITIATION_INFORMATION information;
PEPROCESS eprocess;
PDRIVER_INITIATION_INFORMATION information;
information = (PDRIVER_INITIATION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
@ -636,18 +768,21 @@ DriverUnload(
_In_ PDRIVER_OBJECT DriverObject
)
{
DEBUG_LOG("Unloading driver...");
//PsSetCreateProcessNotifyRoutine( ProcessCreateNotifyRoutine, TRUE );
//QueryActiveApcContextsForCompletion();
/* dont unload while we have active APC operations */
//while ( !FreeAllApcContextStructures() )
// YieldProcessor();
while (FreeAllApcContextStructures() == FALSE)
YieldProcessor();
/* This is safe to call even if the callbacks have already been disabled */
//UnregisterCallbacksOnProcessTermination();
CleanupDriverCallbacksOnDriverUnload();
//CleanupDriverConfigOnUnload();
//IoDeleteDevice( DriverObject->DeviceObject );
CleanupDriverConfigOnUnload();
IoDeleteDevice(DriverObject->DeviceObject);
DEBUG_LOG("Driver unloaded");
}
VOID

View file

@ -26,6 +26,13 @@ typedef struct _SYSTEM_INFORMATION
}SYSTEM_INFORMATION, * PSYSTEM_INFORMATION;
typedef struct _CALLBACKS_CONFIGURATION
{
PVOID registration_handle;
KGUARDED_MUTEX mutex;
}CALLBACK_CONFIGURATION, * PCALLBACK_CONFIGURATION;
NTSTATUS InitialiseProcessConfigOnProcessLaunch(
_In_ PIRP Irp
);
@ -86,4 +93,15 @@ TerminateProtectedProcessOnViolation();
VOID
ClearProcessConfigOnProcessTermination();
NTSTATUS
EnableCallbackRoutinesOnProcessRun();
VOID
UnregisterCallbacksOnProcessTermination();
VOID
GetCallbackConfigStructure(
_Out_ PCALLBACK_CONFIGURATION* CallbackConfiguration
);
#endif

View file

@ -1414,10 +1414,11 @@ WCHAR PROTECTED_FUNCTIONS[EPT_PROTECTED_FUNCTIONS_COUNT][EPT_MAX_FUNCTION_NAME_L
/*
* For whatever reason MmGetSystemRoutineAddress only works once, then every call
* thereafter fails. So will be storing the routine addresses in arrays.
* thereafter fails. So will be storing the routine addresses in arrays since they
* dont change once the kernel is loaded.
*/
UINT64 CONTROL_FUNCTION_ADDRESSES[EPT_CONTROL_FUNCTIONS_COUNT];
UINT64 PROTECTED_FUNCTION_ADDRESSES[EPT_PROTECTED_FUNCTIONS_COUNT];
UINT64 CONTROL_FUNCTION_ADDRESSES[EPT_CONTROL_FUNCTIONS_COUNT] = { 0 };
UINT64 PROTECTED_FUNCTION_ADDRESSES[EPT_PROTECTED_FUNCTIONS_COUNT] = { 0 };
STATIC
NTSTATUS
@ -1446,9 +1447,6 @@ InitiateEptFunctionAddressArrays()
return STATUS_SUCCESS;
}
/*
* This maybe needs to be dispatched from a system thread rather then a user mode thread.
*/
NTSTATUS
DetectEptHooksInKeyFunctions()
{
@ -1483,23 +1481,13 @@ DetectEptHooksInKeyFunctions()
control_time_sum += instruction_time;
}
DEBUG_LOG("Control time sum: %llx", control_time_sum);
if (control_time_sum == 0)
{
DEBUG_ERROR("Control time is null");
return STATUS_UNSUCCESSFUL;
}
control_average = control_time_sum / (EPT_CONTROL_FUNCTIONS_COUNT - control_fails);
DEBUG_LOG("Control average: %llx", control_average);
if (control_average == 0)
{
DEBUG_ERROR("Control average time is null");
return STATUS_UNSUCCESSFUL;
}
return STATUS_ABANDONED;
for (INT index = 0; index < EPT_PROTECTED_FUNCTIONS_COUNT; index++)
{

View file

@ -163,7 +163,7 @@ DeviceControl(
goto end;
}
status = InitiateDriverCallbacks();
status = EnableCallbackRoutinesOnProcessRun();
if (!NT_SUCCESS(status))
DEBUG_ERROR("InitiateDriverCallbacks failed with status %x", status);
@ -338,18 +338,7 @@ DeviceControl(
case IOCTL_CHECK_FOR_EPT_HOOK:
/*
* No need to wait on this thread as if it fails, program will be shut.
*/
status = PsCreateSystemThread(
&handle,
PROCESS_ALL_ACCESS,
NULL,
NULL,
NULL,
DetectEptHooksInKeyFunctions,
NULL
);
status = DetectEptHooksInKeyFunctions();
if (!NT_SUCCESS(status))
DEBUG_ERROR("DetectEpthooksInKeyFunctions failed with status %x", status);

View file

@ -43,19 +43,40 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
while (!GetAsyncKeyState(VK_DELETE))
{
int seed = (rand() % 3);
int seed = (rand() % 10);
std::cout << "Seed: " << seed << std::endl;
switch (seed)
{
case 0:
kmanager.CheckForAttachedThreads();
kmanager.EnumerateHandleTables();
break;
case 1:
kmanager.CheckForHiddenThreads();
kmanager.PerformIntegrityCheck();
break;
case 2:
kmanager.ScanPoolsForUnlinkedProcesses();
break;
case 3:
kmanager.VerifySystemModules();
break;
case 4:
kmanager.ValidateProcessModules();
break;
case 5:
kmanager.RunNmiCallbacks();
break;
case 6:
kmanager.CheckForAttachedThreads();
break;
case 7:
//kmanager.InitiateApcStackwalkOperation();
break;
case 8:
kmanager.CheckForHiddenThreads();
break;
case 9:
kmanager.CheckForEptHooks();
break;
}
@ -65,51 +86,6 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
std::this_thread::sleep_for(std::chrono::seconds(10));
}
//while (!GetAsyncKeyState(VK_DELETE))
//{
// int seed = (rand() % 10);
// std::cout << "Seed: " << seed << std::endl;
// switch (seed)
// {
// case 0:
// kmanager.EnumerateHandleTables();
// break;
// case 1:
// kmanager.PerformIntegrityCheck();
// break;
// case 2:
// kmanager.ScanPoolsForUnlinkedProcesses();
// break;
// case 3:
// kmanager.VerifySystemModules();
// break;
// case 4:
// kmanager.ValidateProcessModules();
// break;
// case 5:
// kmanager.RunNmiCallbacks();
// break;
// case 6:
// kmanager.CheckForAttachedThreads();
// break;
// case 7:
// kmanager.InitiateApcStackwalkOperation();
// break;
// case 8:
// kmanager.CheckForHiddenThreads();
// break;
// case 9:
// kmanager.CheckForEptHooks();
// break;
// }
// kmanager.MonitorCallbackReports();
// std::this_thread::sleep_for(std::chrono::seconds(10));
//}
fclose(stdout);
fclose(stdin);
FreeConsole();