mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
enhance smbios parsing to automatically detect system
This commit is contained in:
parent
f3fafd5bc9
commit
1eff01c8e1
24 changed files with 1718 additions and 1508 deletions
221
driver/driver.c
221
driver/driver.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
293
user/client.h
293
user/client.h
|
@ -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
|
||||
|
|
1060
user/km/driver.cpp
1060
user/km/driver.cpp
File diff suppressed because it is too large
Load diff
193
user/km/driver.h
193
user/km/driver.h
|
@ -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
|
||||
|
|
|
@ -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(); });
|
||||
}
|
|
@ -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
|
160
user/main.cpp
160
user/main.cpp
|
@ -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.
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
68
user/pipe.h
68
user/pipe.h
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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(); });
|
||||
}
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue