mirror-ac/user/km/driver.cpp

644 lines
15 KiB
C++
Raw Normal View History

2023-08-17 10:45:50 +02:00
#include "driver.h"
2023-08-20 09:32:46 +02:00
#include <iostream>
2023-08-19 04:52:57 +02:00
#include "../common.h"
#include <winternl.h>
2023-08-19 04:52:57 +02:00
2023-09-07 19:49:36 +02:00
typedef BOOLEAN( NTAPI* RtlDosPathNameToNtPathName_U )(
PCWSTR DosPathName, PUNICODE_STRING NtPathName, PCWSTR* NtFileNamePart, PVOID DirectoryInfo );
2023-08-22 19:32:25 +02:00
kernelmode::Driver::Driver( LPCWSTR DriverName, std::shared_ptr<global::Client> ReportInterface )
2023-08-17 10:45:50 +02:00
{
this->driver_name = DriverName;
2023-08-18 07:33:13 +02:00
this->report_interface = ReportInterface;
2023-08-19 05:04:37 +02:00
this->driver_handle = CreateFileW(
DriverName,
GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0
);
if ( this->driver_handle == INVALID_HANDLE_VALUE )
2023-08-30 15:23:04 +02:00
{
2023-08-19 05:04:37 +02:00
LOG_ERROR( "Failed to open handle to driver with status 0x%x", GetLastError() );
2023-08-30 15:23:04 +02:00
return;
}
2023-08-24 15:12:49 +02:00
this->NotifyDriverOnProcessLaunch();
2023-08-17 10:45:50 +02:00
}
2023-08-19 04:52:57 +02:00
2023-08-24 17:10:40 +02:00
kernelmode::Driver::~Driver()
{
this->NotifyDriverOnProcessTermination();
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::RunNmiCallbacks()
2023-08-19 04:52:57 +02:00
{
BOOLEAN status;
DWORD bytes_returned;
global::report_structures::NMI_CALLBACK_FAILURE report;
status = DeviceIoControl(
this->driver_handle,
IOCCTL_RUN_NMI_CALLBACKS,
NULL,
NULL,
&report,
sizeof( global::report_structures::NMI_CALLBACK_FAILURE ),
&bytes_returned,
( LPOVERLAPPED )NULL
);
if ( status == NULL )
{
LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() );
return;
}
if ( bytes_returned == NULL )
{
LOG_INFO( "All threads valid, nmis fine." );
return;
}
/* else, report */
this->report_interface->ReportViolation( &report );
}
2023-08-19 11:44:42 +02:00
/*
* 1. Checks that every device object has a system module to back it
* 2. Checks the IOCTL dispatch routines to ensure they lie within the module
*/
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::VerifySystemModules()
2023-08-19 04:52:57 +02:00
{
BOOLEAN status;
2023-08-19 08:06:51 +02:00
DWORD bytes_returned;
2023-08-19 04:52:57 +02:00
PVOID buffer;
SIZE_T buffer_size;
SIZE_T header_size;
/*
* allocate enough to report 5 invalid driver objects + header. The reason we use a raw
* pointer here is so we can pass the address to DeviceIoControl. You are not able (atleast
* as far as im concerned) to pass a shared ptr to DeviceIoControl.
*/
header_size = sizeof( global::report_structures::MODULE_VALIDATION_FAILURE_HEADER );
2023-08-19 08:06:51 +02:00
buffer_size = sizeof( global::report_structures::MODULE_VALIDATION_FAILURE ) *
2023-08-19 04:52:57 +02:00
MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT +
header_size;
buffer = malloc( buffer_size );
2023-08-19 05:04:37 +02:00
if ( !buffer )
return;
2023-08-19 04:52:57 +02:00
status = DeviceIoControl(
this->driver_handle,
IOCTL_VALIDATE_DRIVER_OBJECTS,
NULL,
NULL,
buffer,
buffer_size,
&bytes_returned,
2023-08-19 08:06:51 +02:00
NULL
2023-08-19 04:52:57 +02:00
);
if ( status == NULL )
{
LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() );
free( buffer );
return;
}
2023-08-19 06:37:53 +02:00
if ( bytes_returned == NULL )
2023-08-19 04:52:57 +02:00
{
2023-08-19 06:22:43 +02:00
LOG_INFO( "All modules valid :)" );
2023-08-19 04:52:57 +02:00
free( buffer );
return;
2023-08-19 08:06:51 +02:00
}
2023-08-19 04:52:57 +02:00
/*
2023-08-19 08:06:51 +02:00
* We are splitting up each packet here and passing them on one by one since
2023-08-19 04:52:57 +02:00
* if I am being honest it is just easier in c++ and that way the process
* is streamlined just like all other report packets.
*/
2023-08-20 10:21:20 +02:00
global::report_structures::MODULE_VALIDATION_FAILURE_HEADER* header =
( global::report_structures::MODULE_VALIDATION_FAILURE_HEADER* )buffer;
2023-08-19 06:37:53 +02:00
2023-08-20 10:21:20 +02:00
for ( int i = 0; i < header->module_count; i++ )
2023-08-19 04:52:57 +02:00
{
2023-08-20 10:21:20 +02:00
global::report_structures::MODULE_VALIDATION_FAILURE* report =
( global::report_structures::MODULE_VALIDATION_FAILURE* )(
( UINT64 )buffer + sizeof( global::report_structures::MODULE_VALIDATION_FAILURE_HEADER ) +
i * sizeof( global::report_structures::MODULE_VALIDATION_FAILURE ) );
2023-08-20 09:32:46 +02:00
2023-08-20 11:17:03 +02:00
this->report_interface->ReportViolation( report );
2023-08-19 04:52:57 +02:00
}
free( buffer );
}
2023-08-20 16:12:04 +02:00
/*
* HOW THIS WILL WORK:
*
* 1. On driver initiation, ObRegisterCallbacks will be registered
* 2. Each time a process that is not whitelisted tries to open a handle
* to our game we will store the report in an a report queue
* 3. the user mode app will then periodically query the driver asking
* how many pending reports there are
* 4. once the number is received, the app will allocate a buffer large enough
* for all the reports and once again call CompleteQueuedCallbackReports
* 5. This will then retrieve the reports into the buffer and from there
* we can iteratively report them the same way as we do with the system
* modules.
*/
2023-09-02 10:54:04 +02:00
struct REPORT_ID
{
INT report_id;
};
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::QueryReportQueue()
2023-08-20 16:12:04 +02:00
{
BOOLEAN status;
DWORD bytes_returned;
2023-08-20 17:04:53 +02:00
PVOID buffer;
LONG buffer_size;
2023-09-02 10:54:04 +02:00
REPORT_ID* report_header;
SIZE_T total_size = NULL;
global::report_structures::OPEN_HANDLE_FAILURE_REPORT* handle_report;
global::report_structures::ATTACH_PROCESS_REPORT* attach_report;
2023-09-18 05:15:26 +02:00
global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT* allocation_report;
2023-08-21 06:08:57 +02:00
2023-09-18 05:15:26 +02:00
buffer_size = sizeof( global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT ) * MAX_REPORTS_PER_IRP;
2023-08-20 17:04:53 +02:00
buffer = malloc( buffer_size );
2023-08-20 16:12:04 +02:00
status = DeviceIoControl(
this->driver_handle,
2023-08-20 17:04:53 +02:00
IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE,
2023-08-20 16:12:04 +02:00
NULL,
NULL,
2023-08-20 17:04:53 +02:00
buffer,
buffer_size,
2023-08-20 16:12:04 +02:00
&bytes_returned,
2023-08-20 17:04:53 +02:00
NULL
2023-08-20 16:12:04 +02:00
);
if ( status == NULL )
{
LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() );
2023-08-21 06:08:57 +02:00
free( buffer );
2023-08-20 17:04:53 +02:00
return;
2023-08-20 16:12:04 +02:00
}
2023-09-18 05:15:26 +02:00
global::report_structures::REPORT_QUEUE_HEADER* header =
( global::report_structures::REPORT_QUEUE_HEADER* )buffer;
2023-08-20 16:12:04 +02:00
2023-08-20 18:06:21 +02:00
if ( !header )
2023-08-21 06:08:57 +02:00
goto end;
2023-08-20 18:06:21 +02:00
2023-09-02 17:56:46 +02:00
LOG_INFO( "Report count: %d", header->count );
2023-08-21 06:45:33 +02:00
if ( header->count == 0 )
goto end;
2023-09-02 15:47:15 +02:00
for ( INT i = 0; i < header->count; i++ )
2023-08-20 17:04:53 +02:00
{
2023-09-18 05:15:26 +02:00
report_header = ( REPORT_ID* )( ( UINT64 )buffer +
sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
2023-09-02 10:54:04 +02:00
2023-09-02 17:56:46 +02:00
LOG_INFO( "Report id: %d", report_header->report_id );
2023-09-02 10:54:04 +02:00
2023-09-02 17:56:46 +02:00
if ( report_header->report_id == REPORT_ILLEGAL_ATTACH_PROCESS )
{
attach_report = ( global::report_structures::ATTACH_PROCESS_REPORT* )(
2023-09-18 05:15:26 +02:00
( UINT64 )buffer + sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
2023-09-02 10:54:04 +02:00
this->report_interface->ReportViolation( attach_report );
total_size += sizeof( global::report_structures::ATTACH_PROCESS_REPORT );
2023-09-02 17:56:46 +02:00
continue;
}
2023-09-18 05:15:26 +02:00
else if ( report_header->report_id == REPORT_ILLEGAL_HANDLE_OPERATION )
2023-09-02 17:56:46 +02:00
{
2023-09-02 10:54:04 +02:00
handle_report = ( global::report_structures::OPEN_HANDLE_FAILURE_REPORT* )(
2023-09-18 05:15:26 +02:00
( UINT64 )buffer + sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
2023-09-02 10:54:04 +02:00
this->report_interface->ReportViolation( handle_report );
total_size += sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT );
2023-09-02 17:56:46 +02:00
2023-09-18 05:15:26 +02:00
continue;
}
else if ( report_header->report_id == REPORT_INVALID_PROCESS_ALLOCATION )
{
allocation_report = ( global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT* )(
( UINT64 )buffer + sizeof( global::report_structures::REPORT_QUEUE_HEADER ) + total_size );
this->report_interface->ReportViolation( allocation_report );
total_size += sizeof( global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT );
2023-09-02 17:56:46 +02:00
continue;
2023-09-02 10:54:04 +02:00
}
2023-08-20 17:04:53 +02:00
}
2023-08-20 16:12:04 +02:00
2023-08-21 06:08:57 +02:00
end:
2023-08-20 17:04:53 +02:00
free( buffer );
2023-08-20 16:12:04 +02:00
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::RunCallbackReportQueue()
2023-08-21 06:45:33 +02:00
{
2023-08-21 11:13:00 +02:00
/*TODO have some volatile flag instead */
2023-08-30 15:23:04 +02:00
this->QueryReportQueue();
2023-08-21 06:45:33 +02:00
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::NotifyDriverOnProcessLaunch()
2023-08-19 04:52:57 +02:00
{
2023-08-20 16:12:04 +02:00
BOOLEAN status;
kernelmode::DRIVER_INITIATION_INFORMATION information;
information.protected_process_id = GetCurrentProcessId();
status = DeviceIoControl(
this->driver_handle,
IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH,
&information,
sizeof( kernelmode::DRIVER_INITIATION_INFORMATION ),
NULL,
NULL,
NULL,
NULL
);
if ( status == NULL )
LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() );
2023-08-19 04:52:57 +02:00
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::DetectSystemVirtualization()
2023-08-19 04:52:57 +02:00
{
2023-08-21 17:48:34 +02:00
BOOLEAN status;
HYPERVISOR_DETECTION_REPORT report;
DWORD bytes_returned;
2023-08-20 16:12:04 +02:00
2023-08-21 17:48:34 +02:00
status = DeviceIoControl(
this->driver_handle,
IOCTL_PERFORM_VIRTUALIZATION_CHECK,
NULL,
NULL,
&report,
sizeof( HYPERVISOR_DETECTION_REPORT ),
&bytes_returned,
NULL
);
2023-08-19 04:52:57 +02:00
2023-08-21 17:48:34 +02:00
if ( status == NULL )
{
LOG_ERROR( "DeviceIoControl failed virtualization detect with status %x", GetLastError() );
return;
}
2023-08-19 04:52:57 +02:00
2023-08-21 17:48:34 +02:00
if ( report.aperf_msr_timing_check == TRUE || report.invd_emulation_check == TRUE )
LOG_INFO( "HYPERVISOR DETECTED!!!" );
/* shutdown the application or smth lmao */
2023-08-19 04:52:57 +02:00
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::CheckHandleTableEntries()
2023-08-22 10:51:52 +02:00
{
BOOLEAN status;
DWORD bytes_returned;
/*
* Only pass the IOCTL code and nothing else since the reports are bundled
* with the handle ObRegisterCallbacks report queue hence the QueryReportQueue
* function will handle these reports.
*/
status = DeviceIoControl(
this->driver_handle,
IOCTL_ENUMERATE_HANDLE_TABLES,
NULL,
NULL,
NULL,
NULL,
&bytes_returned,
NULL
);
if ( status == NULL )
LOG_ERROR( "CheckHandleTableEntries failed with status %x", status );
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::RequestModuleExecutableRegions()
2023-08-22 19:32:25 +02:00
{
BOOLEAN status;
2023-08-23 14:14:20 +02:00
DWORD bytes_returned;
ULONG module_size;
PVOID buffer;
module_size = this->RequestTotalModuleSize();
if ( module_size == NULL )
{
LOG_ERROR( "RequestTotalModuleSize failed lolz" );
return;
}
LOG_INFO( "module size: %lx", module_size );
/*
* allocate a buffer big enough for the entire module not including section headers or
* packet headers, however it should be big enough since executable sections do not
* make up 100% of the image size. Bit hacky but it works.
*/
2023-08-23 14:14:20 +02:00
buffer = malloc( module_size );
if ( !buffer )
return;
status = DeviceIoControl(
this->driver_handle,
IOCTL_RETRIEVE_MODULE_EXECUTABLE_REGIONS,
NULL,
NULL,
buffer,
module_size,
&bytes_returned,
NULL
);
if ( status == NULL )
{
LOG_ERROR( "failed to retrieve module executable regions lozl %x", GetLastError() );
goto end;
}
LOG_INFO( "bytes returned: %lx", bytes_returned );
2023-09-08 20:41:11 +02:00
this->report_interface->ServerSend( buffer, bytes_returned, CLIENT_REQUEST_MODULE_INTEGRITY_CHECK );
2023-08-23 14:17:43 +02:00
2023-08-23 14:14:20 +02:00
end:
free( buffer );
2023-08-22 19:32:25 +02:00
}
2023-08-28 17:00:52 +02:00
VOID kernelmode::Driver::ScanForUnlinkedProcess()
{
BOOLEAN status;
DWORD bytes_returned;
global::report_structures::INVALID_PROCESS_ALLOCATION_REPORT report;
status = DeviceIoControl(
this->driver_handle,
IOCTL_SCAN_FOR_UNLINKED_PROCESS,
NULL,
NULL,
&report,
sizeof(report),
&bytes_returned,
NULL
);
if ( status == NULL || bytes_returned == NULL)
{
LOG_ERROR( "failed to scan for unlinked processes %x", GetLastError() );
return;
}
2023-09-08 20:41:11 +02:00
this->report_interface->ServerSend( &report, bytes_returned, CLIENT_REQUEST_MODULE_INTEGRITY_CHECK );
2023-08-28 17:00:52 +02:00
}
2023-09-01 13:46:31 +02:00
VOID kernelmode::Driver::PerformIntegrityCheck()
{
BOOLEAN status;
status = DeviceIoControl(
this->driver_handle,
IOCTL_PERFORM_INTEGRITY_CHECK,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
if ( status == NULL )
LOG_ERROR( "Failed to perform integrity check with status %x", status );
}
2023-08-23 14:14:20 +02:00
ULONG kernelmode::Driver::RequestTotalModuleSize()
2023-08-22 19:32:25 +02:00
{
2023-08-23 14:14:20 +02:00
BOOLEAN status;
DWORD bytes_returned;
ULONG module_size;
status = DeviceIoControl(
this->driver_handle,
IOCTL_REQUEST_TOTAL_MODULE_SIZE,
NULL,
NULL,
&module_size,
sizeof(ULONG),
&bytes_returned,
NULL
);
if ( status == NULL )
LOG_ERROR( "CheckHandleTableEntries failed with status %x", status );
2023-08-22 19:32:25 +02:00
2023-08-23 14:14:20 +02:00
return module_size;
2023-08-22 19:32:25 +02:00
}
2023-08-24 17:10:40 +02:00
VOID kernelmode::Driver::NotifyDriverOnProcessTermination()
{
BOOLEAN status;
status = DeviceIoControl(
this->driver_handle,
IOCTL_NOTIFY_DRIVER_ON_PROCESS_TERMINATION,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
if ( status == NULL )
LOG_ERROR( "NotifyDriverOnProcessTermination failed with status %x", status );
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::ValidateKPRCBThreads()
2023-08-19 04:52:57 +02:00
{
2023-08-30 13:15:57 +02:00
BOOLEAN status;
DWORD bytes_returned;
global::report_structures::HIDDEN_SYSTEM_THREAD_REPORT report;
2023-08-22 10:51:52 +02:00
2023-08-30 13:15:57 +02:00
status = DeviceIoControl(
this->driver_handle,
IOCTL_VALIDATE_KPRCB_CURRENT_THREAD,
NULL,
NULL,
&report,
sizeof( report ),
&bytes_returned,
NULL
);
if ( status == NULL)
{
LOG_ERROR( "failed to validate kpcrb threads with status %x", GetLastError() );
return;
}
if ( bytes_returned == NULL )
return;
2023-09-08 20:41:11 +02:00
this->report_interface->ServerSend( &report, bytes_returned, CLIENT_REQUEST_MODULE_INTEGRITY_CHECK );
2023-08-19 04:52:57 +02:00
}
2023-09-02 15:47:15 +02:00
VOID kernelmode::Driver::CheckForAttachedThreads()
{
BOOLEAN status;
status = DeviceIoControl(
this->driver_handle,
IOCTL_DETECT_ATTACHED_THREADS,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
if ( status == NULL )
LOG_ERROR( "failed to check for attached threads %x", GetLastError() );
}
2023-08-23 14:14:20 +02:00
VOID kernelmode::Driver::CheckDriverHeartbeat()
2023-08-19 04:52:57 +02:00
{
2023-08-22 10:51:52 +02:00
2023-08-19 04:52:57 +02:00
}
2023-09-05 11:16:32 +02:00
VOID kernelmode::Driver::VerifyProcessLoadedModuleExecutableRegions()
{
HANDLE process_modules_handle;
MODULEENTRY32 module_entry;
BOOLEAN status;
PROCESS_MODULE_INFORMATION module_information;
PROCESS_MODULE_VALIDATION_RESULT validation_result;
DWORD bytes_returned;
RtlDosPathNameToNtPathName_U pRtlDosPathNameToNtPathName_U = NULL;
UNICODE_STRING nt_path_name;
pRtlDosPathNameToNtPathName_U = ( RtlDosPathNameToNtPathName_U )
GetProcAddress( GetModuleHandle( L"ntdll.dll" ), "RtlDosPathNameToNtPathName_U" );
2023-09-05 11:16:32 +02:00
process_modules_handle = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, GetCurrentProcessId() );
if ( process_modules_handle == INVALID_HANDLE_VALUE )
{
LOG_ERROR( "CreateToolHelp32Snapshot with TH32CS_SNAPMODULE failed with status 0x%x", GetLastError() );
return;
}
module_entry.dwSize = sizeof( MODULEENTRY32 );
if ( !Module32First( process_modules_handle, &module_entry ) )
{
LOG_ERROR( "Module32First failed with status 0x%x", GetLastError() );
return;
}
do
{
module_information.module_base = module_entry.modBaseAddr;
module_information.module_size = module_entry.modBaseSize;
( *pRtlDosPathNameToNtPathName_U )(
module_entry.szExePath,
&nt_path_name,
NULL,
NULL
);
memcpy( module_information.module_path, nt_path_name.Buffer, MAX_MODULE_PATH );
2023-09-05 11:16:32 +02:00
status = DeviceIoControl(
this->driver_handle,
IOCTL_VALIDATE_PROCESS_LOADED_MODULE,
&module_information,
sizeof( module_information ),
&validation_result,
sizeof( validation_result ),
&bytes_returned,
NULL
);
if ( status == NULL || bytes_returned == NULL )
{
LOG_ERROR( "failed to validate process module with status %x", GetLastError() );
continue;
}
2023-09-05 18:47:46 +02:00
if ( validation_result.is_module_valid == FALSE )
{
/*TODO: copy module aswell from an anomaly offset */
global::report_structures::PROCESS_MODULES_INTEGRITY_CHECK_FAILURE report;
report.report_code = REPORT_CODE_MODULE_VERIFICATION;
report.module_base_address = (UINT64)module_entry.modBaseAddr;
report.module_size = module_entry.modBaseSize;
std::wstring wstr( module_entry.szModule );
2023-09-10 19:32:12 +02:00
std::string module_name_string = std::string( wstr.begin(), wstr.end() );
memcpy( &report.module_name, &module_name_string, module_name_string.length() );
2023-09-05 18:47:46 +02:00
this->report_interface->ReportViolation( &report );
}
2023-09-11 06:53:46 +02:00
else
{
2023-09-11 11:23:29 +02:00
LOG_INFO("Module %S is valid", module_entry.szModule );
2023-09-11 06:53:46 +02:00
}
2023-09-05 11:16:32 +02:00
} while ( Module32Next( process_modules_handle, &module_entry ) );
end:
CloseHandle( process_modules_handle );
}
2023-09-07 19:49:36 +02:00
2023-09-08 20:41:11 +02:00
VOID kernelmode::Driver::SendClientHardwareInformation()
2023-09-07 19:49:36 +02:00
{
BOOLEAN status;
global::headers::SYSTEM_INFORMATION system_information;
DWORD bytes_returned;
2023-09-07 19:49:36 +02:00
status = DeviceIoControl(
this->driver_handle,
IOCTL_REQUEST_HARDWARE_INFORMATION,
NULL,
NULL,
&system_information,
sizeof( global::headers::SYSTEM_INFORMATION ),
&bytes_returned,
NULL
);
if ( status == NULL || bytes_returned == NULL)
{
LOG_ERROR( "DeviceIoControl failed with status %x", GetLastError() );
return;
}
2023-09-08 20:41:11 +02:00
this->report_interface->ServerSend(
&system_information, sizeof( global::headers::SYSTEM_INFORMATION ), CLIENT_SEND_SYSTEM_INFORMATION );
2023-09-07 19:49:36 +02:00
}
2023-09-15 22:25:02 +02:00
VOID GetKernelStructureOffsets()
{
}