mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
thread validation check
This commit is contained in:
parent
40d8a39aa8
commit
67a8bdf170
9 changed files with 117 additions and 48 deletions
|
@ -120,6 +120,8 @@ NTSTATUS DriverEntry(
|
|||
NULL
|
||||
);
|
||||
|
||||
ZwClose( handle );
|
||||
|
||||
status = IoCreateDevice(
|
||||
DriverObject,
|
||||
NULL,
|
||||
|
@ -158,10 +160,10 @@ NTSTATUS DriverEntry(
|
|||
IoDeleteSymbolicLink( &DEVICE_SYMBOLIC_LINK );
|
||||
IoDeleteDevice( DriverObject->DeviceObject );
|
||||
return STATUS_FAILED_DRIVER_ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG( "DonnaAC Driver Entry Complete. type: %lx", DriverObject->DeviceObject->DeviceType );
|
||||
DEBUG_LOG( "DonnaAC Driver Entry Complete" );
|
||||
|
||||
return status;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "callbacks.h"
|
||||
#include "pool.h"
|
||||
#include "integrity.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "hv.h"
|
||||
|
||||
|
@ -218,6 +219,12 @@ NTSTATUS DeviceControl(
|
|||
|
||||
break;
|
||||
|
||||
case IOCTL_VALIDATE_KPRCB_CURRENT_THREAD:
|
||||
|
||||
ValidateKPCRBThreads( Irp );
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR( "Invalid IOCTL passed to driver" );
|
||||
break;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2009, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2011, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_KPRCB_CURRENT_THREAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2012, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
typedef struct _DRIVER_INITIATION_INFORMATION
|
||||
{
|
||||
|
|
|
@ -716,16 +716,16 @@ NTSTATUS LaunchNonMaskableInterrupt(
|
|||
if ( !NumCores )
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PKAFFINITY_EX ProcAffinityPool = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( KAFFINITY_EX ), PROC_AFFINITY_POOL );
|
||||
PKAFFINITY_EX proc_affinity = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( KAFFINITY_EX ), PROC_AFFINITY_POOL );
|
||||
|
||||
if ( !ProcAffinityPool )
|
||||
if ( !proc_affinity )
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
nmi_pools.stack_frames = ExAllocatePool2( POOL_FLAG_NON_PAGED, NumCores * STACK_FRAME_POOL_SIZE, STACK_FRAMES_POOL );
|
||||
|
||||
if ( !nmi_pools.stack_frames )
|
||||
{
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
ExFreePoolWithTag( proc_affinity, PROC_AFFINITY_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
|
@ -734,7 +734,7 @@ NTSTATUS LaunchNonMaskableInterrupt(
|
|||
if ( !nmi_pools.thread_data_pool )
|
||||
{
|
||||
ExFreePoolWithTag( nmi_pools.stack_frames, STACK_FRAMES_POOL );
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
ExFreePoolWithTag( proc_affinity, PROC_AFFINITY_POOL );
|
||||
return STATUS_ABANDONED;
|
||||
}
|
||||
|
||||
|
@ -743,11 +743,11 @@ NTSTATUS LaunchNonMaskableInterrupt(
|
|||
|
||||
for ( ULONG core = 0; core < NumCores; core++ )
|
||||
{
|
||||
KeInitializeAffinityEx( ProcAffinityPool );
|
||||
KeAddProcessorAffinityEx( ProcAffinityPool, core );
|
||||
KeInitializeAffinityEx( proc_affinity );
|
||||
KeAddProcessorAffinityEx( proc_affinity, core );
|
||||
|
||||
DEBUG_LOG( "Sending NMI" );
|
||||
HalSendNMI( ProcAffinityPool );
|
||||
HalSendNMI( proc_affinity );
|
||||
|
||||
/*
|
||||
* Only a single NMI can be active at any given time, so arbitrarily
|
||||
|
@ -756,7 +756,7 @@ NTSTATUS LaunchNonMaskableInterrupt(
|
|||
KeDelayExecutionThread( KernelMode, FALSE, &delay );
|
||||
}
|
||||
|
||||
ExFreePoolWithTag( ProcAffinityPool, PROC_AFFINITY_POOL );
|
||||
ExFreePoolWithTag( proc_affinity, PROC_AFFINITY_POOL );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -5,34 +5,6 @@
|
|||
|
||||
#include <intrin.h>
|
||||
|
||||
/*
|
||||
* How this will work:
|
||||
*
|
||||
* 1. The KPCRB (processor control block) contains 3 pointers to 3 threads:
|
||||
*
|
||||
* +0x008 CurrentThread : Ptr64 _KTHREAD
|
||||
* +0x010 NextThread : Ptr64 _KTHREAD
|
||||
* +0x018 IdleThread : Ptr64 _KTHREAD
|
||||
*
|
||||
* 2. These threads are stored in a list that is seperate to the KTHREADs linked list.
|
||||
* We know this because if you unlink a process, the threads are still scheduled by
|
||||
* the OS, meaning the OS has a seperate list that it uses to schedule these threads.
|
||||
*
|
||||
* 3. Now from here, we can get thread ID and pass it to PsLookupThreadByThreadId which
|
||||
* takes the thread ID and returns a pointer to the ETHREAD structure. It does this
|
||||
* by indexing the PspCidTable using the TID we pass in.
|
||||
*
|
||||
* What we can potentially observer is that any threads that have been removed from the
|
||||
* PspCidTable will return a null ptr from PsLookupThreadById. In addition to this, we
|
||||
* can also check if the KTHREAD address referenced in the KPCRB is not in the KTHREAD
|
||||
* linked list. Allowing us to find threads removed from both the PspCidTable and the
|
||||
* KTHREAD linked list.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IDEA: we can run a thread on each core to maximise the search, so it would be 3 * num procs
|
||||
*/
|
||||
|
||||
UINT8 thread_found_in_pspcidtable = FALSE;
|
||||
UINT8 thread_found_in_kthreadlist = FALSE;
|
||||
BOOLEAN finished = FALSE;
|
||||
|
@ -76,8 +48,30 @@ VOID ProcessEnumerationCallback(
|
|||
}
|
||||
}
|
||||
|
||||
NTSTATUS ValidateKPCRBThreads(
|
||||
//_In_ PIRP Irp
|
||||
/*
|
||||
* How this will work:
|
||||
*
|
||||
* 1. The KPCRB (processor control block) contains 3 pointers to 3 threads:
|
||||
*
|
||||
* +0x008 CurrentThread : Ptr64 _KTHREAD
|
||||
* +0x010 NextThread : Ptr64 _KTHREAD
|
||||
* +0x018 IdleThread : Ptr64 _KTHREAD
|
||||
*
|
||||
* 2. These threads are stored in a list that is seperate to the KTHREADs linked list.
|
||||
* We know this because if you unlink a process, the threads are still scheduled by
|
||||
* the OS, meaning the OS has a seperate list that it uses to schedule these threads.
|
||||
*
|
||||
* 3. From here we can firstly check if the KTHREAD is within the KTHREAD linked list,
|
||||
* if it is we can then use this to check if its in the PspCidTable by passing it
|
||||
* to PsGetThreadId which returns the thread id by enumerating the PspCidTable and
|
||||
* finding the corresponding object pointer. If the thread id is not found, we know
|
||||
* that it's been removed from the PspCidTable, and if the thread is not in any
|
||||
* process' thread list , we know it's been removed from the KTHREAD linked list.
|
||||
*
|
||||
*/
|
||||
|
||||
VOID ValidateKPCRBThreads(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
@ -93,17 +87,30 @@ NTSTATUS ValidateKPCRBThreads(
|
|||
kprcb = kpcr + KPRCB_OFFSET_FROM_GS_BASE;
|
||||
current_kpcrb_thread = *( UINT64* )( kprcb + KPCRB_CURRENT_THREAD );
|
||||
|
||||
DEBUG_LOG( "Current processor: %lx, current kprcb: %llx, current thread: %llx", KeGetCurrentProcessorNumber(), kprcb, current_kpcrb_thread );
|
||||
|
||||
EnumerateProcessListWithCallbackFunction(
|
||||
ProcessEnumerationCallback
|
||||
);
|
||||
|
||||
DEBUG_LOG( "Thread in psp: %i, thread in list: %i", thread_found_in_pspcidtable, thread_found_in_kthreadlist );
|
||||
|
||||
if ( thread_found_in_kthreadlist == FALSE || thread_found_in_pspcidtable == FALSE )
|
||||
{
|
||||
Irp->IoStatus.Information = sizeof( HIDDEN_SYSTEM_THREAD_REPORT );
|
||||
|
||||
HIDDEN_SYSTEM_THREAD_REPORT report;
|
||||
report.report_code = REPORT_HIDDEN_SYSTEM_THREAD;
|
||||
report.found_in_kthreadlist = thread_found_in_kthreadlist;
|
||||
report.found_in_pspcidtable = thread_found_in_pspcidtable;
|
||||
report.thread_id = PsGetThreadId( current_kpcrb_thread );
|
||||
report.thread_address = current_kpcrb_thread;
|
||||
|
||||
RtlCopyMemory(
|
||||
report.thread,
|
||||
current_kpcrb_thread,
|
||||
sizeof( report.thread ));
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
&report,
|
||||
sizeof( HIDDEN_SYSTEM_THREAD_REPORT ) );
|
||||
}
|
||||
|
||||
current_kpcrb_thread = NULL;
|
||||
|
@ -113,5 +120,4 @@ NTSTATUS ValidateKPCRBThreads(
|
|||
|
||||
KeRevertToUserAffinityThreadEx( old_affinity );
|
||||
}
|
||||
|
||||
}
|
|
@ -11,8 +11,21 @@
|
|||
#define KPROCESS_THREADLIST_OFFSET 0x030
|
||||
#define KTHREAD_THREADLIST_OFFSET 0x2f8
|
||||
|
||||
NTSTATUS ValidateKPCRBThreads(
|
||||
//_In_ PIRP Irp
|
||||
#define REPORT_HIDDEN_SYSTEM_THREAD 90
|
||||
|
||||
VOID ValidateKPCRBThreads(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
typedef struct _HIDDEN_SYSTEM_THREAD_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT found_in_kthreadlist;
|
||||
INT found_in_pspcidtable;
|
||||
UINT64 thread_address;
|
||||
LONG thread_id;
|
||||
CHAR thread[ 4096 ];
|
||||
|
||||
}HIDDEN_SYSTEM_THREAD_REPORT, *PHIDDEN_SYSTEM_THREAD_REPORT;
|
||||
|
||||
#endif
|
|
@ -22,6 +22,7 @@
|
|||
#define REPORT_MODULE_VALIDATION_FAILURE 60
|
||||
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
|
||||
#define REPORT_INVALID_PROCESS_ALLOCATION 80
|
||||
#define REPORT_HIDDEN_SYSTEM_THREAD 90
|
||||
|
||||
enum REPORT_CODES
|
||||
{
|
||||
|
@ -153,6 +154,20 @@ namespace global
|
|||
INT report_code;
|
||||
CHAR process[ 4096 ];
|
||||
};
|
||||
|
||||
/*
|
||||
* No point copying data from the start address here
|
||||
* since people can easily change it.
|
||||
*/
|
||||
struct HIDDEN_SYSTEM_THREAD_REPORT
|
||||
{
|
||||
INT report_code;
|
||||
INT found_in_kthreadlist;
|
||||
INT found_in_pspcidtable;
|
||||
UINT64 thread_address;
|
||||
LONG thread_id;
|
||||
CHAR thread[ 4096 ];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -413,7 +413,31 @@ VOID kernelmode::Driver::NotifyDriverOnProcessTermination()
|
|||
|
||||
VOID kernelmode::Driver::ValidateKPRCBThreads()
|
||||
{
|
||||
BOOLEAN status;
|
||||
DWORD bytes_returned;
|
||||
global::report_structures::HIDDEN_SYSTEM_THREAD_REPORT report;
|
||||
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle,
|
||||
IOCTL_VALIDATE_KPRCB_CURRENT_THREAD,
|
||||
NULL,
|
||||
NULL,
|
||||
&report,
|
||||
sizeof( report ),
|
||||
&bytes_returned,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( status == NULL)
|
||||
{
|
||||
LOG_ERROR( "failed to validate kpcrb threads with status %x", GetLastError() );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( bytes_returned == NULL )
|
||||
return;
|
||||
|
||||
this->report_interface->ServerSend( &report, bytes_returned, SERVER_SEND_MODULE_INTEGRITY_CHECK );
|
||||
}
|
||||
|
||||
VOID kernelmode::Driver::CheckDriverHeartbeat()
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2009, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2010, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2011, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_VALIDATE_KPRCB_CURRENT_THREAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2012, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define MAX_HANDLE_REPORTS_PER_IRP 10
|
||||
|
||||
|
|
Loading…
Reference in a new issue