enhance smbios parsing to automatically detect system

This commit is contained in:
lhodges1 2023-12-26 02:54:35 +11:00
parent f3fafd5bc9
commit 1eff01c8e1
24 changed files with 1718 additions and 1508 deletions

View file

@ -103,29 +103,6 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_ST
#define MAXIMUM_APC_CONTEXTS 10
/*
* Determines whether a protection routine is active. This allows us to deactivate a method based on
* some criteria, such as windows version. Some things should never be disabled though, so having
* them as an option here such as the integrity check is probably not the best idea.
*/
typedef struct _PROTECTION_METHOD_FLAGS
{
BOOLEAN process_module_verification;
BOOLEAN nmi_callbacks;
BOOLEAN apc_stackwalk;
BOOLEAN ipi_stackwalk;
BOOLEAN validate_driver_objects;
BOOLEAN virtualization_check;
BOOLEAN enumerate_handle_tables;
BOOLEAN unlinked_process_scan;
BOOLEAN kpcrb_validation;
BOOLEAN driver_integrity_check;
BOOLEAN attached_threads;
BOOLEAN validate_system_modules;
BOOLEAN ept_hook;
} PROTECTION_METHOD_FLAGS, *PPROTECTION_METHOD_FLAGS;
typedef struct _DRIVER_CONFIG
{
UNICODE_STRING unicode_driver_name;
@ -1008,8 +985,8 @@ DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
* This is the issue with using APCs, we have very little safe control over when they
* complete and thus when we can free them.. For now, thisl do.
*/
while (DrvUnloadFreeAllApcContextStructures() == FALSE)
YieldProcessor();
while (DrvUnloadFreeAllApcContextStructures() == FALSE)
YieldProcessor();
DrvUnloadUnregisterObCallbacks();
DrvUnloadFreeThreadList();
@ -1125,26 +1102,184 @@ DrvLoadInitialiseProcessConfig()
KeInitializeGuardedMutex(&process_config.lock);
}
/*
* Values returned from CPUID that are equval to the vendor string
*/
#define CPUID_AUTHENTIC_AMD_EBX 0x68747541
#define CPUID_AUTHENTIC_AMD_EDX 0x69746e65
#define CPUID_AUTHENTIC_AMD_ECX 0x444d4163
#define CPUID_GENUINE_INTEL_EBX 0x756e6547
#define CPUID_GENUINE_INTEL_EDX 0x49656e69
#define CPUID_GENUINE_INTEL_ECX 0x6c65746e
STATIC
NTSTATUS
GetSystemProcessorType()
{
UINT32 cpuid[4] = {0};
__cpuid(cpuid, 0);
DEBUG_VERBOSE("Cpuid: EBX: %lx, ECX: %lx, EDX: %lx", cpuid[1], cpuid[2], cpuid[3]);
if (cpuid[1] == CPUID_AUTHENTIC_AMD_EBX && cpuid[2] == CPUID_AUTHENTIC_AMD_ECX &&
cpuid[3] == CPUID_AUTHENTIC_AMD_EDX)
{
driver_config.system_information.processor = GenuineIntel;
return STATUS_SUCCESS;
}
else if (cpuid[1] == CPUID_GENUINE_INTEL_EBX && cpuid[2] == CPUID_GENUINE_INTEL_ECX &&
cpuid[3] == CPUID_GENUINE_INTEL_EDX)
{
driver_config.system_information.processor = AuthenticAmd;
return STATUS_SUCCESS;
}
else
{
driver_config.system_information.processor = Unknown;
return STATUS_UNSUCCESSFUL;
}
}
/*
* Even though we are technically not meant to be operating when running under a virtualized system,
* it is still useful to test the attainment of system information under a virtualized system for
* testing purposes.
*/
STATIC
NTSTATUS
ParseSmbiosForGivenSystemEnvironment()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = ParseSMBIOSTable(&driver_config.system_information.vendor,
VENDOR_STRING_MAX_LENGTH,
SmbiosInformation,
SMBIOS_VENDOR_STRING_SUB_INDEX);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ParseSMBIOSTable failed with status %x", status);
return status;
}
if (strstr(&driver_config.system_information.vendor, "VMware, Inc"))
driver_config.system_information.environment = Vmware;
else if (strstr(&driver_config.system_information.vendor, "innotek GmbH"))
driver_config.system_information.environment = VirtualBox;
else
driver_config.system_information.environment = NativeWindows;
switch (driver_config.system_information.environment)
{
case NativeWindows:
{
status = ParseSMBIOSTable(&driver_config.system_information.motherboard_serial,
MOTHERBOARD_SERIAL_CODE_LENGTH,
VendorSpecificInformation,
SMBIOS_NATIVE_SERIAL_NUMBER_SUB_INDEX);
break;
}
case Vmware:
{
status = ParseSMBIOSTable(&driver_config.system_information.motherboard_serial,
MOTHERBOARD_SERIAL_CODE_LENGTH,
SystemInformation,
SMBIOS_VMWARE_SERIAL_NUMBER_SUB_INDEX);
break;
}
case VirtualBox:
default: DEBUG_WARNING("Environment type not supported."); return STATUS_NOT_SUPPORTED;
}
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ParseSMBIOSTable failed with status %x", status);
return status;
}
return status;
}
STATIC
NTSTATUS
DrvLoadGatherSystemEnvironmentSettings()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
/*
* On Vmware, the APERF_MSR is not emulated hence this will return TRUE.
*/
if (APERFMsrTimingCheck())
driver_config.system_information.virtualised_environment = TRUE;
status = GetOsVersionInformation(&driver_config.system_information.os_information);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetOsVersionInformation failed with status %x", status);
return status;
}
status = GetSystemProcessorType();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetSystemProcessorType failed with status %x", status);
return status;
}
status = ParseSmbiosForGivenSystemEnvironment();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ParseSmbiosForGivenSystemEnvironment failed with status %x", status);
DrvUnloadFreeConfigStrings();
return status;
}
status =
GetHardDiskDriveSerialNumber(&driver_config.system_information.drive_0_serial,
sizeof(driver_config.system_information.drive_0_serial));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetHardDiskDriverSerialNumber failed with status %x", status);
DrvUnloadFreeConfigStrings();
return status;
}
DEBUG_VERBOSE("OS Major Version: %lx, Minor Version: %lx, Build Number: %lx",
driver_config.system_information.os_information.dwMajorVersion,
driver_config.system_information.os_information.dwMinorVersion,
driver_config.system_information.os_information.dwBuildNumber);
DEBUG_VERBOSE("Environment type: %lx", driver_config.system_information.environment);
DEBUG_VERBOSE("Processor type: %lx", driver_config.system_information.processor);
DEBUG_VERBOSE("Motherboard serial: %s",
driver_config.system_information.motherboard_serial);
DEBUG_VERBOSE("Drive 0 serial: %s", driver_config.system_information.drive_0_serial);
return status;
}
STATIC
NTSTATUS
DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
PAGED_CODE();
NTSTATUS status = STATUS_UNSUCCESSFUL;
/* 3rd page acts as a null terminator for the callback routine */
NTSTATUS status = STATUS_UNSUCCESSFUL;
RTL_QUERY_REGISTRY_TABLE query_table[3] = {0};
DEBUG_VERBOSE("Initialising driver configuration");
KeInitializeGuardedMutex(&driver_config.lock);
/*
* Lets do something cheeky and not reference our driver object here even though we do hold
* a reference to it, purely for APC reasons...
*/
driver_config.unload_in_progress = FALSE;
driver_config.unload_in_progress = FALSE;
driver_config.system_information.virtualised_environment = FALSE;
RtlInitUnicodeString(&driver_config.device_name, L"\\Device\\DonnaAC");
RtlInitUnicodeString(&driver_config.device_symbolic_link, L"\\??\\DonnaAC");
@ -1186,23 +1321,11 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_ST
return status;
}
status = ParseSMBIOSTable(&driver_config.system_information.motherboard_serial,
sizeof(driver_config.system_information.motherboard_serial));
status = DrvLoadGatherSystemEnvironmentSettings();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("ParseSMBIOSTable failed with status %x", status);
DrvUnloadFreeConfigStrings();
return status;
}
status =
GetHardDiskDriveSerialNumber(&driver_config.system_information.drive_0_serial,
sizeof(driver_config.system_information.drive_0_serial));
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("GetHardDiskDriverSerialNumber failed with status %x", status);
DEBUG_ERROR("GatherSystemEnvironmentSettings failed with status %x", status);
DrvUnloadFreeConfigStrings();
return status;
}
@ -1216,10 +1339,6 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_ST
return status;
}
DEBUG_VERBOSE("Motherboard serial: %s",
driver_config.system_information.motherboard_serial);
DEBUG_VERBOSE("Drive 0 serial: %s", driver_config.system_information.drive_0_serial);
return status;
}

View file

@ -19,10 +19,33 @@
#define IOCTL_STORAGE_QUERY_PROPERTY 0x002D1400
typedef enum _ENVIRONMENT_TYPE
{
NativeWindows = 0,
Vmware,
VirtualBox
} ENVIRONMENT_TYPE;
typedef enum _PROCESSOR_TYPE
{
Unknown = 0,
GenuineIntel,
AuthenticAmd
} PROCESSOR_TYPE;
#define VENDOR_STRING_MAX_LENGTH 256
typedef struct _SYSTEM_INFORMATION
{
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
CHAR vendor[VENDOR_STRING_MAX_LENGTH];
BOOLEAN virtualised_environment;
ENVIRONMENT_TYPE environment;
PROCESSOR_TYPE processor;
RTL_OSVERSIONINFOW os_information;
} SYSTEM_INFORMATION, *PSYSTEM_INFORMATION;

View file

@ -22,7 +22,7 @@
* reference: https://secret.club/2020/01/12/battleye-hypervisor-detection.html
*/
_IRQL_always_function_max_(HIGH_LEVEL) STATIC INT APERFMsrTimingCheck()
_IRQL_always_function_max_(HIGH_LEVEL) INT APERFMsrTimingCheck()
{
KAFFINITY new_affinity = {0};
KAFFINITY old_affinity = {0};

View file

@ -14,6 +14,8 @@ typedef struct _HYPERVISOR_DETECTION_REPORT
NTSTATUS
PerformVirtualizationDetection(_Inout_ PIRP Irp);
_IRQL_always_function_max_(HIGH_LEVEL) INT APERFMsrTimingCheck();
extern INT
TestINVDEmulation();

View file

@ -10,18 +10,6 @@
#include <initguid.h>
#include <devpkey.h>
#define SMBIOS_TABLE 'RSMB'
/* for generic intel */
#define SMBIOS_SYSTEM_INFORMATION_TYPE_2_TABLE 2
#define MOTHERBOARD_SERIAL_CODE_TABLE_INDEX 4
#define NULL_TERMINATOR '\0'
/* for testing purposes in vmware */
#define VMWARE_SMBIOS_TABLE 1
#define VMWARE_SMBIOS_TABLE_INDEX 3
typedef struct _INTEGRITY_CHECK_HEADER
{
INT executable_section_count;
@ -773,7 +761,8 @@ end:
return status;
}
#define SMBIOS_TABLE 'RSMB'
#define NULL_TERMINATOR '\0'
/*
* From line 727 in the SMBIOS Specification:
*
@ -876,9 +865,19 @@ GetStringAtIndexFromSMBIOSTable(_In_ PSMBIOS_TABLE_HEADER Table,
return STATUS_NOT_FOUND;
}
/* for generic intel */
//#define SMBIOS_SYSTEM_INFORMATION_TYPE_2_TABLE 2
//#define MOTHERBOARD_SERIAL_CODE_TABLE_INDEX 4
/* for testing purposes in vmware */
//#define VMWARE_SMBIOS_TABLE 1
//#define VMWARE_SMBIOS_TABLE_INDEX 3
NTSTATUS
ParseSMBIOSTable(_In_ PVOID ConfigMotherboardSerialNumber,
_In_ SIZE_T ConfigMotherboardSerialNumberMaxSize)
ParseSMBIOSTable(_Out_ PVOID Buffer,
_In_ SIZE_T BufferSize,
_In_ SMBIOS_TABLE_INDEX TableIndex,
_In_ ULONG TableSubIndex)
{
PAGED_CODE();
@ -928,13 +927,11 @@ ParseSMBIOSTable(_In_ PVOID ConfigMotherboardSerialNumber,
* source: https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
* line 823
*/
while (smbios_table_header->Type != VMWARE_SMBIOS_TABLE)
while (smbios_table_header->Type != TableIndex)
GetNextSMBIOSStructureInTable(&smbios_table_header);
status = GetStringAtIndexFromSMBIOSTable(smbios_table_header,
VMWARE_SMBIOS_TABLE_INDEX,
ConfigMotherboardSerialNumber,
ConfigMotherboardSerialNumberMaxSize);
status =
GetStringAtIndexFromSMBIOSTable(smbios_table_header, TableSubIndex, Buffer, BufferSize);
if (!NT_SUCCESS(status))
{
@ -1709,8 +1706,7 @@ ValidateSystemModules()
if (!MmIsAddressValid(memory_hash) || !MmIsAddressValid(disk_hash))
goto free_iteration;
result =
RtlCompareMemory(memory_hash, disk_hash, memory_hash_size);
result = RtlCompareMemory(memory_hash, disk_hash, memory_hash_size);
if (result = memory_text_header->SizeOfRawData)
DEBUG_VERBOSE("Module executable sections are valid for the module: %s",

View file

@ -2,8 +2,22 @@
#define INTEGRITY_H
#include <ntifs.h>
#include "common.h"
typedef enum _SMBIOS_TABLE_INDEX
{
SmbiosInformation = 0,
SystemInformation,
VendorSpecificInformation,
ChassisInformation
} SMBIOS_TABLE_INDEX;
#define SMBIOS_VMWARE_SERIAL_NUMBER_SUB_INDEX 3
#define SMBIOS_NATIVE_SERIAL_NUMBER_SUB_INDEX 4
#define SMBIOS_VENDOR_STRING_SUB_INDEX 1
NTSTATUS
GetDriverImageSize(_Inout_ PIRP Irp);
@ -22,8 +36,10 @@ NTSTATUS
GetHardDiskDriveSerialNumber(_Inout_ PVOID ConfigDrive0Serial, _In_ SIZE_T ConfigDrive0MaxSize);
NTSTATUS
ParseSMBIOSTable(_In_ PVOID ConfigMotherboardSerialNumber,
_In_ SIZE_T ConfigMotherboardSerialNumberMaxSize);
ParseSMBIOSTable(_Out_ PVOID Buffer,
_In_ SIZE_T BufferSize,
_In_ ULONG TableIndex,
_In_ ULONG TableSubIndex);
NTSTATUS
DetectEptHooksInKeyFunctions();
@ -45,4 +61,7 @@ ValidateSystemModules();
NTSTATUS
ValidateNtoskrnl();
NTSTATUS
GetOsVersionInformation(_Out_ PRTL_OSVERSIONINFOW VersionInfo);
#endif

View file

@ -1366,7 +1366,7 @@ ValidateThreadsViaKernelApc()
if (context)
{
DEBUG_WARNING("Existing APC_STACKWALK operation already in progress.");
return STATUS_ALREADY_INITIALIZED;
return STATUS_SUCCESS;
}
context = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(APC_STACKWALK_CONTEXT), POOL_TAG_APC);

View file

@ -6,66 +6,69 @@
#define TEST_STEAM_64_ID 123456789;
global::Client::Client( std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName )
global::Client::Client(std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName)
{
this->thread_pool = ThreadPool;
this->pipe = std::make_shared<global::Pipe>( PipeName );
this->thread_pool = ThreadPool;
this->pipe = std::make_shared<global::Pipe>(PipeName);
}
/*
* Request an item from the server
*/
void global::Client::ServerReceive(PVOID Buffer, SIZE_T Size)
* Request an item from the server
*/
void
global::Client::ServerReceive(PVOID Buffer, SIZE_T Size)
{
this->pipe->ReadPipe( Buffer, Size );
this->pipe->ReadPipe(Buffer, Size);
}
/*
* Send an item to the server
*/
void global::Client::ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId )
* Send an item to the server
*/
void
global::Client::ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId)
{
mutex.lock();
mutex.lock();
SIZE_T total_header_size = sizeof( global::headers::CLIENT_SEND_PACKET_HEADER ) +
sizeof( global::headers::PIPE_PACKET_HEADER );
SIZE_T total_header_size = sizeof(global::headers::CLIENT_SEND_PACKET_HEADER) +
sizeof(global::headers::PIPE_PACKET_HEADER);
if ( Size + total_header_size > MAX_CLIENT_SEND_PACKET_SIZE )
{
LOG_ERROR( "Packet is too large to send" );
mutex.unlock();
return;
}
if (Size + total_header_size > MAX_CLIENT_SEND_PACKET_SIZE)
{
LOG_ERROR("Packet is too large to send");
mutex.unlock();
return;
}
PVOID send_buffer = malloc( total_header_size + Size );
PVOID send_buffer = malloc(total_header_size + Size);
if ( send_buffer == nullptr )
{
mutex.unlock();
return;
}
if (send_buffer == nullptr)
{
mutex.unlock();
return;
}
RtlZeroMemory( send_buffer, total_header_size + Size );
RtlZeroMemory(send_buffer, total_header_size + Size);
global::headers::PIPE_PACKET_HEADER header;
header.message_type = MESSAGE_TYPE_CLIENT_SEND;
header.steam64_id = TEST_STEAM_64_ID;
global::headers::PIPE_PACKET_HEADER header;
header.message_type = MESSAGE_TYPE_CLIENT_SEND;
header.steam64_id = TEST_STEAM_64_ID;
memcpy( send_buffer, &header, sizeof( global::headers::PIPE_PACKET_HEADER ) );
memcpy(send_buffer, &header, sizeof(global::headers::PIPE_PACKET_HEADER));
global::headers::CLIENT_SEND_PACKET_HEADER header_extension;
header_extension.request_id = RequestId;
header_extension.packet_size = Size + total_header_size;
global::headers::CLIENT_SEND_PACKET_HEADER header_extension = {0};
header_extension.request_id = RequestId;
header_extension.packet_size = Size + total_header_size;
memcpy( PVOID( ( UINT64 )send_buffer + sizeof( global::headers::PIPE_PACKET_HEADER ) ),
&header_extension, sizeof( global::headers::CLIENT_SEND_PACKET_HEADER ) );
memcpy(PVOID((UINT64)send_buffer + sizeof(global::headers::PIPE_PACKET_HEADER)),
&header_extension,
sizeof(global::headers::CLIENT_SEND_PACKET_HEADER));
memcpy(PVOID((UINT64)send_buffer + total_header_size), Buffer, Size);
memcpy(PVOID((UINT64)send_buffer + total_header_size), Buffer, Size);
LOG_INFO( "Writing to pipe" );
LOG_INFO("Writing to pipe");
this->pipe->WriteToPipe( send_buffer, header_extension.packet_size );
this->pipe->WriteToPipe(send_buffer, header_extension.packet_size);
mutex.unlock();
free( send_buffer );
mutex.unlock();
free(send_buffer);
}

View file

@ -9,35 +9,35 @@
#include "common.h"
#define REPORT_BUFFER_SIZE 8192
#define SEND_BUFFER_SIZE 8192
#define SEND_BUFFER_SIZE 8192
#define MAX_SIGNATURE_SIZE 256
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 20
#define REPORT_CODE_PROCESS_MODULE_VERIFICATION 10
#define REPORT_CODE_START_ADDRESS_VERIFICATION 20
#define REPORT_PAGE_PROTECTION_VERIFICATION 30
#define REPORT_PATTERN_SCAN_FAILURE 40
#define REPORT_NMI_CALLBACK_FAILURE 50
#define REPORT_MODULE_VALIDATION_FAILURE 60
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
#define REPORT_INVALID_PROCESS_ALLOCATION 80
#define REPORT_HIDDEN_SYSTEM_THREAD 90
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
#define REPORT_APC_STACKWALK 110
#define REPORT_CODE_START_ADDRESS_VERIFICATION 20
#define REPORT_PAGE_PROTECTION_VERIFICATION 30
#define REPORT_PATTERN_SCAN_FAILURE 40
#define REPORT_NMI_CALLBACK_FAILURE 50
#define REPORT_MODULE_VALIDATION_FAILURE 60
#define REPORT_ILLEGAL_HANDLE_OPERATION 70
#define REPORT_INVALID_PROCESS_ALLOCATION 80
#define REPORT_HIDDEN_SYSTEM_THREAD 90
#define REPORT_ILLEGAL_ATTACH_PROCESS 100
#define REPORT_APC_STACKWALK 110
#define TEST_STEAM_64_ID 123456789;
enum REPORT_CODES
{
USERMODE_MODULE = 10,
START_ADDRESS = 20,
PAGE_PROTECTION = 30,
PATTERN_SCAN = 40,
NMI_CALLBACK = 50,
SYSTEM_MODULE = 60,
HANDLE_OPERATION = 70
USERMODE_MODULE = 10,
START_ADDRESS = 20,
PAGE_PROTECTION = 30,
PATTERN_SCAN = 40,
NMI_CALLBACK = 50,
SYSTEM_MODULE = 60,
HANDLE_OPERATION = 70
};
#define CLIENT_REQUEST_MODULE_INTEGRITY_CHECK 10
@ -48,159 +48,160 @@ enum REPORT_CODES
enum SERVER_SEND_CODES
{
MODULE_INTEGRITY_CHECK = 10
MODULE_INTEGRITY_CHECK = 10
};
namespace global
namespace global {
class Client
{
class Client
{
std::shared_ptr<global::ThreadPool> thread_pool;
std::shared_ptr<global::Pipe> pipe;
std::mutex mutex;
std::shared_ptr<global::ThreadPool> thread_pool;
std::shared_ptr<global::Pipe> pipe;
std::mutex mutex;
byte report_buffer[ REPORT_BUFFER_SIZE ];
byte report_buffer[REPORT_BUFFER_SIZE];
public:
public:
Client(std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName);
Client( std::shared_ptr<global::ThreadPool> ThreadPool, LPTSTR PipeName );
void UpdateSystemInformation(global::headers::SYSTEM_INFORMATION* SystemInformation);
void UpdateSystemInformation( global::headers::SYSTEM_INFORMATION* SystemInformation );
/* lock buffer, attach header, copy report, send to service then clear buffer */
template <typename T>
void ReportViolation(T* Report)
{
mutex.lock();
/* lock buffer, attach header, copy report, send to service then clear buffer */
template <typename T>
void ReportViolation( T* Report )
{
mutex.lock();
global::headers::PIPE_PACKET_HEADER header = {0};
header.message_type = MESSAGE_TYPE_CLIENT_REPORT;
header.steam64_id = TEST_STEAM_64_ID;
memcpy(&this->report_buffer, &header, sizeof(global::headers::PIPE_PACKET_HEADER));
global::headers::PIPE_PACKET_HEADER header;
header.message_type = MESSAGE_TYPE_CLIENT_REPORT;
header.steam64_id = TEST_STEAM_64_ID;
memcpy( &this->report_buffer, &header, sizeof( global::headers::PIPE_PACKET_HEADER ) );
memcpy(PVOID((UINT64)this->report_buffer +
sizeof(global::headers::PIPE_PACKET_HEADER)),
Report,
sizeof(T));
this->pipe->WriteToPipe(this->report_buffer,
sizeof(T) + sizeof(global::headers::PIPE_PACKET_HEADER));
RtlZeroMemory(this->report_buffer, REPORT_BUFFER_SIZE);
memcpy( PVOID( ( UINT64 )this->report_buffer + sizeof( global::headers::PIPE_PACKET_HEADER ) ), Report, sizeof( T ) );
this->pipe->WriteToPipe( this->report_buffer, sizeof(T) + sizeof( global::headers::PIPE_PACKET_HEADER ) );
RtlZeroMemory( this->report_buffer, REPORT_BUFFER_SIZE );
mutex.unlock();
}
mutex.unlock();
}
void ServerReceive(PVOID Buffer, SIZE_T Size);
void ServerSend(PVOID Buffer, SIZE_T Size, INT RequestId);
};
void ServerReceive(PVOID Buffer, SIZE_T Size);
void ServerSend( PVOID Buffer, SIZE_T Size, INT RequestId );
};
namespace report_structures {
struct PROCESS_MODULES_INTEGRITY_CHECK_FAILURE
{
INT report_code;
UINT64 module_base_address;
UINT64 module_size;
CHAR module_name[256];
};
namespace report_structures
{
struct PROCESS_MODULES_INTEGRITY_CHECK_FAILURE
{
INT report_code;
UINT64 module_base_address;
UINT64 module_size;
CHAR module_name[ 256 ];
};
struct PROCESS_THREAD_START_FAILURE
{
INT report_code;
LONG thread_id;
UINT64 start_address;
};
struct PROCESS_THREAD_START_FAILURE
{
INT report_code;
LONG thread_id;
UINT64 start_address;
};
struct PAGE_PROTECTION_FAILURE
{
INT report_code;
UINT64 page_base_address;
LONG allocation_protection;
LONG allocation_state;
LONG allocation_type;
};
struct PAGE_PROTECTION_FAILURE
{
INT report_code;
UINT64 page_base_address;
LONG allocation_protection;
LONG allocation_state;
LONG allocation_type;
};
struct PATTERN_SCAN_FAILURE
{
INT report_code;
INT signature_id;
UINT64 address;
};
struct PATTERN_SCAN_FAILURE
{
INT report_code;
INT signature_id;
UINT64 address;
};
struct NMI_CALLBACK_FAILURE
{
INT report_code;
INT were_nmis_disabled;
UINT64 kthread_address;
UINT64 invalid_rip;
};
struct NMI_CALLBACK_FAILURE
{
INT report_code;
INT were_nmis_disabled;
UINT64 kthread_address;
UINT64 invalid_rip;
};
struct MODULE_VALIDATION_FAILURE_HEADER
{
INT module_count;
};
struct MODULE_VALIDATION_FAILURE_HEADER
{
INT module_count;
};
struct MODULE_VALIDATION_FAILURE
{
INT report_code;
INT report_type;
UINT64 driver_base_address;
UINT64 driver_size;
CHAR driver_name[128];
};
struct MODULE_VALIDATION_FAILURE
{
INT report_code;
INT report_type;
UINT64 driver_base_address;
UINT64 driver_size;
CHAR driver_name[ 128 ];
};
struct REPORT_QUEUE_HEADER
{
INT count;
};
struct REPORT_QUEUE_HEADER
{
INT count;
};
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];
};
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 ];
};
struct INVALID_PROCESS_ALLOCATION_REPORT
{
INT report_code;
CHAR process[4096];
};
struct INVALID_PROCESS_ALLOCATION_REPORT
{
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];
};
/*
* 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 ];
};
struct ATTACH_PROCESS_REPORT
{
INT report_code;
UINT32 thread_id;
UINT64 thread_address;
};
struct ATTACH_PROCESS_REPORT
{
INT report_code;
UINT32 thread_id;
UINT64 thread_address;
};
struct SYSTEM_INFORMATION_REQUEST_RESPONSE
{
INT RequestId;
INT CanUserProceed;
INT reason;
};
struct SYSTEM_INFORMATION_REQUEST_RESPONSE
{
INT RequestId;
INT CanUserProceed;
INT reason;
};
struct APC_STACKWALK_REPORT
{
INT report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[ 4096 ];
};
}
struct APC_STACKWALK_REPORT
{
INT report_code;
UINT64 kthread_address;
UINT64 invalid_rip;
CHAR driver[4096];
};
}
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -6,112 +6,129 @@
#include "../threadpool.h"
#include "../client.h"
#define IOCCTL_RUN_NMI_CALLBACKS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_DRIVER_OBJECTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_ENUMERATE_HANDLE_TABLES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20008, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20009, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_KPRCB_CURRENT_THREAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20012, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PERFORM_INTEGRITY_CHECK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DETECT_ATTACHED_THREADS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_PROCESS_LOADED_MODULE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_REQUEST_HARDWARE_INFORMATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_INITIATE_APC_OPERATION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_CHECK_FOR_EPT_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_LAUNCH_IPI_INTERRUPT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_SYSTEM_MODULES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCCTL_RUN_NMI_CALLBACKS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20001, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_DRIVER_OBJECTS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20002, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20004, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20005, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20006, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_ENUMERATE_HANDLE_TABLES \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20007, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20008, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_REQUEST_TOTAL_MODULE_SIZE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20009, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20010, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SCAN_FOR_UNLINKED_PROCESS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20011, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_KPRCB_CURRENT_THREAD \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20012, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_PERFORM_INTEGRITY_CHECK \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20013, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_DETECT_ATTACHED_THREADS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20014, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_PROCESS_LOADED_MODULE \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20015, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_REQUEST_HARDWARE_INFORMATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20016, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_INITIATE_APC_OPERATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20017, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_CHECK_FOR_EPT_HOOK \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20018, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_LAUNCH_IPI_INTERRUPT \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20019, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_VALIDATE_SYSTEM_MODULES \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x20020, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define MAX_REPORTS_PER_IRP 20
#define MAX_MODULE_PATH 256
namespace kernelmode
namespace kernelmode {
enum APC_OPERATION_IDS
{
enum APC_OPERATION_IDS
{
operation_stackwalk = 0x1
};
operation_stackwalk = 0x1
};
class Driver
{
HANDLE driver_handle;
LPCWSTR driver_name;
std::shared_ptr<global::Client> report_interface;
class Driver
{
HANDLE driver_handle;
LPCWSTR driver_name;
std::shared_ptr<global::Client> report_interface;
ULONG RequestTotalModuleSize();
VOID NotifyDriverOnProcessLaunch();
VOID CheckDriverHeartbeat();
VOID NotifyDriverOnProcessTermination();
//VOID GetKernelStructureOffsets();
ULONG RequestTotalModuleSize();
VOID NotifyDriverOnProcessLaunch();
VOID CheckDriverHeartbeat();
VOID NotifyDriverOnProcessTermination();
// VOID GetKernelStructureOffsets();
template <typename T>
VOID ReportTypeFromReportQueue( CONST PVOID Buffer, PSIZE_T Offset, PVOID Report )
{
Report = ( T* )(
( UINT64 )Buffer + sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + *Offset );
template <typename T>
VOID ReportTypeFromReportQueue(CONST PVOID Buffer, PSIZE_T Offset, PVOID Report)
{
Report = (T*)((UINT64)Buffer +
sizeof(global::report_structures::REPORT_QUEUE_HEADER) + *Offset);
this->report_interface->ReportViolation( ( T* )Report );
this->report_interface->ReportViolation((T*)Report);
*Offset += sizeof( T );
}
*Offset += sizeof(T);
}
public:
public:
Driver(LPCWSTR DriverName, std::shared_ptr<global::Client> ReportInterface);
~Driver();
Driver(LPCWSTR DriverName, std::shared_ptr<global::Client> ReportInterface );
~Driver();
VOID RunNmiCallbacks();
VOID VerifySystemModuleDriverObjects();
VOID RunCallbackReportQueue();
VOID DetectSystemVirtualization();
VOID QueryReportQueue();
VOID ValidateKPRCBThreads();
VOID CheckHandleTableEntries();
VOID RequestModuleExecutableRegions();
VOID ScanForUnlinkedProcess();
VOID PerformIntegrityCheck();
VOID CheckForAttachedThreads();
VOID VerifyProcessLoadedModuleExecutableRegions();
VOID SendClientHardwareInformation();
VOID CheckForHiddenThreads();
VOID CheckForEptHooks();
VOID LaunchIpiInterrupt();
VOID ValidateSystemModules();
BOOLEAN InitiateApcOperation(INT OperationId);
};
VOID RunNmiCallbacks();
VOID VerifySystemModuleDriverObjects();
VOID RunCallbackReportQueue();
VOID DetectSystemVirtualization();
VOID QueryReportQueue();
VOID ValidateKPRCBThreads();
VOID CheckHandleTableEntries();
VOID RequestModuleExecutableRegions();
VOID ScanForUnlinkedProcess();
VOID PerformIntegrityCheck();
VOID CheckForAttachedThreads();
VOID VerifyProcessLoadedModuleExecutableRegions();
VOID SendClientHardwareInformation();
VOID CheckForHiddenThreads();
VOID CheckForEptHooks();
VOID LaunchIpiInterrupt();
VOID ValidateSystemModules();
BOOLEAN InitiateApcOperation( INT OperationId );
};
struct DRIVER_INITIATION_INFORMATION
{
ULONG protected_process_id;
};
struct DRIVER_INITIATION_INFORMATION
{
ULONG protected_process_id;
};
struct HYPERVISOR_DETECTION_REPORT
{
INT aperf_msr_timing_check;
INT invd_emulation_check;
};
struct HYPERVISOR_DETECTION_REPORT
{
INT aperf_msr_timing_check;
INT invd_emulation_check;
};
struct PROCESS_MODULE_INFORMATION
{
PVOID module_base;
SIZE_T module_size;
WCHAR module_path[MAX_MODULE_PATH];
};
struct PROCESS_MODULE_INFORMATION
{
PVOID module_base;
SIZE_T module_size;
WCHAR module_path[ MAX_MODULE_PATH ];
};
struct PROCESS_MODULE_VALIDATION_RESULT
{
INT is_module_valid;
};
struct PROCESS_MODULE_VALIDATION_RESULT
{
INT is_module_valid;
};
struct APC_OPERATION_INFORMATION
{
int operation_id;
};
struct APC_OPERATION_INFORMATION
{
int operation_id;
};
}
#endif

View file

@ -1,87 +1,112 @@
#include "kmanager.h"
kernelmode::KManager::KManager( LPCWSTR DriverName, std::shared_ptr<global::ThreadPool> ThreadPool, std::shared_ptr<global::Client> ReportInterface)
kernelmode::KManager::KManager(LPCWSTR DriverName,
std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface)
{
this->driver_interface = std::make_unique<Driver>(DriverName, ReportInterface);
this->thread_pool = ThreadPool;
this->driver_interface = std::make_unique<Driver>(DriverName, ReportInterface);
this->thread_pool = ThreadPool;
}
void kernelmode::KManager::RunNmiCallbacks()
void
kernelmode::KManager::RunNmiCallbacks()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->RunNmiCallbacks(); } );
this->thread_pool->QueueJob([this]() { this->driver_interface->RunNmiCallbacks(); });
}
void kernelmode::KManager::VerifySystemModuleDriverObjects()
void
kernelmode::KManager::VerifySystemModuleDriverObjects()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->VerifySystemModuleDriverObjects(); } );
this->thread_pool->QueueJob(
[this]() { this->driver_interface->VerifySystemModuleDriverObjects(); });
}
void kernelmode::KManager::MonitorCallbackReports()
void
kernelmode::KManager::MonitorCallbackReports()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->QueryReportQueue(); } );
this->thread_pool->QueueJob([this]() { this->driver_interface->QueryReportQueue(); });
}
void kernelmode::KManager::DetectSystemVirtualization()
void
kernelmode::KManager::DetectSystemVirtualization()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->DetectSystemVirtualization(); } );
this->thread_pool->QueueJob(
[this]() { this->driver_interface->DetectSystemVirtualization(); });
}
void kernelmode::KManager::EnumerateHandleTables()
void
kernelmode::KManager::EnumerateHandleTables()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->CheckHandleTableEntries(); } );
this->thread_pool->QueueJob(
[this]() { this->driver_interface->CheckHandleTableEntries(); });
}
void kernelmode::KManager::RequestModuleExecutableRegionsForIntegrityCheck()
void
kernelmode::KManager::RequestModuleExecutableRegionsForIntegrityCheck()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->RequestModuleExecutableRegions(); } );
this->thread_pool->QueueJob(
[this]() { this->driver_interface->RequestModuleExecutableRegions(); });
}
VOID kernelmode::KManager::ScanPoolsForUnlinkedProcesses()
VOID
kernelmode::KManager::ScanPoolsForUnlinkedProcesses()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->ScanForUnlinkedProcess(); } );
this->thread_pool->QueueJob([this]() { this->driver_interface->ScanForUnlinkedProcess(); });
}
VOID kernelmode::KManager::PerformIntegrityCheck()
VOID
kernelmode::KManager::PerformIntegrityCheck()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->PerformIntegrityCheck(); } );
this->thread_pool->QueueJob([this]() { this->driver_interface->PerformIntegrityCheck(); });
}
VOID kernelmode::KManager::CheckForAttachedThreads()
VOID
kernelmode::KManager::CheckForAttachedThreads()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->CheckForAttachedThreads(); } );
this->thread_pool->QueueJob(
[this]() { this->driver_interface->CheckForAttachedThreads(); });
}
VOID kernelmode::KManager::ValidateProcessModules()
VOID
kernelmode::KManager::ValidateProcessModules()
{
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->VerifyProcessLoadedModuleExecutableRegions(); } );
this->thread_pool->QueueJob(
[this]() { this->driver_interface->VerifyProcessLoadedModuleExecutableRegions(); });
}
VOID kernelmode::KManager::SendClientHardwareInformation()
VOID
kernelmode::KManager::SendClientHardwareInformation()
{
this->driver_interface->SendClientHardwareInformation();
this->driver_interface->SendClientHardwareInformation();
}
VOID kernelmode::KManager::InitiateApcStackwalkOperation()
VOID
kernelmode::KManager::InitiateApcStackwalkOperation()
{
this->driver_interface->InitiateApcOperation( kernelmode::APC_OPERATION_IDS::operation_stackwalk );
this->driver_interface->InitiateApcOperation(
kernelmode::APC_OPERATION_IDS::operation_stackwalk);
}
VOID kernelmode::KManager::CheckForHiddenThreads()
VOID
kernelmode::KManager::CheckForHiddenThreads()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->CheckForHiddenThreads(); });
this->thread_pool->QueueJob([this]() { this->driver_interface->CheckForHiddenThreads(); });
}
VOID kernelmode::KManager::CheckForEptHooks()
VOID
kernelmode::KManager::CheckForEptHooks()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->CheckForEptHooks(); });
this->thread_pool->QueueJob([this]() { this->driver_interface->CheckForEptHooks(); });
}
VOID kernelmode::KManager::LaunchIpiInterrupt()
VOID
kernelmode::KManager::LaunchIpiInterrupt()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->LaunchIpiInterrupt(); });
this->thread_pool->QueueJob([this]() { this->driver_interface->LaunchIpiInterrupt(); });
}
VOID kernelmode::KManager::ValidateSystemModules()
VOID
kernelmode::KManager::ValidateSystemModules()
{
this->thread_pool->QueueJob([this]() { this->driver_interface->ValidateSystemModules(); });
this->thread_pool->QueueJob([this]() { this->driver_interface->ValidateSystemModules(); });
}

View file

@ -8,32 +8,34 @@
#include "driver.h"
namespace kernelmode
namespace kernelmode {
class KManager
{
class KManager
{
std::unique_ptr<Driver> driver_interface;
std::shared_ptr<global::ThreadPool> thread_pool;
public:
KManager( LPCWSTR DriverName, std::shared_ptr<global::ThreadPool> ThreadPool, std::shared_ptr<global::Client> ReportInterface);
std::unique_ptr<Driver> driver_interface;
std::shared_ptr<global::ThreadPool> thread_pool;
VOID RunNmiCallbacks();
VOID VerifySystemModuleDriverObjects();
VOID MonitorCallbackReports();
VOID DetectSystemVirtualization();
VOID EnumerateHandleTables();
VOID RequestModuleExecutableRegionsForIntegrityCheck();
VOID ScanPoolsForUnlinkedProcesses();
VOID PerformIntegrityCheck();
VOID CheckForAttachedThreads();
VOID ValidateProcessModules();
VOID SendClientHardwareInformation();
VOID InitiateApcStackwalkOperation();
VOID CheckForHiddenThreads();
VOID CheckForEptHooks();
VOID LaunchIpiInterrupt();
VOID ValidateSystemModules();
};
public:
KManager(LPCWSTR DriverName,
std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface);
VOID RunNmiCallbacks();
VOID VerifySystemModuleDriverObjects();
VOID MonitorCallbackReports();
VOID DetectSystemVirtualization();
VOID EnumerateHandleTables();
VOID RequestModuleExecutableRegionsForIntegrityCheck();
VOID ScanPoolsForUnlinkedProcesses();
VOID PerformIntegrityCheck();
VOID CheckForAttachedThreads();
VOID ValidateProcessModules();
VOID SendClientHardwareInformation();
VOID InitiateApcStackwalkOperation();
VOID CheckForHiddenThreads();
VOID CheckForEptHooks();
VOID LaunchIpiInterrupt();
VOID ValidateSystemModules();
};
}
#endif

View file

@ -11,31 +11,32 @@
#include "../user/um/umanager.h"
#include "../user/km/kmanager.h"
//BOOLEAN IsTestSigningModeEnabled()
// BOOLEAN IsTestSigningModeEnabled()
//{
// ULONG return_length = 0;
// ULONG return_length = 0;
//
// SYSTEM_CODEINTEGRITY_INFORMATION info = { 0 };
// info.Length = sizeof(SYSTEM_CODEINTEGRITY_INFORMATION);
// info.CodeIntegrityOptions = 0;
// SYSTEM_CODEINTEGRITY_INFORMATION info = { 0 };
// info.Length = sizeof(SYSTEM_CODEINTEGRITY_INFORMATION);
// info.CodeIntegrityOptions = 0;
//
// NTSTATUS status = NtQuerySystemInformation(
// SystemCodeIntegrityInformation,
// &info,
// sizeof(info),
// &return_length
// );
// NTSTATUS status = NtQuerySystemInformation(
// SystemCodeIntegrityInformation,
// &info,
// sizeof(info),
// &return_length
// );
//
// if (!NT_SUCCESS(status))
// {
// LOG_ERROR("NtQuerySystemInformation failed with status: %lx", status);
// return FALSE;
// }
// if (!NT_SUCCESS(status))
// {
// LOG_ERROR("NtQuerySystemInformation failed with status: %lx", status);
// return FALSE;
// }
//
// return info.CodeIntegrityOptions & CODEINTEGRITY_OPTION_TESTSIGN;
//}
// return info.CodeIntegrityOptions & CODEINTEGRITY_OPTION_TESTSIGN;
// }
DWORD WINAPI Init(HINSTANCE hinstDLL)
DWORD WINAPI
Init(HINSTANCE hinstDLL)
{
AllocConsole();
FILE* file;
@ -44,31 +45,32 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
std::this_thread::sleep_for(std::chrono::seconds(1));
LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe";
LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe";
LPCWSTR driver_name = L"\\\\.\\DonnaAC";
std::shared_ptr<global::ThreadPool> thread_pool = std::make_shared<global::ThreadPool>(4);
std::shared_ptr<global::Client> client_interface = std::make_shared<global::Client>(thread_pool, pipe_name);
std::shared_ptr<global::Client> client_interface =
std::make_shared<global::Client>(thread_pool, pipe_name);
usermode::UManager umanager(thread_pool, client_interface);
usermode::UManager umanager(thread_pool, client_interface);
kernelmode::KManager kmanager(driver_name, thread_pool, client_interface);
global::headers::SYSTEM_INFORMATION system_information;
global::headers::SYSTEM_INFORMATION system_information = {0};
kmanager.SendClientHardwareInformation();
global::report_structures::SYSTEM_INFORMATION_REQUEST_RESPONSE response;
//client_interface->ServerReceive( &response, sizeof( response ) );
// client_interface->ServerReceive( &response, sizeof( response ) );
//std::cout << "RequestID: " << response.RequestId << " CanUserProceed: " <<
// response.CanUserProceed << " Reason: " << response.reason << std::endl;
// std::cout << "RequestID: " << response.RequestId << " CanUserProceed: " <<
// response.CanUserProceed << " Reason: " << response.reason << std::endl;
/*
* Note that this is really just for testing the methods for extended periods of time.
* The "real business logic" would execute the methods with varying degrees of uncertaintity
* but still allow for bias, i.e we don't want NMI callbacks to be running every 10 seconds
* since they are "dangerous" for the CPU given the IRQL they run at.
*/
* Note that this is really just for testing the methods for extended periods of time.
* The "real business logic" would execute the methods with varying degrees of uncertaintity
* but still allow for bias, i.e we don't want NMI callbacks to be running every 10 seconds
* since they are "dangerous" for the CPU given the IRQL they run at.
*/
srand(time(NULL));
@ -80,18 +82,66 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
switch (seed)
{
case 0: { kmanager.EnumerateHandleTables(); break; }
case 1: { kmanager.PerformIntegrityCheck(); break; }
case 2: { kmanager.ScanPoolsForUnlinkedProcesses(); break; }
case 3: { kmanager.VerifySystemModuleDriverObjects(); break; }
case 4: { kmanager.ValidateProcessModules(); break; }
case 5: { kmanager.RunNmiCallbacks(); break; }
case 6: { kmanager.CheckForAttachedThreads(); break; }
case 7: { kmanager.InitiateApcStackwalkOperation(); break; }
case 8: { kmanager.CheckForHiddenThreads(); break; }
case 9: { kmanager.CheckForEptHooks(); break; }
case 10: { kmanager.LaunchIpiInterrupt(); break; }
case 11: { kmanager.ValidateSystemModules(); break; }
case 0:
{
kmanager.EnumerateHandleTables();
break;
}
case 1:
{
kmanager.PerformIntegrityCheck();
break;
}
case 2:
{
kmanager.ScanPoolsForUnlinkedProcesses();
break;
}
case 3:
{
kmanager.VerifySystemModuleDriverObjects();
break;
}
case 4:
{
kmanager.ValidateProcessModules();
break;
}
case 5:
{
kmanager.RunNmiCallbacks();
break;
}
case 6:
{
kmanager.CheckForAttachedThreads();
break;
}
case 7:
{
kmanager.InitiateApcStackwalkOperation();
break;
}
case 8:
{
kmanager.CheckForHiddenThreads();
break;
}
case 9:
{
kmanager.CheckForEptHooks();
break;
}
case 10:
{
kmanager.LaunchIpiInterrupt();
break;
}
case 11:
{
kmanager.ValidateSystemModules();
break;
}
}
kmanager.MonitorCallbackReports();
@ -106,10 +156,10 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
return 0;
}
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved) // reserved
BOOL WINAPI
DllMain(HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved) // reserved
{
// Perform actions based on the reason for calling.
switch (fdwReason)
@ -118,19 +168,17 @@ BOOL WINAPI DllMain(
DisableThreadLibraryCalls(hinstDLL);
const auto thread = CreateThread(
nullptr,
0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(Init),
hinstDLL,
0,
nullptr
);
const auto thread = CreateThread(nullptr,
0,
reinterpret_cast<LPTHREAD_START_ROUTINE>(Init),
hinstDLL,
0,
nullptr);
if (thread)
CloseHandle(thread);
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
return TRUE; // Successful DLL_PROCESS_ATTACH.
}

View file

@ -3,61 +3,49 @@
#include "common.h"
#include <intrin.h>
global::Pipe::Pipe( LPTSTR PipeName )
global::Pipe::Pipe(LPTSTR PipeName)
{
this->pipe_name = PipeName;
this->pipe_handle = CreateFile(
this->pipe_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
this->pipe_name = PipeName;
this->pipe_handle = CreateFile(this->pipe_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if ( this->pipe_handle == INVALID_HANDLE_VALUE )
{
LOG_ERROR( "CreateFile failed with status 0x%x", GetLastError() );
return;
}
if (this->pipe_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("CreateFile failed with status 0x%x", GetLastError());
return;
}
}
void global::Pipe::WriteToPipe( PVOID Buffer, SIZE_T Size )
void
global::Pipe::WriteToPipe(PVOID Buffer, SIZE_T Size)
{
DWORD bytes_written;
DWORD bytes_written = 0;
WriteFile(
this->pipe_handle,
Buffer,
Size,
&bytes_written,
NULL
);
WriteFile(this->pipe_handle, Buffer, Size, &bytes_written, NULL);
if ( bytes_written == 0 )
{
LOG_ERROR( "WriteFile failed with status code 0x%x", GetLastError() );
return;
}
if (bytes_written == 0)
{
LOG_ERROR("WriteFile failed with status code 0x%x", GetLastError());
return;
}
}
void global::Pipe::ReadPipe( PVOID Buffer, SIZE_T Size )
void
global::Pipe::ReadPipe(PVOID Buffer, SIZE_T Size)
{
BOOL status = FALSE;
DWORD bytes_read;
BOOL status = FALSE;
DWORD bytes_read = 0;
status = ReadFile(
this->pipe_handle,
Buffer,
Size,
&bytes_read,
NULL
);
status = ReadFile(this->pipe_handle, Buffer, Size, &bytes_read, NULL);
if ( status == NULL )
{
LOG_ERROR( "ReadFile failed with status code 0x%x", GetLastError() );
return;
}
if (status == NULL)
{
LOG_ERROR("ReadFile failed with status code 0x%x", GetLastError());
return;
}
}

View file

@ -3,53 +3,51 @@
#include <Windows.h>
#define MESSAGE_TYPE_CLIENT_REPORT 1
#define MESSAGE_TYPE_CLIENT_SEND 2
#define MESSAGE_TYPE_CLIENT_REPORT 1
#define MESSAGE_TYPE_CLIENT_SEND 2
#define MESSAGE_TYPE_CLIENT_REQUEST 3
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
#define MOTHERBOARD_SERIAL_CODE_LENGTH 64
#define DEVICE_DRIVE_0_SERIAL_CODE_LENGTH 64
namespace global
namespace global {
class Pipe
{
class Pipe
{
HANDLE pipe_handle;
LPTSTR pipe_name;
HANDLE pipe_handle;
LPTSTR pipe_name;
public:
Pipe(LPTSTR PipeName);
public:
Pipe(LPTSTR PipeName);
void WriteToPipe( PVOID Buffer, SIZE_T Size );
void ReadPipe( PVOID Buffer, SIZE_T Size );
};
void WriteToPipe(PVOID Buffer, SIZE_T Size);
void ReadPipe(PVOID Buffer, SIZE_T Size);
};
namespace headers
{
struct SYSTEM_INFORMATION
{
CHAR motherboard_serial[ MOTHERBOARD_SERIAL_CODE_LENGTH ];
CHAR drive_0_serial[ DEVICE_DRIVE_0_SERIAL_CODE_LENGTH ];
};
namespace headers {
struct SYSTEM_INFORMATION
{
CHAR motherboard_serial[MOTHERBOARD_SERIAL_CODE_LENGTH];
CHAR drive_0_serial[DEVICE_DRIVE_0_SERIAL_CODE_LENGTH];
};
struct PIPE_PACKET_HEADER
{
INT message_type;
UINT64 steam64_id;
};
struct PIPE_PACKET_HEADER
{
INT message_type;
UINT64 steam64_id;
};
struct PIPE_PACKET_REQUEST_EXTENSION_HEADER
{
INT request_id;
};
struct PIPE_PACKET_REQUEST_EXTENSION_HEADER
{
INT request_id;
};
struct CLIENT_SEND_PACKET_HEADER
{
INT request_id;
LONG packet_size;
};
struct CLIENT_SEND_PACKET_HEADER
{
INT request_id;
LONG packet_size;
};
}
}
}
#endif

View file

@ -1,92 +1,103 @@
#include "threadpool.h"
/*
* This is the idle loop each thread will be running until a job is ready
* for execution
*/
void global::ThreadPool::ThreadLoop()
* This is the idle loop each thread will be running until a job is ready
* for execution
*/
void
global::ThreadPool::ThreadLoop()
{
while ( true )
{
std::function<void()> job;
{
std::unique_lock<std::mutex> lock( this->queue_mutex );
while (true)
{
std::function<void()> job;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
/*
* This is equivalent to :
*
* while (!this->jobs.empty() || should_terminate)
* mutex_condition.wait(lock);
*
* we are essentially waiting for a job to be queued up or the terminate flag to be set.
* Another piece of useful information is that the predicate is checked under the lock
* as the precondition for .wait() is that the calling thread owns the lock.
*
* Now, when .wait() is run, the lock is unlocked the the executing thread is blocked and
* is added to a list of threads current waiting on the predicate. In our case whether
* there are new jobs available for the terminate flag is set. Once the condition variables
* are true i.e there are new jobs or we are terminating, the lock is reacquired by the thread
* and the thread is unblocked.
*/
mutex_condition.wait( lock, [ this ] { return !this->jobs.empty() || this->should_terminate; } );
/*
* This is equivalent to :
*
* while (!this->jobs.empty() || should_terminate)
* mutex_condition.wait(lock);
*
* we are essentially waiting for a job to be queued up or the terminate
*flag to be set. Another piece of useful information is that the predicate
*is checked under the lock as the precondition for .wait() is that the
*calling thread owns the lock.
*
* Now, when .wait() is run, the lock is unlocked the the executing thread
*is blocked and is added to a list of threads current waiting on the
*predicate. In our case whether there are new jobs available for the
*terminate flag is set. Once the condition variables are true i.e there are
*new jobs or we are terminating, the lock is reacquired by the thread and
*the thread is unblocked.
*/
mutex_condition.wait(
lock, [this] { return !this->jobs.empty() || this->should_terminate; });
if ( this->should_terminate )
return;
if (this->should_terminate)
return;
/* get the first job in the queue*/
job = jobs.front();
jobs.pop();
}
/* run the job */
job();
}
/* get the first job in the queue*/
job = jobs.front();
jobs.pop();
}
/* run the job */
job();
}
}
global::ThreadPool::ThreadPool(int ThreadCount)
{
this->thread_count = ThreadCount;
this->should_terminate = false;
this->thread_count = ThreadCount;
this->should_terminate = false;
/* Initiate our threads and store them in our threads vector */
for ( int i = 0; i < this->thread_count; i++ )
{
this->threads.emplace_back( std::thread( &ThreadPool::ThreadLoop, this ) );
}
/* Initiate our threads and store them in our threads vector */
for (int i = 0; i < this->thread_count; i++)
{
this->threads.emplace_back(std::thread(&ThreadPool::ThreadLoop, this));
}
}
void global::ThreadPool::QueueJob( const std::function<void()>& job )
void
global::ThreadPool::QueueJob(const std::function<void()>& job)
{
/* push a job into our job queue safely by holding our queue lock */
std::unique_lock<std::mutex> lock( this->queue_mutex );
/* push a job into our job queue safely by holding our queue lock */
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->jobs.push( job );
lock.unlock();
this->jobs.push(job);
lock.unlock();
mutex_condition.notify_one();
mutex_condition.notify_one();
}
void global::ThreadPool::Stop()
void
global::ThreadPool::Stop()
{
/* safely set our termination flag to true */
std::unique_lock<std::mutex> lock( this->queue_mutex );
should_terminate = true;
lock.unlock();
/* safely set our termination flag to true */
std::unique_lock<std::mutex> lock(this->queue_mutex);
should_terminate = true;
lock.unlock();
/* unlock all threads waiting on our condition */
mutex_condition.notify_all();
/* unlock all threads waiting on our condition */
mutex_condition.notify_all();
/* join the threads and clear our threads vector */
for ( std::thread& thread : threads ) { thread.join(); }
threads.clear();
/* join the threads and clear our threads vector */
for (std::thread& thread : threads)
{
thread.join();
}
threads.clear();
}
bool global::ThreadPool::Busy()
bool
global::ThreadPool::Busy()
{
/* allows us to wait for when the job queue is empty allowing us to safely call the destructor */
std::unique_lock<std::mutex> lock( this->queue_mutex );
/* allows us to wait for when the job queue is empty allowing us to safely call the
* destructor */
std::unique_lock<std::mutex> lock(this->queue_mutex);
bool pool_busy = !jobs.empty();
this->queue_mutex.unlock();
bool pool_busy = !jobs.empty();
this->queue_mutex.unlock();
return pool_busy;
return pool_busy;
}

View file

@ -6,31 +6,29 @@
#include <queue>
#include <functional>
namespace global
namespace global {
/*
* This ThreadPool class is a simple threadpool implementation that will allow us
* to delegate jobs to a set number of threads without the constant need to close
* and open new threads.
*/
class ThreadPool
{
/*
* This ThreadPool class is a simple threadpool implementation that will allow us
* to delegate jobs to a set number of threads without the constant need to close
* and open new threads.
*/
class ThreadPool
{
int thread_count;
bool should_terminate;
std::mutex queue_mutex;
std::condition_variable mutex_condition;
std::vector<std::thread> threads;
std::queue<std::function<void()>> jobs;
int thread_count;
bool should_terminate;
std::mutex queue_mutex;
std::condition_variable mutex_condition;
std::vector<std::thread> threads;
std::queue<std::function<void()>> jobs;
void ThreadLoop();
void ThreadLoop();
public:
ThreadPool( int ThreadCount );
void QueueJob(const std::function<void()>& job);
void Stop();
bool Busy();
};
public:
ThreadPool(int ThreadCount);
void QueueJob(const std::function<void()>& job);
void Stop();
bool Busy();
};
}
#endif

View file

@ -4,29 +4,29 @@
usermode::Imports::Imports()
{
NtQueryInformationThread = nullptr;
RtlDosPathNameToNtPathName_U = nullptr;
NtQueryInformationThread = nullptr;
RtlDosPathNameToNtPathName_U = nullptr;
this->ImportMap[ "NtQueryInformationThread" ] = NtQueryInformationThread;
this->ImportMap[ "RtlDosPathNameToNtPathName_U" ] = RtlDosPathNameToNtPathName_U;
this->ImportMap["NtQueryInformationThread"] = NtQueryInformationThread;
this->ImportMap["RtlDosPathNameToNtPathName_U"] = RtlDosPathNameToNtPathName_U;
std::map<std::string, void*>::iterator it;
std::map<std::string, void*>::iterator it;
for ( it = this->ImportMap.begin(); it != this->ImportMap.end(); it++ )
{
HMODULE module_handle = GetModuleHandle( L"ntdll.dll" );
for (it = this->ImportMap.begin(); it != this->ImportMap.end(); it++)
{
HMODULE module_handle = GetModuleHandle(L"ntdll.dll");
if ( !module_handle )
{
LOG_ERROR( "GetModuleHandle failed with status code 0x%x", GetLastError() );
return;
}
if (!module_handle)
{
LOG_ERROR("GetModuleHandle failed with status code 0x%x", GetLastError());
return;
}
it->second = GetProcAddress( module_handle, it->first.c_str());
it->second = GetProcAddress(module_handle, it->first.c_str());
if ( !it->second )
{
LOG_ERROR( "GetProcAddress failed with status code 0x%x", GetLastError() );
}
}
if (!it->second)
{
LOG_ERROR("GetProcAddress failed with status code 0x%x", GetLastError());
}
}
}

View file

@ -6,22 +6,21 @@
#include <map>
#include <string>
typedef NTSTATUS( WINAPI* pNtQueryInformationThread )( HANDLE, LONG, PVOID, ULONG, PULONG );
typedef BOOLEAN( NTAPI pRtlDosPathNameToNtPathName_U( PCWSTR, PVOID, PCWSTR*, PVOID ));
typedef NTSTATUS(WINAPI* pNtQueryInformationThread)(HANDLE, LONG, PVOID, ULONG, PULONG);
typedef BOOLEAN(NTAPI pRtlDosPathNameToNtPathName_U(PCWSTR, PVOID, PCWSTR*, PVOID));
namespace usermode
namespace usermode {
class Imports
{
class Imports
{
public:
std::map<std::string, void*> ImportMap;
public:
std::map<std::string, void*> ImportMap;
void* NtQueryInformationThread;
void* NtQueryVirtualMemory;
void* RtlDosPathNameToNtPathName_U;
void* NtQueryInformationThread;
void* NtQueryVirtualMemory;
void* RtlDosPathNameToNtPathName_U;
Imports();
};
Imports();
};
}
#endif

View file

@ -11,307 +11,311 @@
const static char MASK_BYTE = '\x00';
usermode::Process::Process( std::shared_ptr<global::Client> ClientInterface )
usermode::Process::Process(std::shared_ptr<global::Client> ClientInterface)
{
this->process_handle = GetCurrentProcess();
this->process_id = GetCurrentProcessId();
this->function_imports = std::make_unique<Imports>();
this->client_interface = ClientInterface;
this->process_handle = GetCurrentProcess();
this->process_id = GetCurrentProcessId();
this->function_imports = std::make_unique<Imports>();
this->client_interface = ClientInterface;
}
void usermode::Process::ValidateProcessThreads()
void
usermode::Process::ValidateProcessThreads()
{
HANDLE thread_snapshot_handle = INVALID_HANDLE_VALUE;
THREADENTRY32 thread_entry;
NTSTATUS status;
HANDLE thread_handle;
UINT64 start_address;
bool result;
HANDLE thread_snapshot_handle = INVALID_HANDLE_VALUE;
THREADENTRY32 thread_entry = {0};
NTSTATUS status = 0;
HANDLE thread_handle = INVALID_HANDLE_VALUE;
UINT64 start_address = 0;
bool result = false;
pNtQueryInformationThread NtQueryInfo =
( pNtQueryInformationThread )this->function_imports->ImportMap["NtQueryInformationThread"];
pNtQueryInformationThread NtQueryInfo = (pNtQueryInformationThread)this->function_imports
->ImportMap["NtQueryInformationThread"];
/* th32ProcessId ignored for TH32CS_SNAPTHREAD value */
thread_snapshot_handle = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
/* th32ProcessId ignored for TH32CS_SNAPTHREAD value */
thread_snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if ( thread_snapshot_handle == INVALID_HANDLE_VALUE )
{
LOG_ERROR( "thread snapshot handle invalid with error 0x%x", GetLastError() );
return;
}
if (thread_snapshot_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("thread snapshot handle invalid with error 0x%x", GetLastError());
return;
}
thread_entry.dwSize = sizeof( THREADENTRY32 );
thread_entry.dwSize = sizeof(THREADENTRY32);
if ( !Thread32First( thread_snapshot_handle, &thread_entry ))
{
LOG_ERROR( "Thread32First failed with status 0x%x", GetLastError() );
CloseHandle( thread_snapshot_handle );
return;
}
if (!Thread32First(thread_snapshot_handle, &thread_entry))
{
LOG_ERROR("Thread32First failed with status 0x%x", GetLastError());
CloseHandle(thread_snapshot_handle);
return;
}
do
{
if ( thread_entry.th32OwnerProcessID != process_id )
continue;
do
{
if (thread_entry.th32OwnerProcessID != process_id)
continue;
thread_handle = OpenThread( THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID );
thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_entry.th32ThreadID);
if ( thread_handle == INVALID_HANDLE_VALUE )
continue;
if (thread_handle == INVALID_HANDLE_VALUE)
continue;
status = NtQueryInfo(
thread_handle,
( THREADINFOCLASS )ThreadQuerySetWin32StartAddress,
&start_address,
sizeof( UINT64 ),
NULL
);
status = NtQueryInfo(thread_handle,
(THREADINFOCLASS)ThreadQuerySetWin32StartAddress,
&start_address,
sizeof(UINT64),
NULL);
if ( !NT_SUCCESS( status ) )
{
LOG_ERROR( "NtQueryInfo failed with status code 0x%lx", status );
continue;
}
if (!NT_SUCCESS(status))
{
LOG_ERROR("NtQueryInfo failed with status code 0x%lx", status);
continue;
}
if ( CheckIfAddressLiesWithinValidProcessModule( start_address, &result ) )
{
if ( result == false )
{
global::report_structures::PROCESS_THREAD_START_FAILURE report;
report.report_code = REPORT_CODE_START_ADDRESS_VERIFICATION;
report.start_address = start_address;
report.thread_id = thread_entry.th32ThreadID;
this->client_interface->ReportViolation( &report );
}
}
if (CheckIfAddressLiesWithinValidProcessModule(start_address, &result))
{
if (result == false)
{
global::report_structures::PROCESS_THREAD_START_FAILURE report;
report.report_code = REPORT_CODE_START_ADDRESS_VERIFICATION;
report.start_address = start_address;
report.thread_id = thread_entry.th32ThreadID;
this->client_interface->ReportViolation(&report);
}
}
} while ( Thread32Next( thread_snapshot_handle, &thread_entry ) );
} while (Thread32Next(thread_snapshot_handle, &thread_entry));
}
/*
* Iterates through a processes modules and confirms whether the address lies within the memory region
* of the module. A simple way to check if a thread is a valid thread, however there are ways around
* this check so it is not a perfect solution.
*/
bool usermode::Process::CheckIfAddressLiesWithinValidProcessModule( UINT64 Address, bool* Result )
* Iterates through a processes modules and confirms whether the address lies within the memory
* region of the module. A simple way to check if a thread is a valid thread, however there are ways
* around this check so it is not a perfect solution.
*/
bool
usermode::Process::CheckIfAddressLiesWithinValidProcessModule(UINT64 Address, bool* Result)
{
HANDLE process_modules_handle;
MODULEENTRY32 module_entry;
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
MODULEENTRY32 module_entry = {0};
process_modules_handle = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id );
process_modules_handle =
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id);
LOG_INFO( "Address: %llx", Address );
LOG_INFO("Address: %llx", Address);
if ( process_modules_handle == INVALID_HANDLE_VALUE )
{
LOG_ERROR( "CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x", GetLastError() );
return false;
}
if (process_modules_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
GetLastError());
return false;
}
module_entry.dwSize = sizeof( MODULEENTRY32 );
module_entry.dwSize = sizeof(MODULEENTRY32);
if ( !Module32First( process_modules_handle, &module_entry ) )
{
LOG_ERROR( "Module32First failed with status 0x%x", GetLastError() );
CloseHandle( process_modules_handle );
return false;
}
if (!Module32First(process_modules_handle, &module_entry))
{
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
CloseHandle(process_modules_handle);
return false;
}
do
{
UINT64 base = (UINT64)module_entry.modBaseAddr;
UINT64 end = base + module_entry.modBaseSize;
do
{
UINT64 base = (UINT64)module_entry.modBaseAddr;
UINT64 end = base + module_entry.modBaseSize;
if ( Address >= base && Address <= end )
{
LOG_INFO( "found valid module LOL" );
CloseHandle( process_modules_handle );
*Result = true;
return true;
}
if (Address >= base && Address <= end)
{
LOG_INFO("found valid module LOL");
CloseHandle(process_modules_handle);
*Result = true;
return true;
}
} while ( Module32Next( process_modules_handle, &module_entry ) );
} while (Module32Next(process_modules_handle, &module_entry));
CloseHandle( process_modules_handle );
*Result = false;
return true;
CloseHandle(process_modules_handle);
*Result = false;
return true;
}
HANDLE usermode::Process::GetHandleToProcessGivenName( std::string ProcessName )
HANDLE
usermode::Process::GetHandleToProcessGivenName(std::string ProcessName)
{
std::wstring wide_process_name;
std::wstring target_process_name;
HANDLE process_snapshot_handle;
HANDLE process_handle;
PROCESSENTRY32 process_entry;
std::wstring wide_process_name = {0};
std::wstring target_process_name = {0};
HANDLE process_snapshot_handle = INVALID_HANDLE_VALUE;
HANDLE process_handle = INVALID_HANDLE_VALUE;
PROCESSENTRY32 process_entry = {0};
wide_process_name = std::wstring( ProcessName.begin(), ProcessName.end() );
process_snapshot_handle = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
wide_process_name = std::wstring(ProcessName.begin(), ProcessName.end());
process_snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if ( process_snapshot_handle == INVALID_HANDLE_VALUE )
{
LOG_ERROR( "Failed to create snapshot of current running processes error: 0x%x", GetLastError() );
return INVALID_HANDLE_VALUE;
}
if (process_snapshot_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("Failed to create snapshot of current running processes error: 0x%x",
GetLastError());
return INVALID_HANDLE_VALUE;
}
process_entry.dwSize = sizeof( PROCESSENTRY32 );
process_entry.dwSize = sizeof(PROCESSENTRY32);
if ( !Process32First( process_snapshot_handle, &process_entry ) )
{
LOG_ERROR( "Failed to get the first process using Process32First error: 0x%x", GetLastError() );
CloseHandle( process_snapshot_handle );
return INVALID_HANDLE_VALUE;
}
if (!Process32First(process_snapshot_handle, &process_entry))
{
LOG_ERROR("Failed to get the first process using Process32First error: 0x%x",
GetLastError());
CloseHandle(process_snapshot_handle);
return INVALID_HANDLE_VALUE;
}
do
{
process_handle = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
process_entry.th32ProcessID
);
do
{
process_handle =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_entry.th32ProcessID);
/*
* this will generally fail due to a process being an elevated process and denying
* us access so we dont really care if OpenProcess fails in most cases
*/
if ( process_handle == NULL )
continue;
/*
* this will generally fail due to a process being an elevated process and denying
* us access so we dont really care if OpenProcess fails in most cases
*/
if (process_handle == NULL)
continue;
target_process_name = std::wstring( process_entry.szExeFile );
target_process_name = std::wstring(process_entry.szExeFile);
if ( wide_process_name == target_process_name )
{
LOG_INFO( "Found target process" );
CloseHandle( process_snapshot_handle );
return process_handle;
}
if (wide_process_name == target_process_name)
{
LOG_INFO("Found target process");
CloseHandle(process_snapshot_handle);
return process_handle;
}
} while ( Process32Next( process_snapshot_handle, &process_entry ) );
} while (Process32Next(process_snapshot_handle, &process_entry));
CloseHandle( process_snapshot_handle );
return INVALID_HANDLE_VALUE;
CloseHandle(process_snapshot_handle);
return INVALID_HANDLE_VALUE;
}
bool usermode::Process::GetProcessBaseAddress( UINT64* Result )
bool
usermode::Process::GetProcessBaseAddress(UINT64* Result)
{
HANDLE process_modules_handle;
MODULEENTRY32 module_entry;
HANDLE process_modules_handle = INVALID_HANDLE_VALUE;
MODULEENTRY32 module_entry = {0};
process_modules_handle = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id );
process_modules_handle =
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, this->process_id);
if ( process_modules_handle == INVALID_HANDLE_VALUE )
{
LOG_ERROR( "CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x", GetLastError() );
return false;
}
if (process_modules_handle == INVALID_HANDLE_VALUE)
{
LOG_ERROR("CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x",
GetLastError());
return false;
}
module_entry.dwSize = sizeof( MODULEENTRY32 );
module_entry.dwSize = sizeof(MODULEENTRY32);
if ( !Module32First( process_modules_handle, &module_entry ) )
{
LOG_ERROR( "Module32First failed with status 0x%x", GetLastError() );
CloseHandle( process_modules_handle );
return false;
}
if (!Module32First(process_modules_handle, &module_entry))
{
LOG_ERROR("Module32First failed with status 0x%x", GetLastError());
CloseHandle(process_modules_handle);
return false;
}
*Result = (UINT64)module_entry.modBaseAddr;
CloseHandle( process_modules_handle );
return true;
*Result = (UINT64)module_entry.modBaseAddr;
CloseHandle(process_modules_handle);
return true;
}
void usermode::Process::ScanProcessMemory()
void
usermode::Process::ScanProcessMemory()
{
MEMORY_BASIC_INFORMATION memory_info = { 0 };
UINT64 address;
MEMORY_BASIC_INFORMATION memory_info = {0};
UINT64 address = 0;
if ( !GetProcessBaseAddress( &address) )
{
LOG_ERROR( "Failed to get process base address with status 0x%x", GetLastError() );
return;
}
if (!GetProcessBaseAddress(&address))
{
LOG_ERROR("Failed to get process base address with status 0x%x", GetLastError());
return;
}
while ( VirtualQueryEx(
this->process_handle,
( PVOID )address,
&memory_info,
sizeof( MEMORY_BASIC_INFORMATION )))
{
this->CheckPageProtection( &memory_info );
this->PatternScanRegion(address, &memory_info);
while (VirtualQueryEx(
this->process_handle, (PVOID)address, &memory_info, sizeof(MEMORY_BASIC_INFORMATION)))
{
this->CheckPageProtection(&memory_info);
this->PatternScanRegion(address, &memory_info);
address += memory_info.RegionSize;
}
address += memory_info.RegionSize;
}
}
void usermode::Process::PatternScanRegion( UINT64 Address, MEMORY_BASIC_INFORMATION* Page )
void
usermode::Process::PatternScanRegion(UINT64 Address, MEMORY_BASIC_INFORMATION* Page)
{
/* todo: stream signatures from server */
//char buf[] = "\x85\xc0\x74\x00\xb9\x00\x00\x00\x00\xcd";
char buf[] = "\x55\x8B\xEC\xFF\x75\x00\xD9\x45\x00\x51\xD9\x1C\x00\xE8\x00\x00\x00\x00\x5D\xC2\x00\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC";
std::vector<char> signature;
/* todo: stream signatures from server */
// char buf[] = "\x85\xc0\x74\x00\xb9\x00\x00\x00\x00\xcd";
char buf[] =
"\x55\x8B\xEC\xFF\x75\x00\xD9\x45\x00\x51\xD9\x1C\x00\xE8\x00\x00\x00\x00\x5D\xC2\x00\x00\xCC\xCC\xCC\xCC\xCC\xCC\xCC";
std::vector<char> signature = {0};
for ( int i = 0; i < 10; i++ )
signature.push_back( buf[ i ] );
for (int i = 0; i < 10; i++)
signature.push_back(buf[i]);
/* skip free or reserved pages */
if ( Page->State == MEM_RESERVE || Page->State == MEM_FREE )
return;
/* skip free or reserved pages */
if (Page->State == MEM_RESERVE || Page->State == MEM_FREE)
return;
char* base = ( char* )Address;
char* base = (char*)Address;
for ( unsigned int i = 0; i < Page->RegionSize; i++ )
{
for ( unsigned j = 0; j < signature.size(); j++ )
{
char current_byte = *( base + i );
char current_sig_byte = signature[j];
for (unsigned int i = 0; i < Page->RegionSize; i++)
{
for (unsigned j = 0; j < signature.size(); j++)
{
char current_byte = *(base + i);
char current_sig_byte = signature[j];
/* if we've found the signature, report */
if ( j + 1 == signature.size())
{
global::report_structures::PATTERN_SCAN_FAILURE report;
report.report_code = REPORT_PATTERN_SCAN_FAILURE;
report.address = (UINT64)base + i;
report.signature_id = 1; /* this will be taken from the vector in future */
this->client_interface->ReportViolation( &report );
/* if we've found the signature, report */
if (j + 1 == signature.size())
{
global::report_structures::PATTERN_SCAN_FAILURE report;
report.report_code = REPORT_PATTERN_SCAN_FAILURE;
report.address = (UINT64)base + i;
report.signature_id =
1; /* this will be taken from the vector in future */
this->client_interface->ReportViolation(&report);
/*
* for now return, however when we stream the signatures we iterate over
* each signature for every page
*/
return;
}
/*
* for now return, however when we stream the signatures we iterate
* over each signature for every page
*/
return;
}
/* else, continue searching */
if ( current_byte != current_sig_byte && current_sig_byte != MASK_BYTE )
break;
/* else, continue searching */
if (current_byte != current_sig_byte && current_sig_byte != MASK_BYTE)
break;
i++;
}
}
i++;
}
}
}
void usermode::Process::CheckPageProtection( MEMORY_BASIC_INFORMATION* Page )
void
usermode::Process::CheckPageProtection(MEMORY_BASIC_INFORMATION* Page)
{
/* MEM_IMAGE indicates the pages are mapped into view of an image section */
if ( Page->Type == MEM_IMAGE )
return;
/* MEM_IMAGE indicates the pages are mapped into view of an image section */
if (Page->Type == MEM_IMAGE)
return;
if ( Page->AllocationProtect & PAGE_EXECUTE ||
Page->AllocationProtect & PAGE_EXECUTE_READ ||
Page->AllocationProtect & PAGE_EXECUTE_READWRITE ||
Page->AllocationProtect & PAGE_EXECUTE_WRITECOPY
)
{
//Not etirely sure about this check, needs to be looked into further.
global::report_structures::PAGE_PROTECTION_FAILURE report;
report.report_code = REPORT_PAGE_PROTECTION_VERIFICATION;
report.page_base_address = (UINT64)Page->AllocationBase;
report.allocation_protection = Page->AllocationProtect;
report.allocation_state = Page->State;
report.allocation_type = Page->Type;
this->client_interface->ReportViolation( &report );
}
if (Page->AllocationProtect & PAGE_EXECUTE || Page->AllocationProtect & PAGE_EXECUTE_READ ||
Page->AllocationProtect & PAGE_EXECUTE_READWRITE ||
Page->AllocationProtect & PAGE_EXECUTE_WRITECOPY)
{
// Not etirely sure about this check, needs to be looked into further.
global::report_structures::PAGE_PROTECTION_FAILURE report;
report.report_code = REPORT_PAGE_PROTECTION_VERIFICATION;
report.page_base_address = (UINT64)Page->AllocationBase;
report.allocation_protection = Page->AllocationProtect;
report.allocation_state = Page->State;
report.allocation_type = Page->Type;
this->client_interface->ReportViolation(&report);
}
}

View file

@ -13,36 +13,34 @@
#define ThreadQuerySetWin32StartAddress 9
namespace usermode
namespace usermode {
/*
* This class represents a process and the usermode functions responsible for
* the protection of it. This class represents the protected process and allows
* us to split protection class into methods which can then be easily managed
* by the usermode manager class.
*/
class Process
{
/*
* This class represents a process and the usermode functions responsible for
* the protection of it. This class represents the protected process and allows
* us to split protection class into methods which can then be easily managed
* by the usermode manager class.
*/
class Process
{
HANDLE process_handle;
DWORD process_id;
std::mutex mutex;
std::unique_ptr<Imports> function_imports;
std::vector<DWORD> in_memory_module_checksums;
std::shared_ptr<global::Client> client_interface;
HANDLE process_handle;
DWORD process_id;
std::mutex mutex;
std::unique_ptr<Imports> function_imports;
std::vector<DWORD> in_memory_module_checksums;
std::shared_ptr<global::Client> client_interface;
HANDLE GetHandleToProcessGivenName( std::string ProcessName );
bool CheckIfAddressLiesWithinValidProcessModule( UINT64 Address, bool* Result );
bool GetProcessBaseAddress( UINT64* Result );
void CheckPageProtection( MEMORY_BASIC_INFORMATION* Page );
void PatternScanRegion( UINT64 Address, MEMORY_BASIC_INFORMATION* Page );
HANDLE GetHandleToProcessGivenName(std::string ProcessName);
bool CheckIfAddressLiesWithinValidProcessModule(UINT64 Address, bool* Result);
bool GetProcessBaseAddress(UINT64* Result);
void CheckPageProtection(MEMORY_BASIC_INFORMATION* Page);
void PatternScanRegion(UINT64 Address, MEMORY_BASIC_INFORMATION* Page);
public:
public:
Process(std::shared_ptr<global::Client> ClientInterface);
Process( std::shared_ptr<global::Client> ClientInterface );
void ValidateProcessThreads();
void ScanProcessMemory();
};
void ValidateProcessThreads();
void ScanProcessMemory();
};
}
#endif

View file

@ -6,31 +6,34 @@
#include <TlHelp32.h>
usermode::UManager::UManager( std::shared_ptr<global::ThreadPool> ThreadPool, std::shared_ptr<global::Client> ReportInterface )
usermode::UManager::UManager(std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface)
{
this->thread_pool = ThreadPool;
this->process = std::make_unique<Process>(ReportInterface);
this->thread_pool = ThreadPool;
this->process = std::make_unique<Process>(ReportInterface);
}
usermode::UManager::~UManager()
{
/* Wait for our jobs to be finished, then safely stop our pool */
//while ( true )
//{
// if ( this->thread_pool->Busy() == FALSE )
// {
// this->thread_pool->Stop();
// break;
// }
//}
/* Wait for our jobs to be finished, then safely stop our pool */
// while ( true )
//{
// if ( this->thread_pool->Busy() == FALSE )
// {
// this->thread_pool->Stop();
// break;
// }
// }
}
void usermode::UManager::ValidateProcessThreads()
void
usermode::UManager::ValidateProcessThreads()
{
this->thread_pool->QueueJob( [ this ]() {this->process->ValidateProcessThreads(); } );
this->thread_pool->QueueJob([this]() { this->process->ValidateProcessThreads(); });
}
void usermode::UManager::ValidateProcessMemory()
void
usermode::UManager::ValidateProcessMemory()
{
this->thread_pool->QueueJob( [ this ]() {this->process->ScanProcessMemory(); } );
this->thread_pool->QueueJob([this]() { this->process->ScanProcessMemory(); });
}

View file

@ -12,26 +12,26 @@
#include "process.h"
namespace usermode
namespace usermode {
/*
* The manager class is meant to abstract away the interaction between the Process
* class and the threadpool class to allow a single thread (or multiple) to easily run
* the core business logic of running tasks in a certain order.
*/
class UManager
{
/*
* The manager class is meant to abstract away the interaction between the Process
* class and the threadpool class to allow a single thread (or multiple) to easily run
* the core business logic of running tasks in a certain order.
*/
class UManager
{
std::unique_ptr<Process> process;
std::shared_ptr<global::ThreadPool> thread_pool;
std::unique_ptr<Process> process;
std::shared_ptr<global::ThreadPool> thread_pool;
public:
UManager( std::shared_ptr<global::ThreadPool> ThreadPool, std::shared_ptr<global::Client> ReportInterface );
~UManager();
public:
UManager(std::shared_ptr<global::ThreadPool> ThreadPool,
std::shared_ptr<global::Client> ReportInterface);
~UManager();
void ValidateProcessThreads();
void ValidateProcessMemory();
void ValidateProcessModules();
};
void ValidateProcessThreads();
void ValidateProcessMemory();
void ValidateProcessModules();
};
}
#endif