diff --git a/driver/hw.c b/driver/hw.c index 6314455..31d120d 100644 --- a/driver/hw.c +++ b/driver/hw.c @@ -1,6 +1,8 @@ #include "hw.h" #include "modules.h" +#include "crypt.h" +#include "imports.h" #define PCI_VENDOR_ID_OFFSET 0x00 #define PCI_DEVICE_ID_OFFSET 0x02 @@ -67,11 +69,11 @@ QueryPciDeviceConfigurationSpace(_In_ PDEVICE_OBJECT DeviceObject, _Out_opt_ PVOID Buffer, _In_ UINT32 BufferLength) { - NTSTATUS status = STATUS_UNSUCCESSFUL; - KEVENT event = {0}; - IO_STATUS_BLOCK io = {0}; - PIRP irp = NULL; - PIO_STACK_LOCATION io_stack_location = NULL; + NTSTATUS status = STATUS_UNSUCCESSFUL; + KEVENT event = {0}; + IO_STATUS_BLOCK io = {0}; + PIRP irp = NULL; + PIO_STACK_LOCATION packet = NULL; if (BufferLength == 0) return STATUS_BUFFER_TOO_SMALL; @@ -90,13 +92,12 @@ QueryPciDeviceConfigurationSpace(_In_ PDEVICE_OBJECT DeviceObject, return STATUS_INSUFFICIENT_RESOURCES; } - io_stack_location = IoGetNextIrpStackLocation(irp); - io_stack_location->MinorFunction = IRP_MN_READ_CONFIG; - io_stack_location->Parameters.ReadWriteConfig.WhichSpace = - PCI_WHICHSPACE_CONFIG; - io_stack_location->Parameters.ReadWriteConfig.Offset = Offset; - io_stack_location->Parameters.ReadWriteConfig.Buffer = Buffer; - io_stack_location->Parameters.ReadWriteConfig.Length = BufferLength; + packet = IoGetNextIrpStackLocation(irp); + packet->MinorFunction = IRP_MN_READ_CONFIG; + packet->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG; + packet->Parameters.ReadWriteConfig.Offset = Offset; + packet->Parameters.ReadWriteConfig.Buffer = Buffer; + packet->Parameters.ReadWriteConfig.Length = BufferLength; status = IoCallDriver(DeviceObject, irp); @@ -255,6 +256,38 @@ IsPciConfigurationSpaceFlagged(_In_ PPCI_COMMON_HEADER Configuration) return FALSE; } +STATIC +VOID +ReportBlacklistedPcieDevice(_In_ PDEVICE_OBJECT DeviceObject, + _In_ PPCI_COMMON_HEADER Header) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + UINT32 packet_size = CryptRequestRequiredBufferLength( + sizeof(BLACKLISTED_PCIE_DEVICE_REPORT)); + + PBLACKLISTED_PCIE_DEVICE_REPORT report = + ImpExAllocatePool2(POOL_FLAG_NON_PAGED, packet_size, REPORT_POOL_TAG); + + if (!report) + return; + + INIT_REPORT_PACKET(report, REPORT_BLACKLISTED_PCIE_DEVICE, 0); + + report->device_object = (UINT64)DeviceObject; + report->device_id = Header->DeviceID; + report->vendor_id = Header->VendorID; + + status = CryptEncryptBuffer(report, packet_size); + + if (!NT_SUCCESS(status)) { + DEBUG_ERROR("CryptEncryptBuffer: %lx", status); + ImpExFreePoolWithTag(report, packet_size); + return; + } + + IrpQueueSchedulePacket(report, packet_size); +} + STATIC NTSTATUS PciDeviceQueryCallback(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context) @@ -283,6 +316,7 @@ PciDeviceQueryCallback(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context) DeviceObject, header.DeviceID, header.VendorID); + ReportBlacklistedPcieDevice(DeviceObject, &header); } return status; diff --git a/driver/integrity.c b/driver/integrity.c index 188c998..9835df7 100644 --- a/driver/integrity.c +++ b/driver/integrity.c @@ -1609,7 +1609,7 @@ end: */ STATIC VOID -ReportInvalidSystemModule(_In_ PRTL_MODULE_EXTENDED_INFO Module) +ReportModifiedSystemImage(_In_ PRTL_MODULE_EXTENDED_INFO Module) { NTSTATUS status = STATUS_UNSUCCESSFUL; UINT32 packet_size = CryptRequestRequiredBufferLength( @@ -1684,7 +1684,7 @@ ValidateSystemModule(_In_ PRTL_MODULE_EXTENDED_INFO Module) else { DEBUG_WARNING("**!!** Module: %s text regions are NOT valid **!!**", Module->FullPathName); - ReportInvalidSystemModule(Module); + ReportModifiedSystemImage(Module); } end: @@ -1693,6 +1693,39 @@ end: ExFreePoolWithTag(hash, POOL_TAG_INTEGRITY); } +STATIC +VOID +ReportModifiedSelfDriverImage(_In_ PRTL_MODULE_EXTENDED_INFO Module) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + UINT32 packet_size = CryptRequestRequiredBufferLength( + sizeof(DRIVER_SELF_INTEGRITY_CHECK_REPORT)); + + PDRIVER_SELF_INTEGRITY_CHECK_REPORT report = + ImpExAllocatePool2(POOL_FLAG_NON_PAGED, packet_size, REPORT_POOL_TAG); + + if (!report) + return; + + INIT_REPORT_PACKET(report, REPORT_SELF_DRIVER_PATCHED, 0); + + report->image_base = Module->ImageBase; + report->image_size = Module->ImageSize; + + RtlCopyMemory( + report->path_name, Module->FullPathName, sizeof(report->path_name)); + + status = CryptEncryptBuffer(report, packet_size); + + if (!NT_SUCCESS(status)) { + DEBUG_ERROR("CryptEncryptBuffer: %lx", status); + ImpExFreePoolWithTag(report, packet_size); + return; + } + + IrpQueueSchedulePacket(report, packet_size); +} + NTSTATUS ValidateOurDriverImage() { @@ -1750,10 +1783,13 @@ ValidateOurDriverImage() * module error and stop the users game session ? since module .text * section error would be a large red flag */ - if (CompareHashes(memory_hash, entry->text_hash, SHA_256_HASH_LENGTH)) + if (CompareHashes(memory_hash, entry->text_hash, SHA_256_HASH_LENGTH)) { DEBUG_VERBOSE("Driver image is valid. Integrity check complete"); - else + } + else { DEBUG_WARNING("**!!** Driver image is NOT valid. **!!**"); + ReportModifiedSelfDriverImage(module_info); + } end: @@ -2312,7 +2348,7 @@ end: * the right direction. */ NTSTATUS -InitialiseHeartbeatConfiguration(_Inout_ PHEARTBEAT_CONFIGURATION Configuration) +InitialiseHeartbeatConfiguration(_Out_ PHEARTBEAT_CONFIGURATION Configuration) { NTSTATUS status = STATUS_UNSUCCESSFUL; diff --git a/driver/integrity.h b/driver/integrity.h index c6b5cf7..c36b32a 100644 --- a/driver/integrity.h +++ b/driver/integrity.h @@ -123,7 +123,7 @@ FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context); NTSTATUS InitialiseHeartbeatConfiguration( - _Inout_ PHEARTBEAT_CONFIGURATION Configuration); + _Out_ PHEARTBEAT_CONFIGURATION Configuration); VOID FreeHeartbeatConfiguration(_Inout_ PHEARTBEAT_CONFIGURATION Configuration); diff --git a/driver/io.c b/driver/io.c index c1d4289..86ad5f5 100644 --- a/driver/io.c +++ b/driver/io.c @@ -337,12 +337,12 @@ IrpQueueCompletePacket(_In_ PVOID Buffer, _In_ ULONG BufferSize) } /* - * Not only does this allow reporting threads to continue execution once the - * report is scheduled (which in some cases such as handle reporting is very - * important for performance reasons), but it allows us to safely report from - * within a region guarded by a mutex as we use a spinlock here (for performance - * reasons, we dont need certain time critical threads being slept whilst we - * wait). + * Due to the fact that many reporting structures are holding a mutex when + * scheduling a report packet, we need an alternative queueing option from DPCs + * and spinlocks. Here we will use an array of work items ( + * + * Hmm this is an interesting issue. Not sure how we shall resolve this, for now + * this works well enough. */ VOID IrpQueueSchedulePacket(_In_ PVOID Buffer, _In_ UINT32 BufferLength) diff --git a/driver/types/types.h b/driver/types/types.h index f3a0c49..d140cc2 100644 --- a/driver/types/types.h +++ b/driver/types/types.h @@ -13,7 +13,9 @@ #define REPORT_DPC_STACKWALK 120 #define REPORT_DATA_TABLE_ROUTINE 130 #define REPORT_INVALID_PROCESS_MODULE 140 -#define REPORT_PATCHED_SYSTEM_MODULE 150 +#define REPORT_PATCHED_SYSTEM_MODULE 150 +#define REPORT_SELF_DRIVER_PATCHED 160 +#define REPORT_BLACKLISTED_PCIE_DEVICE 170 #define REPORT_SUBTYPE_NO_BACKING_MODULE 0x0 #define REPORT_SUBTYPE_INVALID_DISPATCH 0x1 @@ -198,4 +200,20 @@ typedef struct _SYSTEM_MODULE_INTEGRITY_CHECK_REPORT { } SYSTEM_MODULE_INTEGRITY_CHECK_REPORT, *PSYSTEM_MODULE_INTEGRITY_CHECK_REPORT; +typedef struct _DRIVER_SELF_INTEGRITY_CHECK_REPORT { + REPORT_PACKET_HEADER header; + UINT64 image_base; + UINT32 image_size; + CHAR path_name[0x100]; + +} DRIVER_SELF_INTEGRITY_CHECK_REPORT, *PDRIVER_SELF_INTEGRITY_CHECK_REPORT; + +typedef struct _BLACKLISTED_PCIE_DEVICE_REPORT { + REPORT_PACKET_HEADER header; + UINT64 device_object; + UINT16 device_id; + UINT16 vendor_id; + +} BLACKLISTED_PCIE_DEVICE_REPORT, *PBLACKLISTED_PCIE_DEVICE_REPORT; + #endif \ No newline at end of file diff --git a/module/helper.cpp b/module/helper.cpp index 24f6369..233e0b0 100644 --- a/module/helper.cpp +++ b/module/helper.cpp @@ -5,50 +5,64 @@ #include "crypt/crypt.h" -void helper::generate_rand_seed() { srand(time(0)); } - -int helper::generate_rand_int(int max) { return std::rand() % max; } - -void helper::sleep_thread(int seconds) { - std::this_thread::sleep_for(std::chrono::seconds(seconds)); +void +helper::generate_rand_seed() +{ + srand(time(0)); } -int helper::get_report_id_from_buffer(void *buffer) { - kernel_interface::report_header *header = - reinterpret_cast( - (uint64_t)buffer + sizeof(kernel_interface::report_header)); - return header->report_code; +int +helper::generate_rand_int(int max) +{ + return std::rand() % max; } -kernel_interface::report_id helper::get_kernel_report_type(void *buffer) { - switch (helper::get_report_id_from_buffer(buffer)) { - case kernel_interface::report_id::report_nmi_callback_failure: - return kernel_interface::report_id::report_nmi_callback_failure; +void +helper::sleep_thread(int seconds) +{ + std::this_thread::sleep_for(std::chrono::seconds(seconds)); +} - case kernel_interface::report_id::report_module_validation_failure: - return kernel_interface::report_id::report_module_validation_failure; +int +helper::get_report_id_from_buffer(void* buffer) +{ + kernel_interface::report_header* header = + reinterpret_cast( + (uint64_t)buffer + sizeof(kernel_interface::report_header)); + return header->report_code; +} - case kernel_interface::report_id::report_illegal_handle_operation: - return kernel_interface::report_id::report_illegal_handle_operation; +kernel_interface::report_id +helper::get_kernel_report_type(void* buffer) +{ + switch (helper::get_report_id_from_buffer(buffer)) { + case kernel_interface::report_id::report_nmi_callback_failure: + return kernel_interface::report_id::report_nmi_callback_failure; - case kernel_interface::report_id::report_invalid_process_allocation: - return kernel_interface::report_id::report_invalid_process_allocation; + case kernel_interface::report_id::report_module_validation_failure: + return kernel_interface::report_id::report_module_validation_failure; - case kernel_interface::report_id::report_hidden_system_thread: - return kernel_interface::report_id::report_hidden_system_thread; + case kernel_interface::report_id::report_illegal_handle_operation: + return kernel_interface::report_id::report_illegal_handle_operation; - case kernel_interface::report_id::report_illegal_attach_process: - return kernel_interface::report_id::report_illegal_attach_process; + case kernel_interface::report_id::report_invalid_process_allocation: + return kernel_interface::report_id::report_invalid_process_allocation; - case kernel_interface::report_id::report_apc_stackwalk: - return kernel_interface::report_id::report_apc_stackwalk; + case kernel_interface::report_id::report_hidden_system_thread: + return kernel_interface::report_id::report_hidden_system_thread; - case kernel_interface::report_id::report_dpc_stackwalk: - return kernel_interface::report_id::report_dpc_stackwalk; + case kernel_interface::report_id::report_illegal_attach_process: + return kernel_interface::report_id::report_illegal_attach_process; - case kernel_interface::report_id::report_data_table_routine: - return kernel_interface::report_id::report_data_table_routine; - } + case kernel_interface::report_id::report_apc_stackwalk: + return kernel_interface::report_id::report_apc_stackwalk; + + case kernel_interface::report_id::report_dpc_stackwalk: + return kernel_interface::report_id::report_dpc_stackwalk; + + case kernel_interface::report_id::report_data_table_routine: + return kernel_interface::report_id::report_data_table_routine; + } } void @@ -156,6 +170,37 @@ print_report_packet(void* buffer) LOG_INFO("********************************"); break; } + case kernel_interface::report_id::report_patched_system_module: { + kernel_interface::system_module_integrity_check_report* r11 = + reinterpret_cast< + kernel_interface::system_module_integrity_check_report*>( + buffer); + LOG_INFO("image_base: %llx", r11->image_base); + LOG_INFO("image_size: %lx", r11->image_size); + LOG_INFO("path_name: %s", r11->path_name); + LOG_INFO("********************************"); + break; + } + case kernel_interface::report_id::report_self_driver_patched: { + kernel_interface::driver_self_integrity_check_report* r12 = + reinterpret_cast< + kernel_interface::driver_self_integrity_check_report*>(buffer); + LOG_INFO("image_base: %llx", r12->image_base); + LOG_INFO("image_size: %lx", r12->image_size); + LOG_INFO("path_name: %s", r12->path_name); + LOG_INFO("********************************"); + break; + } + case kernel_interface::report_id::report_blacklisted_pcie_device: { + kernel_interface::blacklisted_pcie_device_report* r13 = + reinterpret_cast( + buffer); + LOG_INFO("device_object: %llx", r13->device_object); + LOG_INFO("device_id: %x", r13->device_id); + LOG_INFO("vendor_id: %x", r13->vendor_id); + LOG_INFO("********************************"); + break; + } default: LOG_INFO("Invalid report type."); break; } } @@ -172,28 +217,32 @@ print_heartbeat_packet(void* buffer) LOG_INFO("********************************"); } -void helper::print_kernel_report(void *buffer) { - uint32_t size = crypt::get_padded_packet_size( - sizeof(kernel_interface::open_handle_failure_report)); - crypt::decrypt_packet(buffer, size); +void +helper::print_kernel_report(void* buffer) +{ + uint32_t size = crypt::get_padded_packet_size( + sizeof(kernel_interface::open_handle_failure_report)); + crypt::decrypt_packet(buffer, size); - kernel_interface::packet_header *header = - reinterpret_cast(buffer); + kernel_interface::packet_header* header = + reinterpret_cast(buffer); - LOG_INFO("packet type: %lx", header->packet_type); + LOG_INFO("packet type: %lx", header->packet_type); - switch (header->packet_type) - { - case 0: print_report_packet(buffer); break; - case 1: print_heartbeat_packet(buffer); break; - } - + switch (header->packet_type) { + case 0: print_report_packet(buffer); break; + case 1: print_heartbeat_packet(buffer); break; + } } -unsigned __int64 helper::seconds_to_nanoseconds(int seconds) { - return ABSOLUTE(SECONDS(seconds)); +unsigned __int64 +helper::seconds_to_nanoseconds(int seconds) +{ + return ABSOLUTE(SECONDS(seconds)); } -unsigned __int32 helper::seconds_to_milliseconds(int seconds) { - return seconds * 1000; +unsigned __int32 +helper::seconds_to_milliseconds(int seconds) +{ + return seconds * 1000; } \ No newline at end of file diff --git a/module/kernel_interface/kernel_interface.h b/module/kernel_interface/kernel_interface.h index 82a6909..a8f0c67 100644 --- a/module/kernel_interface/kernel_interface.h +++ b/module/kernel_interface/kernel_interface.h @@ -22,7 +22,10 @@ enum report_id { report_apc_stackwalk = 110, report_dpc_stackwalk = 120, report_data_table_routine = 130, - report_invalid_process_module = 140 + report_invalid_process_module = 140, + report_patched_system_module = 150, + report_self_driver_patched = 160, + report_blacklisted_pcie_device = 170 }; #define AES_256_BLOCK_SIZE 16 @@ -126,6 +129,20 @@ struct process_module_validation_report { wchar_t module_path[MODULE_PATH_LEN]; }; +struct system_module_integrity_check_report { + report_header header; + uint64_t image_base; + uint32_t image_size; + char path_name[0x100]; +}; + +struct driver_self_integrity_check_report { + report_header header; + uint64_t image_base; + uint32_t image_size; + char path_name[0x100]; +}; + struct heartbeat_packet { heartbeat_header header; uint32_t heartbeat_count; @@ -134,6 +151,13 @@ struct heartbeat_packet { uint32_t total_heartbeats_completed; }; +struct blacklisted_pcie_device_report { + report_header header; + uint64_t device_object; + uint16_t device_id; + uint16_t vendor_id; +}; + enum apc_operation { operation_stackwalk = 0x1 }; // clang-format off