mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
implemented global report irp queue
This commit is contained in:
parent
3d1e2c7235
commit
5e8eeb4bf0
13 changed files with 340 additions and 171 deletions
|
@ -4,107 +4,9 @@
|
|||
|
||||
#include "queue.h"
|
||||
#include "pool.h"
|
||||
#include "thread.h"
|
||||
|
||||
CALLBACK_CONFIGURATION configuration;
|
||||
QUEUE_HEAD head = { 0 };
|
||||
|
||||
/*
|
||||
* This mutex is to prevent a new item being pushed to the queue
|
||||
* while the HandlePeriodicCallbackReportQueue is iterating through
|
||||
* the objects. This can be an issue because the spinlock is released
|
||||
* after each report is placed in the IRP buffer which means a new report
|
||||
* can be pushed into the queue before the next iteration can take ownership
|
||||
* of the spinlock.
|
||||
*/
|
||||
KGUARDED_MUTEX mutex;
|
||||
|
||||
VOID InitCallbackReportQueue(
|
||||
_In_ PBOOLEAN Status
|
||||
)
|
||||
{
|
||||
head.start = NULL;
|
||||
head.end = NULL;
|
||||
head.entries = 0;
|
||||
|
||||
KeInitializeSpinLock( &head.lock );
|
||||
KeInitializeGuardedMutex( &mutex );
|
||||
|
||||
*Status = TRUE;
|
||||
}
|
||||
|
||||
VOID InsertReportToQueue(
|
||||
_In_ POPEN_HANDLE_FAILURE_REPORT Report
|
||||
)
|
||||
{
|
||||
KeAcquireGuardedMutex( &mutex );
|
||||
QueuePush( &head, Report );
|
||||
KeReleaseGuardedMutex( &mutex );
|
||||
}
|
||||
|
||||
VOID FreeQueueObjectsAndCleanup()
|
||||
{
|
||||
KeAcquireGuardedMutex( &mutex );
|
||||
|
||||
PVOID report = QueuePop( &head );
|
||||
|
||||
while ( report != NULL )
|
||||
{
|
||||
ExFreePoolWithTag( report, REPORT_POOL_TAG );
|
||||
report = QueuePop( &head );
|
||||
}
|
||||
|
||||
end:
|
||||
KeReleaseGuardedMutex( &mutex );
|
||||
}
|
||||
|
||||
NTSTATUS HandlePeriodicCallbackReportQueue(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
PVOID report = NULL;
|
||||
INT count = 0;
|
||||
OPEN_HANDLE_FAILURE_REPORT_HEADER header;
|
||||
|
||||
KeAcquireGuardedMutex( &mutex );
|
||||
report = QueuePop( &head );
|
||||
|
||||
if ( report == NULL )
|
||||
{
|
||||
DEBUG_LOG( "callback report queue is empty, returning" );
|
||||
Irp->IoStatus.Information = sizeof( OPEN_HANDLE_FAILURE_REPORT_HEADER );
|
||||
goto end;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = sizeof( OPEN_HANDLE_FAILURE_REPORT ) * MAX_HANDLE_REPORTS_PER_IRP +
|
||||
sizeof( OPEN_HANDLE_FAILURE_REPORT_HEADER );
|
||||
|
||||
while ( report != NULL )
|
||||
{
|
||||
if ( count >= MAX_HANDLE_REPORTS_PER_IRP )
|
||||
goto end;
|
||||
|
||||
RtlCopyMemory(
|
||||
( ( UINT64 )Irp->AssociatedIrp.SystemBuffer + sizeof( OPEN_HANDLE_FAILURE_REPORT_HEADER ) ) + count * sizeof( OPEN_HANDLE_FAILURE_REPORT ),
|
||||
report,
|
||||
sizeof( OPEN_HANDLE_FAILURE_REPORT )
|
||||
);
|
||||
|
||||
/* QueuePop frees the node, but we still need to free the returned data */
|
||||
ExFreePoolWithTag( report, REPORT_POOL_TAG );
|
||||
|
||||
report = QueuePop( &head );
|
||||
count += 1;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
header.count = count;
|
||||
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &header, sizeof( OPEN_HANDLE_FAILURE_REPORT_HEADER ));
|
||||
KeReleaseGuardedMutex( &mutex );
|
||||
|
||||
DEBUG_LOG( "Moved all reports into the IRP, sending !" );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID ObPostOpCallbackRoutine(
|
||||
_In_ PVOID RegistrationContext,
|
||||
|
|
|
@ -10,18 +10,9 @@
|
|||
|
||||
#define HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH 64
|
||||
|
||||
#define REPORT_POOL_TAG 'repo'
|
||||
|
||||
#define MAX_HANDLE_REPORTS_PER_IRP 10
|
||||
|
||||
VOID UnregisterCallbacksOnProcessTermination();
|
||||
|
||||
typedef struct _OPEN_HANDLE_FAILURE_REPORT_HEADER
|
||||
{
|
||||
INT count;
|
||||
|
||||
}OPEN_HANDLE_FAILURE_REPORT_HEADER, *POPEN_HANDLE_FAILURE_REPORT_HEADER;
|
||||
|
||||
typedef struct _OPEN_HANDLE_FAILURE_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
|
@ -81,21 +72,11 @@ OB_PREOP_CALLBACK_STATUS ObPreOpCallbackRoutine(
|
|||
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
|
||||
);
|
||||
|
||||
VOID InitCallbackReportQueue(
|
||||
_In_ PBOOLEAN Status
|
||||
);
|
||||
|
||||
NTSTATUS HandlePeriodicCallbackReportQueue(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
VOID ProcessCreateNotifyRoutine(
|
||||
_In_ HANDLE ParentId,
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ BOOLEAN Create
|
||||
);
|
||||
|
||||
VOID FreeQueueObjectsAndCleanup();
|
||||
//VOID ProcessCreateNotifyRoutine(
|
||||
// _In_ HANDLE ParentId,
|
||||
// _In_ HANDLE ProcessId,
|
||||
// _In_ BOOLEAN Create
|
||||
//);
|
||||
|
||||
VOID EnumerateProcessListWithCallbackFunction(
|
||||
_In_ PVOID Function
|
||||
|
|
|
@ -10,10 +10,15 @@
|
|||
#include "modules.h"
|
||||
#include "integrity.h"
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
|
||||
DRIVER_CONFIG driver_config = { 0 };
|
||||
PROCESS_CONFIG process_config = { 0 };
|
||||
|
||||
UNICODE_STRING image_path = RTL_CONSTANT_STRING( L"ImagePath" );
|
||||
UNICODE_STRING display_name = RTL_CONSTANT_STRING( L"DisplayName" );
|
||||
|
||||
VOID ReadProcessInitialisedConfigFlag(
|
||||
_Out_ PBOOLEAN Flag
|
||||
)
|
||||
|
@ -109,9 +114,6 @@ NTSTATUS RegistryPathQueryCallbackRoutine(
|
|||
BOOLEAN result;
|
||||
RtlInitUnicodeString( &value_name, ValueName );
|
||||
|
||||
UNICODE_STRING image_path = RTL_CONSTANT_STRING( L"ImagePath" );
|
||||
UNICODE_STRING display_name = RTL_CONSTANT_STRING( L"DisplayName" );
|
||||
|
||||
if ( RtlCompareUnicodeString(&value_name, &image_path, FALSE) == FALSE )
|
||||
{
|
||||
DEBUG_LOG( "Value type image path given" );
|
||||
|
@ -120,7 +122,10 @@ NTSTATUS RegistryPathQueryCallbackRoutine(
|
|||
driver_config.driver_path.MaximumLength = ValueLength;
|
||||
|
||||
if ( !driver_config.driver_path.Buffer )
|
||||
{
|
||||
DEBUG_ERROR( "Failed to allocate buffer for unicode string driver path" );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
RtlCopyMemory(
|
||||
driver_config.driver_path.Buffer,
|
||||
|
@ -131,13 +136,16 @@ NTSTATUS RegistryPathQueryCallbackRoutine(
|
|||
|
||||
if ( RtlCompareUnicodeString( &value_name, &display_name, FALSE ) == FALSE )
|
||||
{
|
||||
DEBUG_LOG( "Value type image path given" );
|
||||
DEBUG_LOG( "Value type display name given" );
|
||||
driver_config.unicode_driver_name.Buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, ValueLength, DRIVER_PATH_POOL_TAG );
|
||||
driver_config.unicode_driver_name.Length = ValueLength;
|
||||
driver_config.unicode_driver_name.MaximumLength = ValueLength;
|
||||
|
||||
if ( !driver_config.unicode_driver_name.Buffer )
|
||||
{
|
||||
DEBUG_ERROR( "Failed to allocate buffer for unicode string driver name" );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
RtlCopyMemory(
|
||||
driver_config.unicode_driver_name.Buffer,
|
||||
|
@ -166,7 +174,9 @@ NTSTATUS InitialiseDriverConfigOnDriverEntry(
|
|||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
RTL_QUERY_REGISTRY_TABLE query_table[ 2 ] = { 0 };
|
||||
|
||||
/* allocate 3 so the as to act as a null terminator */
|
||||
RTL_QUERY_REGISTRY_TABLE query_table[ 3 ] = { 0 };
|
||||
|
||||
KeInitializeGuardedMutex( &driver_config.lock );
|
||||
|
||||
|
@ -200,6 +210,7 @@ NTSTATUS InitialiseDriverConfigOnDriverEntry(
|
|||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "RtlxQueryRegistryValues failed with status %x", status );
|
||||
FreeDriverConfigurationStringBuffers();
|
||||
return status;
|
||||
}
|
||||
|
@ -221,7 +232,7 @@ NTSTATUS InitialiseDriverConfigOnDriverEntry(
|
|||
}
|
||||
|
||||
|
||||
NTSTATUS InitialiseDriverConfigOnProcessLaunch(
|
||||
NTSTATUS InitialiseProcessConfigOnProcessLaunch(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
|
@ -256,6 +267,7 @@ NTSTATUS InitialiseDriverConfigOnProcessLaunch(
|
|||
VOID CleanupDriverConfigOnUnload()
|
||||
{
|
||||
FreeDriverConfigurationStringBuffers();
|
||||
FreeGlobalReportQueueObjects();
|
||||
IoDeleteSymbolicLink( &driver_config.device_symbolic_link );
|
||||
}
|
||||
|
||||
|
@ -284,7 +296,14 @@ VOID TerminateProtectedProcessOnViolation()
|
|||
status = ZwTerminateProcess( process_id, STATUS_SYSTEM_INTEGRITY_POLICY_VIOLATION );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
/*
|
||||
* We don't want to clear the process config if ZwTerminateProcess fails
|
||||
* so we can try again.
|
||||
*/
|
||||
DEBUG_ERROR( "ZwTerminateProcess failed with status %x", status );
|
||||
return;
|
||||
}
|
||||
|
||||
ClearProcessConfigOnProcessTermination();
|
||||
}
|
||||
|
@ -301,9 +320,13 @@ NTSTATUS DriverEntry(
|
|||
|
||||
status = InitialiseDriverConfigOnDriverEntry( RegistryPath );
|
||||
|
||||
KeInitializeGuardedMutex( &process_config.lock );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
{
|
||||
DEBUG_ERROR( "InitialiseDriverConfigOnDriverEntry failed with status %x", status );
|
||||
return status;
|
||||
}
|
||||
|
||||
status = IoCreateDevice(
|
||||
DriverObject,
|
||||
|
@ -317,6 +340,7 @@ NTSTATUS DriverEntry(
|
|||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "IoCreateDevice failed with status %x", status );
|
||||
FreeDriverConfigurationStringBuffers();
|
||||
return STATUS_FAILED_DRIVER_ENTRY;
|
||||
}
|
||||
|
@ -339,7 +363,7 @@ NTSTATUS DriverEntry(
|
|||
DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = DeviceControl;
|
||||
DriverObject->DriverUnload = DriverUnload;
|
||||
|
||||
InitCallbackReportQueue(&flag);
|
||||
InitialiseGlobalReportQueue(&flag);
|
||||
|
||||
if ( !flag )
|
||||
{
|
||||
|
@ -352,19 +376,6 @@ NTSTATUS DriverEntry(
|
|||
|
||||
DEBUG_LOG( "DonnaAC Driver Entry Complete" );
|
||||
|
||||
//HANDLE handle;
|
||||
//PsCreateSystemThread(
|
||||
// &handle,
|
||||
// PROCESS_ALL_ACCESS,
|
||||
// NULL,
|
||||
// NULL,
|
||||
// NULL,
|
||||
// VerifyInMemoryImageVsDiskImage,
|
||||
// NULL
|
||||
//);
|
||||
|
||||
//ZwClose( handle );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ typedef struct _PROCESS_CONFIG
|
|||
|
||||
}PROCESS_CONFIG, *PPROCESS_CONFIG;
|
||||
|
||||
NTSTATUS InitialiseDriverConfigOnProcessLaunch(
|
||||
NTSTATUS InitialiseProcessConfigOnProcessLaunch(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "pool.h"
|
||||
#include "integrity.h"
|
||||
#include "thread.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include "hv.h"
|
||||
|
||||
|
@ -106,7 +107,7 @@ NTSTATUS DeviceControl(
|
|||
|
||||
case IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH:;
|
||||
|
||||
status = InitialiseDriverConfigOnProcessLaunch(Irp);
|
||||
status = InitialiseProcessConfigOnProcessLaunch(Irp);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
|
@ -123,7 +124,7 @@ NTSTATUS DeviceControl(
|
|||
|
||||
case IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE:
|
||||
|
||||
status = HandlePeriodicCallbackReportQueue(Irp);
|
||||
status = HandlePeriodicGlobalReportQueueQuery(Irp);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
DEBUG_ERROR( "Failed to handle period callback report queue" );
|
||||
|
@ -252,7 +253,7 @@ NTSTATUS DeviceClose(
|
|||
{
|
||||
DEBUG_LOG( "Handle closed to DonnaAC" );
|
||||
|
||||
FreeQueueObjectsAndCleanup();
|
||||
FreeGlobalReportQueueObjects();
|
||||
ClearProcessConfigOnProcessTermination();
|
||||
UnregisterCallbacksOnProcessTermination();
|
||||
|
||||
|
|
174
driver/queue.c
174
driver/queue.c
|
@ -1,7 +1,52 @@
|
|||
#include "queue.h"
|
||||
|
||||
#include "callbacks.h"
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
#include "queue.h"
|
||||
#include "pool.h"
|
||||
#include "thread.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef struct _REPORT_HEADER
|
||||
{
|
||||
INT report_id;
|
||||
|
||||
}REPORT_HEADER, * PREPORT_HEADER;
|
||||
|
||||
/*
|
||||
* This mutex is to prevent a new item being pushed to the queue
|
||||
* while the HandlePeriodicCallbackReportQueue is iterating through
|
||||
* the objects. This can be an issue because the spinlock is released
|
||||
* after each report is placed in the IRP buffer which means a new report
|
||||
* can be pushed into the queue before the next iteration can take ownership
|
||||
* of the spinlock.
|
||||
*/
|
||||
|
||||
typedef struct _REPORT_QUEUE_CONFIGURATION
|
||||
{
|
||||
QUEUE_HEAD head;
|
||||
KGUARDED_MUTEX lock;
|
||||
|
||||
}REPORT_QUEUE_CONFIGURATION, *PREPORT_QUEUE_CONFIGURATION;
|
||||
|
||||
REPORT_QUEUE_CONFIGURATION report_queue_config = { 0 };
|
||||
|
||||
VOID InitialiseGlobalReportQueue(
|
||||
_In_ PBOOLEAN Status
|
||||
)
|
||||
{
|
||||
report_queue_config.head.start = NULL;
|
||||
report_queue_config.head.end = NULL;
|
||||
report_queue_config.head.entries = 0;
|
||||
|
||||
KeInitializeSpinLock( &report_queue_config.head.lock );
|
||||
KeInitializeGuardedMutex( &report_queue_config.lock );
|
||||
|
||||
*Status = TRUE;
|
||||
}
|
||||
|
||||
//PQUEUE_HEAD QueueCreate()
|
||||
//{
|
||||
// PQUEUE_HEAD head = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( QUEUE_HEAD ), QUEUE_POOL_TAG );
|
||||
|
@ -74,3 +119,132 @@ end:
|
|||
KeReleaseSpinLock( &Head->lock, irql );
|
||||
return data;
|
||||
}
|
||||
|
||||
VOID InsertReportToQueue(
|
||||
_In_ PVOID Report
|
||||
)
|
||||
{
|
||||
KeAcquireGuardedMutex( &report_queue_config.lock );
|
||||
QueuePush( &report_queue_config.head, Report );
|
||||
KeReleaseGuardedMutex( &report_queue_config.lock );
|
||||
}
|
||||
|
||||
VOID FreeGlobalReportQueueObjects()
|
||||
{
|
||||
KeAcquireGuardedMutex( &report_queue_config.lock );
|
||||
|
||||
PVOID report = QueuePop( &report_queue_config.head );
|
||||
|
||||
while ( report != NULL )
|
||||
{
|
||||
ExFreePoolWithTag( report, REPORT_POOL_TAG );
|
||||
report = QueuePop( &report_queue_config.head );
|
||||
}
|
||||
|
||||
end:
|
||||
KeReleaseGuardedMutex( &report_queue_config.lock );
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles sending all the pending reports in the global report
|
||||
* queue to the usermode application. This function is called periodically by the
|
||||
* usermode application. The reason I have implemented this is because as this application
|
||||
* expanded, it became apparent that some of the driver functions will generate multiple
|
||||
* reports as a result of a single usermode request and hence it makes dealing with
|
||||
* reports generated from ObRegisterCallbacks for example much easier.
|
||||
*/
|
||||
NTSTATUS HandlePeriodicGlobalReportQueueQuery(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
PVOID report = NULL;
|
||||
INT count = 0;
|
||||
GLOBAL_REPORT_QUEUE_HEADER header;
|
||||
PVOID report_buffer = NULL;
|
||||
PREPORT_HEADER report_header;
|
||||
SIZE_T total_size = NULL;
|
||||
|
||||
KeAcquireGuardedMutex( &report_queue_config.lock );
|
||||
report = QueuePop( &report_queue_config.head );
|
||||
|
||||
report_buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, 1024 * 2, REPORT_QUEUE_TEMP_BUFFER_TAG );
|
||||
|
||||
if ( !report_buffer )
|
||||
{
|
||||
DEBUG_LOG( "Failed to allocate report buffer" );
|
||||
KeReleaseGuardedMutex( &report_queue_config.lock );
|
||||
return STATUS_MEMORY_NOT_ALLOCATED;
|
||||
}
|
||||
|
||||
if ( report == NULL )
|
||||
{
|
||||
DEBUG_LOG( "callback report queue is empty, returning" );
|
||||
goto end;
|
||||
}
|
||||
|
||||
while ( report != NULL )
|
||||
{
|
||||
if ( count >= MAX_REPORTS_PER_IRP )
|
||||
goto end;
|
||||
|
||||
report_header = ( PREPORT_HEADER )report;
|
||||
|
||||
switch ( report_header->report_id )
|
||||
{
|
||||
case REPORT_ILLEGAL_HANDLE_OPERATION:
|
||||
|
||||
RtlCopyMemory(
|
||||
( UINT64 )report_buffer + sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size,
|
||||
report,
|
||||
sizeof( OPEN_HANDLE_FAILURE_REPORT )
|
||||
);
|
||||
|
||||
total_size += sizeof( OPEN_HANDLE_FAILURE_REPORT );
|
||||
|
||||
break;
|
||||
|
||||
case REPORT_ILLEGAL_ATTACH_PROCESS:
|
||||
|
||||
RtlCopyMemory(
|
||||
( UINT64 )report_buffer + sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size,
|
||||
report,
|
||||
sizeof( ATTACH_PROCESS_REPORT )
|
||||
);
|
||||
|
||||
total_size += sizeof( ATTACH_PROCESS_REPORT );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* QueuePop frees the node, but we still need to free the returned data */
|
||||
ExFreePoolWithTag( report, REPORT_POOL_TAG );
|
||||
|
||||
report = QueuePop( &report_queue_config.head );
|
||||
count += 1;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
Irp->IoStatus.Information = sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size;
|
||||
|
||||
header.count = count;
|
||||
|
||||
RtlCopyMemory(
|
||||
report_buffer,
|
||||
&header,
|
||||
sizeof( GLOBAL_REPORT_QUEUE_HEADER ) );
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
report_buffer,
|
||||
sizeof( GLOBAL_REPORT_QUEUE_HEADER ) + total_size
|
||||
);
|
||||
|
||||
KeReleaseGuardedMutex( &report_queue_config.lock );
|
||||
|
||||
if ( report_buffer )
|
||||
ExFreePoolWithTag( report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG );
|
||||
|
||||
DEBUG_LOG( "Moved all reports into the IRP, sending !" );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
#include <ntifs.h>
|
||||
|
||||
#define QUEUE_POOL_TAG 'qqqq'
|
||||
#define REPORT_QUEUE_TEMP_BUFFER_TAG 'temp'
|
||||
|
||||
#define REPORT_POOL_TAG 'repo'
|
||||
|
||||
#define MAX_REPORTS_PER_IRP 20
|
||||
|
||||
typedef struct _QUEUE_NODE
|
||||
{
|
||||
|
@ -21,6 +26,12 @@ typedef struct QUEUE_HEAD
|
|||
|
||||
}QUEUE_HEAD, *PQUEUE_HEAD;
|
||||
|
||||
typedef struct _GLOBAL_REPORT_QUEUE_HEADER
|
||||
{
|
||||
INT count;
|
||||
|
||||
}GLOBAL_REPORT_QUEUE_HEADER, * PGLOBAL_REPORT_QUEUE_HEADER;
|
||||
|
||||
VOID QueuePush(
|
||||
_In_ PQUEUE_HEAD Head,
|
||||
_In_ PVOID Data
|
||||
|
@ -30,6 +41,18 @@ PVOID QueuePop(
|
|||
_In_ PQUEUE_HEAD Head
|
||||
);
|
||||
|
||||
VOID InitialiseGlobalReportQueue(
|
||||
_In_ PBOOLEAN Status
|
||||
);
|
||||
|
||||
VOID InsertReportToQueue(
|
||||
_In_ PVOID Report
|
||||
);
|
||||
|
||||
NTSTATUS HandlePeriodicGlobalReportQueueQuery(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
VOID FreeGlobalReportQueueObjects();
|
||||
|
||||
#endif
|
|
@ -11,7 +11,7 @@ BOOLEAN finished = FALSE;
|
|||
|
||||
UINT64 current_kpcrb_thread = NULL;
|
||||
|
||||
VOID ProcessEnumerationCallback(
|
||||
VOID KPRCBThreadValidationProcessCallback(
|
||||
_In_ PEPROCESS Process
|
||||
)
|
||||
{
|
||||
|
@ -88,7 +88,7 @@ VOID ValidateKPCRBThreads(
|
|||
current_kpcrb_thread = *( UINT64* )( kprcb + KPCRB_CURRENT_THREAD );
|
||||
|
||||
EnumerateProcessListWithCallbackFunction(
|
||||
ProcessEnumerationCallback
|
||||
KPRCBThreadValidationProcessCallback
|
||||
);
|
||||
|
||||
if ( thread_found_in_kthreadlist == FALSE || thread_found_in_pspcidtable == FALSE )
|
||||
|
@ -122,3 +122,49 @@ VOID ValidateKPCRBThreads(
|
|||
}
|
||||
}
|
||||
|
||||
VOID DetectAttachedThreadsProcessCallback(
|
||||
_In_ PEPROCESS Process
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PLIST_ENTRY thread_list_head;
|
||||
PLIST_ENTRY thread_list_entry;
|
||||
PETHREAD current_thread;
|
||||
UINT32 thread_id;
|
||||
|
||||
if ( finished == TRUE )
|
||||
return;
|
||||
|
||||
thread_list_head = ( PLIST_ENTRY )( ( UINT64 )Process + KPROCESS_THREADLIST_OFFSET );
|
||||
thread_list_entry = thread_list_head->Flink;
|
||||
|
||||
while ( thread_list_entry != thread_list_head )
|
||||
{
|
||||
current_thread = ( PETHREAD )( ( UINT64 )thread_list_entry - KTHREAD_THREADLIST_OFFSET );
|
||||
|
||||
|
||||
|
||||
thread_list_entry = thread_list_entry->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* I did not reverse this myself and previously had no idea how you would go about
|
||||
* detecting KiAttachProcess so credits to KANKOSHEV for the explanation:
|
||||
*
|
||||
* https://github.com/KANKOSHEV/Detect-KeAttachProcess/tree/main
|
||||
* https://doxygen.reactos.org/d0/dc9/procobj_8c.html#adec6dc539d4a5c0ee7d0f48e24ef0933
|
||||
*
|
||||
* Then from here you can see that the _KAPC_STATE structure in the KTHREAD stores the
|
||||
* APC state for the thread. The Process field in this structure is the offset referred to
|
||||
* in KANKOSHEV's proof of concept. This the field that is updated by KiAttachProcess when
|
||||
* calling KeStackAttachProcess.
|
||||
*/
|
||||
VOID DetectThreadsAttachedToProtectedProcess(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
EnumerateProcessListWithCallbackFunction(
|
||||
DetectAttachedThreadsProcessCallback
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#define REPORT_HIDDEN_SYSTEM_THREAD 90
|
||||
|
||||
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
|
||||
|
||||
VOID ValidateKPCRBThreads(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
@ -28,4 +30,10 @@ typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
|
|||
|
||||
}HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
|
||||
|
||||
typedef struct _ATTACH_PROCESS_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
|
||||
}ATTACH_PROCESS_REPORT, *PATTACH_PROCESS_REPORT;
|
||||
|
||||
#endif
|
|
@ -23,6 +23,7 @@
|
|||
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
|
||||
#define REPORT_INVALID_PROCESS_ALLOCATION 80
|
||||
#define REPORT_HIDDEN_SYSTEM_THREAD 90
|
||||
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
|
||||
|
||||
enum REPORT_CODES
|
||||
{
|
||||
|
@ -168,6 +169,12 @@ namespace global
|
|||
LONG thread_id;
|
||||
CHAR thread[ 4096 ];
|
||||
};
|
||||
|
||||
|
||||
struct ATTACH_PROCESS_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -155,17 +155,23 @@ VOID kernelmode::Driver::VerifySystemModules()
|
|||
* modules.
|
||||
*/
|
||||
|
||||
struct REPORT_ID
|
||||
{
|
||||
INT report_id;
|
||||
};
|
||||
|
||||
VOID kernelmode::Driver::QueryReportQueue()
|
||||
{
|
||||
BOOLEAN status;
|
||||
DWORD bytes_returned;
|
||||
PVOID buffer;
|
||||
LONG buffer_size;
|
||||
global::report_structures::OPEN_HANDLE_FAILURE_REPORT report;
|
||||
|
||||
buffer_size = sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT ) * MAX_HANDLE_REPORTS_PER_IRP +
|
||||
sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER );
|
||||
REPORT_ID* report_header;
|
||||
SIZE_T total_size = NULL;
|
||||
global::report_structures::OPEN_HANDLE_FAILURE_REPORT* handle_report;
|
||||
global::report_structures::ATTACH_PROCESS_REPORT* attach_report;
|
||||
|
||||
buffer_size = 1024 * 2;
|
||||
buffer = malloc( buffer_size );
|
||||
|
||||
status = DeviceIoControl(
|
||||
|
@ -195,14 +201,34 @@ VOID kernelmode::Driver::QueryReportQueue()
|
|||
if ( header->count == 0 )
|
||||
goto end;
|
||||
|
||||
LOG_INFO( "report count: %i", header->count );
|
||||
|
||||
for ( int i = 0; i < header->count; i++ )
|
||||
{
|
||||
global::report_structures::OPEN_HANDLE_FAILURE_REPORT* report =
|
||||
( global::report_structures::OPEN_HANDLE_FAILURE_REPORT* )(
|
||||
( UINT64 )buffer + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) +
|
||||
i * sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT ) );
|
||||
report_header = (REPORT_ID*)( ( UINT64 )buffer + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) + total_size );
|
||||
|
||||
this->report_interface->ReportViolation( report );
|
||||
LOG_INFO( "REport id: %i", report_header->report_id );
|
||||
|
||||
switch ( report_header->report_id )
|
||||
{
|
||||
case REPORT_ILLEGAL_ATTACH_PROCESS:
|
||||
|
||||
attach_report = (global::report_structures::ATTACH_PROCESS_REPORT*)(
|
||||
( UINT64 )buffer + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) + total_size );
|
||||
|
||||
this->report_interface->ReportViolation( attach_report );
|
||||
|
||||
total_size += sizeof( global::report_structures::ATTACH_PROCESS_REPORT );
|
||||
|
||||
case REPORT_ILLEGAL_HANDLE_OPERATION:
|
||||
|
||||
handle_report = ( global::report_structures::OPEN_HANDLE_FAILURE_REPORT* )(
|
||||
( UINT64 )buffer + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) + total_size );
|
||||
|
||||
this->report_interface->ReportViolation( handle_report );
|
||||
|
||||
total_size += sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT );
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#define IOCTL_VALIDATE_KPRCB_CURRENT_THREAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2012, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_INTEGRITY_CHECK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2013, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define MAX_HANDLE_REPORTS_PER_IRP 10
|
||||
#define MAX_REPORTS_PER_IRP 20
|
||||
|
||||
namespace kernelmode
|
||||
{
|
||||
|
|
|
@ -31,16 +31,6 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
|
|||
while ( !GetAsyncKeyState( VK_DELETE ) )
|
||||
{
|
||||
kmanager.MonitorCallbackReports();
|
||||
kmanager.RunNmiCallbacks();
|
||||
kmanager.VerifySystemModules();
|
||||
kmanager.RequestModuleExecutableRegionsForIntegrityCheck();
|
||||
kmanager.DetectSystemVirtualization();
|
||||
kmanager.ScanPoolsForUnlinkedProcesses();
|
||||
kmanager.EnumerateHandleTables();
|
||||
|
||||
umanager.ValidateProcessModules();
|
||||
umanager.ValidateProcessMemory();
|
||||
umanager.ValidateProcessThreads();
|
||||
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 10000 ) );
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue