From af62e47949df287fdd7c1d930134132ec2bd9a68 Mon Sep 17 00:00:00 2001 From: lhodges1 Date: Wed, 23 Aug 2023 22:14:20 +1000 Subject: [PATCH] working on integrity checks --- driver/integrity.c | 95 ++++++++++++++++++++++++++++++++------------ driver/integrity.h | 4 ++ driver/ioctl.c | 48 +++++++++++++++++++++- user/client.cpp | 2 + user/km/driver.cpp | 88 +++++++++++++++++++++++++++++++++------- user/km/driver.h | 22 +++++----- user/km/kmanager.cpp | 10 +++++ user/km/kmanager.h | 10 +++-- user/main.cpp | 2 +- 9 files changed, 223 insertions(+), 58 deletions(-) diff --git a/driver/integrity.c b/driver/integrity.c index 8551dcb..b36bba8 100644 --- a/driver/integrity.c +++ b/driver/integrity.c @@ -3,6 +3,47 @@ #include "common.h" #include "modules.h" +/* +* note: this can be put into its own function wihtout an IRP as argument then it can be used +* in both the get driver image ioctl handler and the CopyDriverExecvutableRegions func +*/ +NTSTATUS GetDriverImageSize( + _In_ PIRP Irp +) +{ + NTSTATUS status; + SYSTEM_MODULES modules = { 0 }; + PRTL_MODULE_EXTENDED_INFO driver_info; + + status = GetSystemModuleInformation( &modules ); + + if ( !NT_SUCCESS( status ) ) + { + DEBUG_ERROR( "GetSystemModuleInformation failed with status %x", status ); + return status; + } + + driver_info = FindSystemModuleByName( + "driver.sys", + &modules + ); + + Irp->IoStatus.Information = sizeof( ULONG ); + RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &driver_info->ImageSize, sizeof( ULONG ) ); + + if (modules.address ) + ExFreePoolWithTag( modules.address, SYSTEM_MODULES_POOL ); + + return status; +} + +/* +* Instead of copying pages with the EDB (execute disable bit) not set, I am simply +* copying the entire image which we can then send to the server which can then can +* analyse the executable sections from there. Until I find a better way to enumerate +* kernel memory without having to walk the pages tables to check the EDB bit this +* is how I will be doing it. c: +*/ NTSTATUS CopyDriverExecutableRegions( _In_ PIRP Irp ) @@ -10,10 +51,10 @@ NTSTATUS CopyDriverExecutableRegions( NTSTATUS status; SYSTEM_MODULES modules = { 0 }; PRTL_MODULE_EXTENDED_INFO driver_info; - MEMORY_BASIC_INFORMATION region_info; - SIZE_T return_length; - PVOID current; - INT count = 0; + MM_COPY_ADDRESS address; + PVOID mapped_address; + PHYSICAL_ADDRESS physical_address; + SIZE_T bytes_returned; status = GetSystemModuleInformation( &modules ); @@ -28,33 +69,35 @@ NTSTATUS CopyDriverExecutableRegions( &modules ); - current = driver_info->ImageBase; - Irp->IoStatus.Information = driver_info->ImageSize; - while (NT_SUCCESS( NtQueryVirtualMemory( - NtCurrentProcess(), - current, - MemoryBasicInformation, - ®ion_info, - sizeof( MEMORY_BASIC_INFORMATION ), - &return_length - ))) + /* + * Map the drivers physical memory into our IO space, then copy it into + * our IRP buffer. + */ + physical_address.QuadPart = MmGetPhysicalAddress( driver_info->ImageBase ).QuadPart; + + mapped_address = MmMapIoSpace( + physical_address, + driver_info->ImageSize, + MmNonCached + ); + + if ( !mapped_address ) { - if ( region_info.AllocationProtect & PAGE_EXECUTE ) - { - RtlCopyMemory( - (UINT64)Irp->AssociatedIrp.SystemBuffer + count * region_info.RegionSize, - current, - region_info.RegionSize - ); - - DEBUG_LOG( "Copied region at address: %p, with protect: %lx", current, region_info.AllocationProtect ); - } - - current = (UINT64)current + region_info.RegionSize; + DEBUG_ERROR( "Failed to MmMapIoSpace " ); + goto end; } + RtlCopyMemory( + Irp->AssociatedIrp.SystemBuffer, + mapped_address, + driver_info->ImageSize + ); + + if ( !NT_SUCCESS( status ) ) + DEBUG_ERROR( "MmCopyMemory failed with status %x", status ); + end: Irp->IoStatus.Status = status; diff --git a/driver/integrity.h b/driver/integrity.h index f0feb75..d43ba95 100644 --- a/driver/integrity.h +++ b/driver/integrity.h @@ -9,4 +9,8 @@ NTSTATUS CopyDriverExecutableRegions( _In_ PIRP Irp ); +NTSTATUS GetDriverImageSize( + _In_ PIRP Irp +); + #endif \ No newline at end of file diff --git a/driver/ioctl.c b/driver/ioctl.c index c8e8512..82a43f1 100644 --- a/driver/ioctl.c +++ b/driver/ioctl.c @@ -126,13 +126,59 @@ NTSTATUS DeviceControl( case IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS: - status = CopyDriverExecutableRegions( Irp ); + status = PsCreateSystemThread( + &handle, + PROCESS_ALL_ACCESS, + NULL, + NULL, + NULL, + CopyDriverExecutableRegions, + Irp + ); + + if ( !NT_SUCCESS( status ) ) + { + DEBUG_ERROR( "Failed to start system thread to get executable regions" ); + goto end; + } + + status = ObReferenceObjectByHandle( + handle, + THREAD_ALL_ACCESS, + *PsThreadType, + KernelMode, + &thread, + NULL + ); + + if ( !NT_SUCCESS( status ) ) + { + DEBUG_ERROR( "ObReferenceObjectbyhandle failed with status %lx", status ); + ZwClose( handle ); + goto end; + } + + PAGED_CODE(); + + KeWaitForSingleObject( thread, Executive, KernelMode, FALSE, NULL );; + + ZwClose( handle ); + ObDereferenceObject( thread ); if ( !NT_SUCCESS( status ) ) DEBUG_ERROR( "Failed to retrieve executable regions" ); break; + case IOCTL_REQUEST_TOTAL_MODULE_SIZE: + + status = GetDriverImageSize( Irp ); + + if ( !NT_SUCCESS( status ) ) + DEBUG_ERROR( "Failed to retrieve driver image size" ); + + break; + default: DEBUG_ERROR( "Invalid IOCTL passed to driver" ); break; diff --git a/user/client.cpp b/user/client.cpp index 008db1f..9c9611c 100644 --- a/user/client.cpp +++ b/user/client.cpp @@ -44,6 +44,8 @@ void global::Client::ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId) header_extension.current_packet_number = count; header_extension.packet_size = ( count + 1 ) == total_packets ? remaining_bytes : SEND_BUFFER_SIZE; + LOG_INFO( "current packet number: %lx, packet size: %lx", header_extension.current_packet_number, header_extension.packet_size ); + memcpy( PVOID( ( UINT64 )this->send_buffer + sizeof( global::headers::PIPE_PACKET_HEADER ) ), &header_extension, sizeof(global::headers::PIPE_PACKET_SEND_EXTENSION_HEADER)); diff --git a/user/km/driver.cpp b/user/km/driver.cpp index 907f021..5310d69 100644 --- a/user/km/driver.cpp +++ b/user/km/driver.cpp @@ -22,7 +22,7 @@ kernelmode::Driver::Driver( LPCWSTR DriverName, std::shared_ptr LOG_ERROR( "Failed to open handle to driver with status 0x%x", GetLastError() ); } -void kernelmode::Driver::RunNmiCallbacks() +VOID kernelmode::Driver::RunNmiCallbacks() { BOOLEAN status; DWORD bytes_returned; @@ -60,7 +60,7 @@ void kernelmode::Driver::RunNmiCallbacks() * 2. Checks the IOCTL dispatch routines to ensure they lie within the module */ -void kernelmode::Driver::VerifySystemModules() +VOID kernelmode::Driver::VerifySystemModules() { BOOLEAN status; DWORD bytes_returned; @@ -145,7 +145,7 @@ void kernelmode::Driver::VerifySystemModules() * modules. */ -void kernelmode::Driver::QueryReportQueue() +VOID kernelmode::Driver::QueryReportQueue() { BOOLEAN status; DWORD bytes_returned; @@ -199,7 +199,7 @@ end: free( buffer ); } -void kernelmode::Driver::RunCallbackReportQueue() +VOID kernelmode::Driver::RunCallbackReportQueue() { /*TODO have some volatile flag instead */ while ( true ) @@ -209,7 +209,7 @@ void kernelmode::Driver::RunCallbackReportQueue() } } -void kernelmode::Driver::NotifyDriverOnProcessLaunch() +VOID kernelmode::Driver::NotifyDriverOnProcessLaunch() { BOOLEAN status; kernelmode::DRIVER_INITIATION_INFORMATION information; @@ -230,7 +230,7 @@ void kernelmode::Driver::NotifyDriverOnProcessLaunch() LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() ); } -void kernelmode::Driver::DetectSystemVirtualization() +VOID kernelmode::Driver::DetectSystemVirtualization() { BOOLEAN status; HYPERVISOR_DETECTION_REPORT report; @@ -259,7 +259,7 @@ void kernelmode::Driver::DetectSystemVirtualization() /* shutdown the application or smth lmao */ } -void kernelmode::Driver::CheckHandleTableEntries() +VOID kernelmode::Driver::CheckHandleTableEntries() { BOOLEAN status; DWORD bytes_returned; @@ -284,22 +284,80 @@ void kernelmode::Driver::CheckHandleTableEntries() LOG_ERROR( "CheckHandleTableEntries failed with status %x", status ); } -void kernelmode::Driver::RequestModuleExecutableRegions() +VOID kernelmode::Driver::RequestModuleExecutableRegions() { BOOLEAN status; + DWORD bytes_returned; + ULONG module_size; + PVOID buffer; + + module_size = this->RequestTotalModuleSize(); + + if ( module_size == NULL ) + { + LOG_ERROR( "RequestTotalModuleSize failed lolz" ); + return; + } + + LOG_INFO( "module size: %lx", module_size ); + + buffer = malloc( module_size ); + + if ( !buffer ) + return; + + status = DeviceIoControl( + this->driver_handle, + IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS, + NULL, + NULL, + buffer, + module_size, + &bytes_returned, + NULL + ); + + if ( status == NULL ) + { + LOG_ERROR( "failed to retrieve module executable regions lozl %x", GetLastError() ); + goto end; + } + + LOG_INFO( "bytes returned: %lx", bytes_returned ); + +end: + free( buffer ); } -void kernelmode::Driver::RequestTotalModuleSize() +ULONG kernelmode::Driver::RequestTotalModuleSize() +{ + BOOLEAN status; + DWORD bytes_returned; + ULONG module_size; + + status = DeviceIoControl( + this->driver_handle, + IOCTL_REQUEST_TOTAL_MODULE_SIZE, + NULL, + NULL, + &module_size, + sizeof(ULONG), + &bytes_returned, + NULL + ); + + if ( status == NULL ) + LOG_ERROR( "CheckHandleTableEntries failed with status %x", status ); + + return module_size; +} + +VOID kernelmode::Driver::ValidateKPRCBThreads() { } -void kernelmode::Driver::ValidateKPRCBThreads() -{ - -} - -void kernelmode::Driver::CheckDriverHeartbeat() +VOID kernelmode::Driver::CheckDriverHeartbeat() { } diff --git a/user/km/driver.h b/user/km/driver.h index 1fb65b3..2e3723e 100644 --- a/user/km/driver.h +++ b/user/km/driver.h @@ -27,22 +27,22 @@ namespace kernelmode LPCWSTR driver_name; std::shared_ptr report_interface; - void QueryReportQueue(); - void RequestTotalModuleSize(); + VOID QueryReportQueue(); + ULONG RequestTotalModuleSize(); public: Driver(LPCWSTR DriverName, std::shared_ptr ReportInterface ); - void RunNmiCallbacks(); - void VerifySystemModules(); - void RunCallbackReportQueue(); - void NotifyDriverOnProcessLaunch(); - void DetectSystemVirtualization(); - void ValidateKPRCBThreads(); - void CheckDriverHeartbeat(); - void CheckHandleTableEntries(); - void RequestModuleExecutableRegions(); + VOID RunNmiCallbacks(); + VOID VerifySystemModules(); + VOID RunCallbackReportQueue(); + VOID NotifyDriverOnProcessLaunch(); + VOID DetectSystemVirtualization(); + VOID ValidateKPRCBThreads(); + VOID CheckDriverHeartbeat(); + VOID CheckHandleTableEntries(); + VOID RequestModuleExecutableRegions(); /* todo: driver integrity check */ }; diff --git a/user/km/kmanager.cpp b/user/km/kmanager.cpp index c67a85e..a52b81b 100644 --- a/user/km/kmanager.cpp +++ b/user/km/kmanager.cpp @@ -25,3 +25,13 @@ void kernelmode::KManager::DetectSystemVirtualization() { this->thread_pool->QueueJob( [ this ]() { this->driver_interface->DetectSystemVirtualization(); } ); } + +void kernelmode::KManager::EnumerateHandleTables() +{ + this->thread_pool->QueueJob( [ this ]() { this->driver_interface->CheckHandleTableEntries(); } ); +} + +void kernelmode::KManager::RequestModuleExecutableRegionsForIntegrityCheck() +{ + this->thread_pool->QueueJob( [ this ]() { this->driver_interface->RequestModuleExecutableRegions(); } ); +} \ No newline at end of file diff --git a/user/km/kmanager.h b/user/km/kmanager.h index 20a6b62..b5a1977 100644 --- a/user/km/kmanager.h +++ b/user/km/kmanager.h @@ -17,10 +17,12 @@ namespace kernelmode public: KManager( LPCWSTR DriverName, std::shared_ptr ThreadPool, std::shared_ptr ReportInterface); - void RunNmiCallbacks(); - void VerifySystemModules(); - void MonitorCallbackReports(); - void DetectSystemVirtualization(); + VOID RunNmiCallbacks(); + VOID VerifySystemModules(); + VOID MonitorCallbackReports(); + VOID DetectSystemVirtualization(); + VOID EnumerateHandleTables(); + VOID RequestModuleExecutableRegionsForIntegrityCheck(); }; } diff --git a/user/main.cpp b/user/main.cpp index 8a88866..28c2062 100644 --- a/user/main.cpp +++ b/user/main.cpp @@ -31,7 +31,7 @@ DWORD WINAPI Init(HINSTANCE hinstDLL) //kmanager.MonitorCallbackReports(); //kmanager.RunNmiCallbacks(); //kmanager.VerifySystemModules(); - kmanager.DetectSystemVirtualization(); + kmanager.RequestModuleExecutableRegionsForIntegrityCheck(); //umanager.ValidateProcessModules(); //umanager.ValidateProcessMemory();