diff --git a/driver/callbacks.c b/driver/callbacks.c new file mode 100644 index 0000000..da1d6a0 --- /dev/null +++ b/driver/callbacks.c @@ -0,0 +1,138 @@ +#include "callbacks.h" + +#include "common.h" +#include "driver.h" + +#include "queue.h" + +PQUEUE_HEAD report_queue = NULL; + +VOID InitCallbackReportQueue( PBOOLEAN Status ) +{ + report_queue = QueueCreate(); + + if ( report_queue == NULL ) + *Status = FALSE; + + *Status = TRUE; +} + +VOID DeleteCallbackReportQueueHead() +{ + ExFreePoolWithTag( report_queue, QUEUE_POOL_TAG ); +} + +VOID InsertReportToQueue( POPEN_HANDLE_FAILURE_REPORT Report ) +{ + QueuePush( report_queue, Report ); +} + +PVOID PopFirstReportFromQueue( report_queue ) +{ + return QueuePop( report_queue ); +} + +VOID ObPostOpCallbackRoutine( + _In_ PVOID RegistrationContext, + _In_ POB_POST_OPERATION_INFORMATION OperationInformation +) +{ + +} + +OB_PREOP_CALLBACK_STATUS ObPreOpCallbackRoutine( + _In_ PVOID RegistrationContext, + _In_ POB_PRE_OPERATION_INFORMATION OperationInformation +) +{ + UNREFERENCED_PARAMETER( RegistrationContext ); + + /* access mask to completely strip permissions */ + ACCESS_MASK deny_access = SYNCHRONIZE | PROCESS_TERMINATE; + + /* Access mask to be used for crss / lsass */ + ACCESS_MASK downgrade_access = 0; + + /* + * This callback routine is executed in the context of the thread that + * is requesting to open said handle + */ + PEPROCESS process_creator = PsGetCurrentProcess(); + PEPROCESS target_process = ( PEPROCESS )OperationInformation->Object; + + LONG target_process_id = PsGetProcessId( target_process ); + LONG process_creator_id = PsGetProcessId( process_creator ); + + LONG protected_process_id; + LONG parent_process_id; + + GetProtectedProcessId( &protected_process_id ); + GetProtectedProcessParentId( &parent_process_id ); + + LPCSTR process_creator_name = PsGetProcessImageFileName( process_creator ); + LPCSTR target_process_name = PsGetProcessImageFileName( target_process ); + + if ( protected_process_id == target_process_id) + { + if ( !strcmp( process_creator_name, "lsass.exe" ) || !strcmp( process_creator_name, "csrss.exe" ) ) + { + /* We will downgrade these handles later */ + DEBUG_LOG( "Handles created by CSRSS and LSASS are allowed for now..." ); + } + /* NOTE: try allowing only 1 handle from the proc creator */ + else if ( parent_process_id == process_creator_id ) + { + /* Allow handles created by the protected process' creator i.e explorer, cmd etc. */ + DEBUG_LOG( "Process creator: %s handles are fine for now...", process_creator_name ); + } + else + { + OperationInformation->Parameters->CreateHandleInformation.DesiredAccess = deny_access; + OperationInformation->Parameters->DuplicateHandleInformation.DesiredAccess = deny_access; + DEBUG_LOG( "handle stripped from: %s", process_creator_name ); + } + } + + return OB_PREOP_SUCCESS; +} + +VOID ProcessCreateNotifyRoutine( + _In_ HANDLE ParentId, + _In_ HANDLE ProcessId, + _In_ BOOLEAN Create +) +{ + NTSTATUS status; + PEPROCESS parent_process; + PEPROCESS target_process; + LONG parent_process_id; + LPCSTR target_process_name = NULL; + LPCSTR parent_process_name = NULL; + + status = PsLookupProcessByProcessId( ParentId, &parent_process ); + + if ( !NT_SUCCESS( status ) ) + return; + + status = PsLookupProcessByProcessId( ProcessId, &target_process ); + + if ( !NT_SUCCESS( status ) ) + return; + + parent_process_name = PsGetProcessImageFileName( parent_process ); + + if ( !parent_process_name ) + return; + + target_process_name = PsGetProcessImageFileName( target_process ); + + if ( !target_process_name ) + return; + + if ( !strcmp( target_process_name, "notepad.exe") ) + { + parent_process_id = PsGetProcessId( target_process ); + UpdateProtectedProcessId( parent_process_id ); + LOG_INFO( "Protected process parent proc id: %lx", parent_process_id ); + } +} \ No newline at end of file diff --git a/driver/callbacks.h b/driver/callbacks.h new file mode 100644 index 0000000..1d0e860 --- /dev/null +++ b/driver/callbacks.h @@ -0,0 +1,47 @@ +#ifndef CALLBACKS_H +#define CALLBACKS_H + +#include +#include +#include + +typedef struct _OPEN_HANDLE_FAILURE_REPORT +{ + INT report_code; + INT is_kernel_handle; + LONG process_id; + LONG thread_id; + LONG desired_access; + CHAR process_name[ 64 ]; + +}OPEN_HANDLE_FAILURE_REPORT, *POPEN_HANDLE_FAILURE_REPORT; + +//handle access masks +//https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights +#define PROCESS_CREATE_PROCESS 0x0080 +#define PROCESS_TERMINATE 0x0001 +#define PROCESS_CREATE_THREAD 0x0002 +#define PROCESS_DUP_HANDLE 0x0040 +#define PROCESS_QUERY_INFORMATION 0x0400 +#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000 +#define PROCESS_SET_INFORMATION 0x0200 +#define PROCESS_SET_QUOTA 0x0100 +#define PROCESS_SUSPEND_RESUME 0x0800 +#define PROCESS_VM_OPERATION 0x0008 +#define PROCESS_VM_READ 0x0010 +#define PROCESS_VM_WRITE 0x0020 + +VOID ObPostOpCallbackRoutine( + _In_ PVOID RegistrationContext, + _In_ POB_POST_OPERATION_INFORMATION OperationInformation +); + +OB_PREOP_CALLBACK_STATUS ObPreOpCallbackRoutine( + _In_ PVOID RegistrationContext, + _In_ POB_PRE_OPERATION_INFORMATION OperationInformation +); + +VOID InitCallbackReportQueue(PBOOLEAN Status); +VOID DeleteCallbackReportQueueHead(); + +#endif diff --git a/driver/common.h b/driver/common.h index c4e8fec..5a0624a 100644 --- a/driver/common.h +++ b/driver/common.h @@ -116,4 +116,348 @@ Thread Information Block: (GS register) ... */ +#pragma once + +#include +#include + +typedef struct _OBJECT_TYPE +{ + LIST_ENTRY TypeList; + UNICODE_STRING Name; + PVOID DefaultObject; + UCHAR Index; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + PVOID TypeInfo; //_OBJECT_TYPE_INITIALIZER + EX_PUSH_LOCK TypeLock; + ULONG Key; + LIST_ENTRY CallbackList; + +} OBJECT_TYPE, * POBJECT_TYPE; + +typedef struct _PEB_LDR_DATA { + BYTE Reserved1[ 8 ]; + PVOID Reserved2[ 3 ]; + LIST_ENTRY InMemoryOrderModuleList; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +typedef struct _LDR_DATA_TABLE_ENTRY { + PVOID Reserved1[ 2 ]; + LIST_ENTRY InMemoryOrderLinks; + PVOID Reserved2[ 2 ]; + PVOID DllBase; + PVOID Reserved3[ 2 ]; + UNICODE_STRING FullDllName; + BYTE Reserved4[ 8 ]; + PVOID Reserved5[ 3 ]; +#pragma warning(push) +#pragma warning(disable: 4201) // we'll always use the Microsoft compiler + union { + ULONG CheckSum; + PVOID Reserved6; + } DUMMYUNIONNAME; +#pragma warning(pop) + ULONG TimeDateStamp; +} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; + +typedef struct _PEB { + BYTE Reserved1[ 2 ]; + BYTE BeingDebugged; + BYTE Reserved2[ 1 ]; + PVOID Reserved3[ 2 ]; + PPEB_LDR_DATA Ldr; + PVOID ProcessParameters; + PVOID Reserved4[ 3 ]; + PVOID AtlThunkSListPtr; + PVOID Reserved5; + ULONG Reserved6; + PVOID Reserved7; + ULONG Reserved8; + ULONG AtlThunkSListPtr32; + PVOID Reserved9[ 45 ]; + BYTE Reserved10[ 96 ]; + PVOID PostProcessInitRoutine; + BYTE Reserved11[ 128 ]; + PVOID Reserved12[ 1 ]; + ULONG SessionId; +} PEB, * PPEB; + +typedef struct _PEB32 { + UCHAR InheritedAddressSpace; + UCHAR ReadImageFileExecOptions; + UCHAR BeingDebugged; + UCHAR BitField; + ULONG Mutant; + ULONG ImageBaseAddress; + ULONG Ldr; + ULONG ProcessParameters; + ULONG SubSystemData; + ULONG ProcessHeap; + ULONG FastPebLock; + ULONG AtlThunkSListPtr; + ULONG IFEOKey; + ULONG CrossProcessFlags; + ULONG UserSharedInfoPtr; + ULONG SystemReserved; + ULONG AtlThunkSListPtr32; + ULONG ApiSetMap; +} PEB32, * PPEB32; + +typedef struct _PEB_LDR_DATA32 { + ULONG Length; + UCHAR Initialized; + ULONG SsHandle; + LIST_ENTRY32 InLoadOrderModuleList; + LIST_ENTRY32 InMemoryOrderModuleList; + LIST_ENTRY32 InInitializationOrderModuleList; +} PEB_LDR_DATA32, * PPEB_LDR_DATA32; + +typedef struct _LDR_DATA_TABLE_ENTRY32 { + LIST_ENTRY32 InLoadOrderLinks; + LIST_ENTRY32 InMemoryOrderLinks; + LIST_ENTRY32 InInitializationOrderLinks; + ULONG DllBase; + ULONG EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING32 FullDllName; + UNICODE_STRING32 BaseDllName; + ULONG Flags; + USHORT LoadCount; + USHORT TlsIndex; + LIST_ENTRY32 HashLinks; + ULONG TimeDateStamp; +} LDR_DATA_TABLE_ENTRY32, * PLDR_DATA_TABLE_ENTRY32; + +typedef struct _HANDLE_TABLE_ENTRY_INFO +{ + ULONG AuditMask; + ULONG MaxRelativeAccessMask; + +} HANDLE_TABLE_ENTRY_INFO, * PHANDLE_TABLE_ENTRY_INFO; + +typedef union _EXHANDLE +{ + struct + { + int TagBits : 2; + int Index : 30; + } u; + void* GenericHandleOverlay; + ULONG_PTR Value; +} EXHANDLE, * PEXHANDLE; + +#pragma warning(disable : 4214 4201) + +#pragma pack(push, 1) +typedef struct _POOL_HEADER // Size=16 +{ + union + { + struct + { + unsigned long PreviousSize : 8; // Size=4 Offset=0 BitOffset=0 BitCount=8 + unsigned long PoolIndex : 8; // Size=4 Offset=0 BitOffset=8 BitCount=8 + unsigned long BlockSize : 8; // Size=4 Offset=0 BitOffset=16 BitCount=8 + unsigned long PoolType : 8; // Size=4 Offset=0 BitOffset=24 BitCount=8 + }; + unsigned long Ulong1; // Size=4 Offset=0 + }; + unsigned long PoolTag; // Size=4 Offset=4 + union + { + struct _EPROCESS* ProcessBilled; // Size=8 Offset=8 + struct + { + unsigned short AllocatorBackTraceIndex; // Size=2 Offset=8 + unsigned short PoolTagHash; // Size=2 Offset=10 + }; + }; +} POOL_HEADER, * PPOOL_HEADER; +#pragma pack(pop) + +typedef struct _HANDLE_TABLE_ENTRY // Size=16 +{ + union + { + ULONG_PTR VolatileLowValue; // Size=8 Offset=0 + ULONG_PTR LowValue; // Size=8 Offset=0 + struct _HANDLE_TABLE_ENTRY_INFO* InfoTable; // Size=8 Offset=0 + struct + { + ULONG_PTR Unlocked : 1; // Size=8 Offset=0 BitOffset=0 BitCount=1 + ULONG_PTR RefCnt : 16; // Size=8 Offset=0 BitOffset=1 BitCount=16 + ULONG_PTR Attributes : 3; // Size=8 Offset=0 BitOffset=17 BitCount=3 + ULONG_PTR ObjectPointerBits : 44; // Size=8 Offset=0 BitOffset=20 BitCount=44 + }; + }; + union + { + ULONG_PTR HighValue; // Size=8 Offset=8 + struct _HANDLE_TABLE_ENTRY* NextFreeHandleEntry; // Size=8 Offset=8 + union _EXHANDLE LeafHandleValue; // Size=8 Offset=8 + struct + { + ULONG GrantedAccessBits : 25; // Size=4 Offset=8 BitOffset=0 BitCount=25 + ULONG NoRightsUpgrade : 1; // Size=4 Offset=8 BitOffset=25 BitCount=1 + ULONG Spare : 6; // Size=4 Offset=8 BitOffset=26 BitCount=6 + }; + }; + ULONG TypeInfo; // Size=4 Offset=12 +} HANDLE_TABLE_ENTRY, * PHANDLE_TABLE_ENTRY; + +typedef struct _HANDLE_TABLE_FREE_LIST +{ + EX_PUSH_LOCK FreeListLock; + PHANDLE_TABLE_ENTRY FirstFreeHandleEntry; + PHANDLE_TABLE_ENTRY LastFreeHandleEntry; + LONG HandleCount; + ULONG HighWaterMark; +} HANDLE_TABLE_FREE_LIST, * PHANDLE_TABLE_FREE_LIST; + +typedef struct _HANDLE_TRACE_DB_ENTRY +{ + CLIENT_ID ClientId; + PVOID Handle; + ULONG Type; + PVOID StackTrace[ 16 ]; + +} HANDLE_TRACE_DB_ENTRY, * PHANDLE_TRACE_DB_ENTRY; + + + +typedef struct _HANDLE_TRACE_DEBUG_INFO +{ + LONG RefCount; + ULONG TableSize; + ULONG BitMaskFlags; + FAST_MUTEX CloseCompactionLock; + ULONG CurrentStackIndex; + HANDLE_TRACE_DB_ENTRY TraceDb[ 1 ]; + +} HANDLE_TRACE_DEBUG_INFO, * PHANDLE_TRACE_DEBUG_INFO; + +typedef struct _HANDLE_TABLE +{ + ULONG NextHandleNeedingPool; + LONG ExtraInfoPages; + ULONGLONG TableCode; + PEPROCESS QuotaProcess; + LIST_ENTRY HandleTableList; + ULONG UniqueProcessId; + union { + ULONG Flags; + struct { + UCHAR StrictFIFO : 1; + UCHAR EnableHandleExceptions : 1; + UCHAR Rundown : 1; + UCHAR Duplicated : 1; + UCHAR RaiseUMExceptionOnInvalidHandleClose : 1; + }; + }; + EX_PUSH_LOCK HandleContentionEvent; + EX_PUSH_LOCK HandleTableLock; + union { + HANDLE_TABLE_FREE_LIST FreeLists[ 1 ]; + UCHAR ActualEntry[ 32 ]; + }; + + struct _HANDLE_TRACE_DEBUG_INFO* DebugInfo; + +} HANDLE_TABLE, * PHANDLE_TABLE; + +typedef BOOLEAN( *EX_ENUMERATE_HANDLE_ROUTINE )( + IN PHANDLE_TABLE_ENTRY HandleTableEntry, + IN HANDLE Handle, + IN PVOID EnumParameter + ); + +typedef struct _OBJECT_CREATE_INFORMATION +{ + ULONG Attributes; + PVOID RootDirectory; + CHAR ProbeMode; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG SecurityDescriptorCharge; + PVOID SecurityDescriptor; + struct _SECURITY_QUALITY_OF_SERVICE* SecurityQos; + struct _SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService; + +} OBJECT_CREATE_INFORMATION, * POBJECT_CREATE_INFORMATION; + +typedef struct _OBJECT_HEADER +{ + LONGLONG PointerCount; + union { + LONGLONG HandleCount; + PVOID NextToFree; + }; + EX_PUSH_LOCK Lock; + UCHAR TypeIndex; + union { + UCHAR TraceFlags; + struct { + UCHAR DbgRefTrace : 1; + UCHAR DbgTracePermanent : 1; + }; + }; + UCHAR InfoMask; + union { + UCHAR Flags; + struct { + UCHAR NewObject : 1; + UCHAR KernelObject : 1; + UCHAR KernelOnlyAccess : 1; + UCHAR ExclusiveObject : 1; + UCHAR PermanentObject : 1; + UCHAR DefaultSecurityQuota : 1; + UCHAR SingleHandleEntry : 1; + UCHAR DeletedInline : 1; + }; + }; + ULONG Reserved; + union { + POBJECT_CREATE_INFORMATION ObjectCreateInfo; + PVOID QuotaBlockCharged; + }; + PVOID SecurityDescriptor; + QUAD Body; +} OBJECT_HEADER, * POBJECT_HEADER; + +NTKERNELAPI +BOOLEAN +ExEnumHandleTable( + __in PHANDLE_TABLE HandleTable, + __in EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure, + __in PVOID EnumParameter, + __out_opt PHANDLE Handle +); + +NTKERNELAPI +POBJECT_TYPE +NTAPI +ObGetObjectType( + _In_ PVOID Object +); + +typedef struct _EX_PUSH_LOCK_WAIT_BLOCK* PEX_PUSH_LOCK_WAIT_BLOCK; + +NTKERNELAPI +VOID +FASTCALL +ExfUnblockPushLock( + _Inout_ PEX_PUSH_LOCK PushLock, + _Inout_opt_ PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock +); + +LPCSTR +NTSYSAPI +NTAPI +PsGetProcessImageFileName( + PEPROCESS Process +); + #endif diff --git a/driver/driver.c b/driver/driver.c index 76428c7..f49b92f 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -2,6 +2,49 @@ #include "common.h" #include "ioctl.h" +#include "callbacks.h" + +PVOID callback_registration_handle; + +LONG protected_process_id; +LONG protected_process_parent_id; +KGUARDED_MUTEX mutex; + +VOID UpdateProtectedProcessId( + _In_ LONG NewProcessId +) +{ + KeAcquireGuardedMutex( &mutex ); + protected_process_id = NewProcessId; + KeReleaseGuardedMutex( &mutex ); +} + +VOID GetProtectedProcessId( + _Out_ PLONG ProcessId +) +{ + KeAcquireGuardedMutex( &mutex ); + *ProcessId = protected_process_id; + KeReleaseGuardedMutex( &mutex ); +} + +VOID GetProtectedProcessParentId( + _Out_ PLONG ProcessId +) +{ + KeAcquireGuardedMutex( &mutex ); + *ProcessId = protected_process_parent_id; + KeReleaseGuardedMutex( &mutex ); +} + +VOID UpdateProtectedProcessParentId( + _In_ LONG NewProcessId +) +{ + KeAcquireGuardedMutex( &mutex ); + protected_process_parent_id = NewProcessId; + KeReleaseGuardedMutex( &mutex ); +} VOID DriverUnload( _In_ PDRIVER_OBJECT DriverObject @@ -18,6 +61,7 @@ NTSTATUS DriverEntry( { UNREFERENCED_PARAMETER( RegistryPath ); + BOOLEAN flag; NTSTATUS status; status = IoCreateDevice( @@ -49,6 +93,43 @@ NTSTATUS DriverEntry( DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = DeviceControl; DriverObject->DriverUnload = DriverUnload; + KeInitializeGuardedMutex( &mutex ); + + InitCallbackReportQueue(&flag); + + if ( !flag ) + { + IoDeleteSymbolicLink( &DEVICE_SYMBOLIC_LINK ); + IoDeleteDevice( DriverObject->DeviceObject ); + return STATUS_FAILED_DRIVER_ENTRY; + } + + 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, + &callback_registration_handle + ); + + if ( !NT_SUCCESS( status ) ) + { + DeleteCallbackReportQueueHead(); + IoDeleteSymbolicLink( &DEVICE_SYMBOLIC_LINK ); + IoDeleteDevice( DriverObject->DeviceObject ); + return STATUS_FAILED_DRIVER_ENTRY; + } + DEBUG_LOG( "DonnaAC Driver Entry Complete. type: %lx", DriverObject->DeviceObject->DeviceType ); return status; diff --git a/driver/driver.h b/driver/driver.h index 754a5d9..d30eb32 100644 --- a/driver/driver.h +++ b/driver/driver.h @@ -8,4 +8,20 @@ UNICODE_STRING DEVICE_NAME = RTL_CONSTANT_STRING( L"\\Device\\DonnaAC" ); UNICODE_STRING DEVICE_SYMBOLIC_LINK = RTL_CONSTANT_STRING( L"\\??\\DonnaAC" ); +VOID UpdateProtectedProcessId( + _In_ LONG NewProcessId +); + +VOID GetProtectedProcessId( + _Out_ PLONG ProcessId +); + +VOID GetProtectedProcessParentId( + _Out_ PLONG ProcessId +); + +VOID UpdateProtectedProcessParentId( + _In_ LONG NewProcessId +); + #endif \ No newline at end of file diff --git a/driver/driver.vcxproj b/driver/driver.vcxproj index 9578dc5..b91300d 100644 --- a/driver/driver.vcxproj +++ b/driver/driver.vcxproj @@ -117,17 +117,21 @@ + + + + diff --git a/driver/driver.vcxproj.filters b/driver/driver.vcxproj.filters index cb11864..0d49a77 100644 --- a/driver/driver.vcxproj.filters +++ b/driver/driver.vcxproj.filters @@ -36,6 +36,12 @@ Source Files + + Source Files + + + Source Files + @@ -53,5 +59,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/driver/ioctl.c b/driver/ioctl.c index 6caff1b..516591e 100644 --- a/driver/ioctl.c +++ b/driver/ioctl.c @@ -4,6 +4,7 @@ #include "nmi.h" #include "modules.h" +#include "driver.h" NTSTATUS DeviceControl( _In_ PDRIVER_OBJECT DriverObject, @@ -88,6 +89,13 @@ NTSTATUS DeviceControl( break; + case IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH:; + + PDRIVER_INITIATION_INFORMATION information = ( PDRIVER_INITIATION_INFORMATION )Irp->AssociatedIrp.SystemBuffer; + UpdateProtectedProcessId( information->protected_process_id ); + break; + + default: DEBUG_ERROR( "Invalid IOCTL passed to driver" ); break; diff --git a/driver/ioctl.h b/driver/ioctl.h index 3518ac2..18fb8ba 100644 --- a/driver/ioctl.h +++ b/driver/ioctl.h @@ -9,6 +9,13 @@ #define IOCCTL_RUN_NMI_CALLBACKS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2001, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_VALIDATE_DRIVER_OBJECTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2002, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2004, METHOD_BUFFERED, FILE_ANY_ACCESS) + +typedef struct _DRIVER_INITIATION_INFORMATION +{ + LONG protected_process_id; + +} DRIVER_INITIATION_INFORMATION, * PDRIVER_INITIATION_INFORMATION; NTSTATUS DeviceControl( _In_ PDRIVER_OBJECT DriverObject, diff --git a/driver/queue.c b/driver/queue.c new file mode 100644 index 0000000..7a5f9e8 --- /dev/null +++ b/driver/queue.c @@ -0,0 +1,70 @@ +#include "queue.h" + +PQUEUE_HEAD QueueCreate() +{ + PQUEUE_HEAD head = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( PQUEUE_HEAD ), QUEUE_POOL_TAG ); + + if ( !head ) + return NULL; + + head->end = NULL; + head->start = NULL; + + KeInitializeSpinLock( head->lock ); + + return head; +} + +VOID QueuePush( + _In_ PQUEUE_HEAD Head, + _In_ PVOID Data +) +{ + KIRQL irql = KeGetCurrentIrql(); + KeAcquireSpinLock( Head->lock, &irql ); + + PQUEUE_NODE temp = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( QUEUE_NODE ), QUEUE_POOL_TAG ); + + if ( !temp ) + goto end; + + temp->data = Data; + temp->lock = Head->lock; + + if ( Head->end != NULL ) + Head->end->next = temp; + + Head->end = temp; + + if ( Head->start == NULL ) + Head->start = temp; + +end: + KeReleaseSpinLock( Head->lock, irql ); +} + +PVOID QueuePop( + _In_ PQUEUE_HEAD Head +) +{ + KIRQL irql = KeGetCurrentIrql(); + KeAcquireSpinLock( Head->lock, &irql ); + + PVOID data = NULL; + PQUEUE_NODE temp = Head->start; + + if ( temp == NULL ) + goto end; + + data = temp->data; + Head->start = temp->next; + + if ( Head->end == temp ) + Head->end = NULL; + + ExFreePoolWithTag( temp, QUEUE_POOL_TAG ); + +end: + KeReleaseSpinLock( Head->lock, irql ); + return data; +} diff --git a/driver/queue.h b/driver/queue.h new file mode 100644 index 0000000..bfc06d6 --- /dev/null +++ b/driver/queue.h @@ -0,0 +1,37 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include + +#define QUEUE_POOL_TAG 'qqqq' + +typedef struct _QUEUE_NODE +{ + struct _QUEUE_NODE* next; + PKSPIN_LOCK lock; + PVOID data; + +}QUEUE_NODE, *PQUEUE_NODE; + +typedef struct QUEUE_HEAD +{ + struct _QUEUE_NODE* start; + struct _QUEUE_NODE* end; + PKSPIN_LOCK lock; + +}QUEUE_HEAD, *PQUEUE_HEAD; + +PQUEUE_NODE QueueCreate(); + +VOID QueuePush( + _In_ PQUEUE_HEAD Head, + _In_ PVOID Data +); + +PVOID QueuePop( + _In_ PQUEUE_HEAD Head +); + + + +#endif \ No newline at end of file diff --git a/service/Types.cs b/service/Types.cs index ec210e9..8528a51 100644 --- a/service/Types.cs +++ b/service/Types.cs @@ -10,16 +10,12 @@ namespace service { namespace Types { - [StructLayout(LayoutKind.Explicit)] + [StructLayout(LayoutKind.Sequential)] public unsafe struct MODULE_VERIFICATION_CHECKSUM_FAILURE { - [FieldOffset(0)] public int ReportCode; - [FieldOffset(0)] public UInt64 ModuleBaseAddress; - [FieldOffset(0)] public UInt64 ModuleSize; - [FieldOffset(0)] public fixed char ModuleName[512]; } diff --git a/service/Worker.cs b/service/Worker.cs index c88e48b..699fe2b 100644 --- a/service/Worker.cs +++ b/service/Worker.cs @@ -1,4 +1,5 @@ using System.IO.Pipes; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using service.Types; @@ -193,6 +194,19 @@ namespace service Marshal.FreeHGlobal(ptr); } } + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern bool GetNamedPipeClientProcessId(IntPtr Pipe, out uint ClientProcessId); + public static uint GetNamedPipeClientProcId(NamedPipeServerStream PipeServer) + { + UInt32 procId; + IntPtr pipeHandle = PipeServer.SafePipeHandle.DangerousGetHandle(); + + if (GetNamedPipeClientProcessId(pipeHandle, out procId)) + return procId; + + return 0; + } } } #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously diff --git a/user/km/driver.cpp b/user/km/driver.cpp index 8ffe186..6dff5d7 100644 --- a/user/km/driver.cpp +++ b/user/km/driver.cpp @@ -130,16 +130,92 @@ void kernelmode::Driver::VerifySystemModules() free( buffer ); } -void kernelmode::Driver::EnableObRegisterCallbacks() +/* +* HOW THIS WILL WORK: +* +* 1. On driver initiation, ObRegisterCallbacks will be registered +* 2. Each time a process that is not whitelisted tries to open a handle +* to our game we will store the report in an a report queue +* 3. the user mode app will then periodically query the driver asking +* how many pending reports there are +* 4. once the number is received, the app will allocate a buffer large enough +* for all the reports and once again call CompleteQueuedCallbackReports +* 5. This will then retrieve the reports into the buffer and from there +* we can iteratively report them the same way as we do with the system +* modules. +*/ + +bool kernelmode::Driver::QueueCallbackReportIrp(PHANDLE Event) { + if ( !Event ) + return false; + + OVERLAPPED io; + BOOLEAN status; + DWORD bytes_returned; + global::report_structures::OPEN_HANDLE_FAILURE_REPORT report; + + io.hEvent = *Event; + + status = DeviceIoControl( + this->driver_handle, + IOCTL_MONITOR_CALLBACKS_FOR_REPORTS, + NULL, + NULL, + &report, + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT ), + &bytes_returned, + &io + ); + + if ( status == NULL ) + { + LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() ); + return false; + } + + WaitForSingleObject( io.hEvent, INFINITE ); + + /* we EXPECTED to receive bytes so this is an error */ + if ( bytes_returned == NULL ) + return false; + + + } -void kernelmode::Driver::DisableObRegisterCallbacks() +void kernelmode::Driver::NotifyDriverOnProcessLaunch() { + BOOLEAN status; + kernelmode::DRIVER_INITIATION_INFORMATION information; + information.protected_process_id = GetCurrentProcessId(); + + status = DeviceIoControl( + this->driver_handle, + IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH, + &information, + sizeof( kernelmode::DRIVER_INITIATION_INFORMATION ), + NULL, + NULL, + NULL, + NULL + ); + + if ( status == NULL ) + LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() ); +} + +void kernelmode::Driver::CompleteQueuedCallbackReports() +{ + } void kernelmode::Driver::EnableProcessLoadNotifyCallbacks() { + /* + * note: no need for these since when the dll is loaded it will simply + * notify the driver. + */ } void kernelmode::Driver::DisableProcessLoadNotifyCallbacks() @@ -150,10 +226,6 @@ void kernelmode::Driver::ValidateKPRCBThreads() { } -void kernelmode::Driver::CheckForHypervisor() -{ -} - void kernelmode::Driver::CheckDriverHeartbeat() { } diff --git a/user/km/driver.h b/user/km/driver.h index dd20d00..64162a1 100644 --- a/user/km/driver.h +++ b/user/km/driver.h @@ -8,6 +8,8 @@ #define IOCCTL_RUN_NMI_CALLBACKS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2001, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_VALIDATE_DRIVER_OBJECTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2002, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MONITOR_CALLBACKS_FOR_REPORTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2003, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2004, METHOD_BUFFERED, FILE_ANY_ACCESS) namespace kernelmode { @@ -22,15 +24,20 @@ namespace kernelmode void RunNmiCallbacks(); void VerifySystemModules(); - void EnableObRegisterCallbacks(); - void DisableObRegisterCallbacks(); + bool QueueCallbackReportIrp( PHANDLE Event ); + void NotifyDriverOnProcessLaunch(); + void CompleteQueuedCallbackReports(); void EnableProcessLoadNotifyCallbacks(); void DisableProcessLoadNotifyCallbacks(); void ValidateKPRCBThreads(); - void CheckForHypervisor(); void CheckDriverHeartbeat(); /* todo: driver integrity check */ }; + + struct DRIVER_INITIATION_INFORMATION + { + LONG protected_process_id; + }; } #endif diff --git a/user/km/kmanager.cpp b/user/km/kmanager.cpp index 8400b2f..21a9fc5 100644 --- a/user/km/kmanager.cpp +++ b/user/km/kmanager.cpp @@ -15,3 +15,8 @@ void kernelmode::KManager::VerifySystemModules() { this->thread_pool->QueueJob( [ this ]() { this->driver_interface->VerifySystemModules(); } ); } + +void kernelmode::KManager::MonitorCallbackReports() +{ + +} diff --git a/user/km/kmanager.h b/user/km/kmanager.h index 5d1ff9b..857ce55 100644 --- a/user/km/kmanager.h +++ b/user/km/kmanager.h @@ -19,6 +19,7 @@ namespace kernelmode void RunNmiCallbacks(); void VerifySystemModules(); + void MonitorCallbackReports(); }; } diff --git a/user/report.h b/user/report.h index 95a5b44..ac8d1c7 100644 --- a/user/report.h +++ b/user/report.h @@ -33,7 +33,7 @@ namespace global Report( std::shared_ptr ThreadPool, LPTSTR PipeName ); - /* lock buffer, copy report, send to service then clear buffer */ + /* lock buffer, attach header, copy report, send to service then clear buffer */ template void ReportViolation( T* Report ) { @@ -105,6 +105,16 @@ namespace global UINT64 driver_size; CHAR driver_name[ 128 ]; }; + + struct OPEN_HANDLE_FAILURE_REPORT + { + INT report_code; + INT is_kernel_handle; + LONG process_id; + LONG thread_id; + LONG desired_access; + CHAR process_name[ 64 ]; + }; } }