This commit is contained in:
lhodges1 2023-11-18 21:40:22 +11:00
parent 4797892900
commit a043150844
10 changed files with 138 additions and 38 deletions

View file

@ -133,10 +133,11 @@ typedef struct _DRIVER_CONFIG
typedef struct _PROCESS_CONFIG
{
BOOLEAN initialised;
LONG um_handle;
LONG km_handle;
ULONG um_handle;
ULONG km_handle;
PEPROCESS process;
OB_CALLBACKS_CONFIG ob_cb_config;
UINT16 cookie;
KGUARDED_MUTEX lock;
}PROCESS_CONFIG, * PPROCESS_CONFIG;
@ -144,6 +145,23 @@ typedef struct _PROCESS_CONFIG
DRIVER_CONFIG driver_config = { 0 };
PROCESS_CONFIG process_config = { 0 };
/*
* ioctl_flag consists of the first 16 bits of the Function part of the CTL code
* cookie_value consists of a static 16 bit value generated by the user mode app on startup
* which is then passed to the driver and stored.
*/
typedef union _SECURITY_COOKIE
{
struct
{
UINT32 ioctl_flag : 16;
UINT32 cookie_value : 16;
}bits;
UINT32 flags;
}SECURITY_COOKIE, *PSECURITY_COOKIE;
#define POOL_TAG_CONFIG 'conf'
/*
@ -761,6 +779,19 @@ end:
return status;
}
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Lock_kind_mutex_)
_Releases_lock_(_Lock_kind_mutex_)
VOID
ImageLoadSetProcessId(
_In_ HANDLE ProcessId
)
{
KeAcquireGuardedMutex(&process_config.lock);
process_config.km_handle = (ULONG)ProcessId;
KeReleaseGuardedMutex(&process_config.lock);
}
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Lock_kind_mutex_)
_Releases_lock_(_Lock_kind_mutex_)
@ -785,18 +816,34 @@ ProcLoadInitialiseProcessConfig(
information = (PDRIVER_INITIATION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
status = PsLookupProcessByProcessId(information->protected_process_id, &eprocess);
KeAcquireGuardedMutex(&process_config.lock);
process_config.um_handle = information->protected_process_id;
/*
* What if we pass an invalid handle here? not good.
*/
status = PsLookupProcessByProcessId(process_config.um_handle, &eprocess);
if (!NT_SUCCESS(status))
return status;
{
status = STATUS_INVALID_PARAMETER;
goto end;
}
KeAcquireGuardedMutex(&process_config.lock);
process_config.km_handle = PsGetProcessId(eprocess);
if (!process_config.km_handle)
{
status = STATUS_INVALID_PARAMETER;
goto end;
}
process_config.process = eprocess;
process_config.um_handle = information->protected_process_id;
process_config.km_handle = PsGetProcessId(eprocess);
process_config.initialised = TRUE;
end:
KeReleaseGuardedMutex(&process_config.lock);
return status;
@ -1017,6 +1064,18 @@ DrvLoadEnableNotifyRoutines()
return status;
}
//status = PsSetLoadImageNotifyRoutine(ImageLoadNotifyRoutine);
//if (!NT_SUCCESS(status))
//{
// DEBUG_ERROR("PsSetCreateProcessNotifyRoutine failed with status %x", status);
// PsRemoveCreateThreadNotifyRoutine(ThreadCreateNotifyRoutine);
// PsSetCreateProcessNotifyRoutine(ProcessCreateNotifyRoutine, TRUE);
// DrvUnloadFreeThreadList();
// DrvUnloadFreeProcessList();
// return status;
//}
return status;
}

View file

@ -157,6 +157,14 @@ GetCallbackConfigStructure(
_Out_ POB_CALLBACKS_CONFIG* CallbackConfiguration
);
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Lock_kind_mutex_)
_Releases_lock_(_Lock_kind_mutex_)
VOID
ImageLoadSetProcessId(
_In_ HANDLE ProcessId
);
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Lock_kind_mutex_)
_Releases_lock_(_Lock_kind_mutex_)

View file

@ -1080,6 +1080,9 @@ end:
* StoreModuleExecutableRegionsInBuffer() just as we did before.
* 5. With the 2 buffers that contain both images executable regions, we hash them and compare
* for anomalies.
*
* note: Its important to realise that since these are user mode modules, they are often hooked
* by various legitimate programs - such as discord, nvidia etc. So this needs to be rethinked.
*/
NTSTATUS
ValidateProcessLoadedModule(
@ -1088,23 +1091,23 @@ ValidateProcessLoadedModule(
{
PAGED_CODE();
NTSTATUS status;
BOOLEAN bstatus;
PROCESS_MODULE_VALIDATION_RESULT validation_result;
PPROCESS_MODULE_INFORMATION module_info;
PKPROCESS process;
KAPC_STATE apc_state;
NTSTATUS status = STATUS_ABANDONED;
BOOLEAN bstatus = FALSE;
PROCESS_MODULE_VALIDATION_RESULT validation_result = { 0 };
PPROCESS_MODULE_INFORMATION module_info = NULL;
PKPROCESS process = NULL;
KAPC_STATE apc_state = { 0 };
PVOID in_memory_buffer = NULL;
PVOID disk_buffer = NULL;
PVOID in_memory_hash = NULL;
PVOID disk_hash = NULL;
ULONG in_memory_hash_size = NULL;
ULONG disk_hash_size = NULL;
SIZE_T bytes_written = NULL;
UNICODE_STRING module_path;
ULONG in_memory_hash_size = 0;
ULONG disk_hash_size = 0;
SIZE_T bytes_written = 0;
UNICODE_STRING module_path = { 0 };
HANDLE section_handle = NULL;
PVOID section = NULL;
ULONG section_size = NULL;
ULONG section_size = 0;
status = ValidateIrpInputBuffer(Irp, sizeof(PROCESS_MODULE_INFORMATION));
@ -1222,7 +1225,7 @@ ValidateProcessLoadedModule(
);
end:
if (section_handle != NULL)
ZwClose(section_handle);
@ -1269,6 +1272,10 @@ GetHardDiskDriveSerialNumber(
RtlInitUnicodeString(&physical_drive_path, L"\\DosDevices\\PhysicalDrive0");
/*
* No need to use the flag OBJ_FORCE_ACCESS_CHECK since we arent passing a handle given
* to us from usermode.
*/
InitializeObjectAttributes(
&attributes,
&physical_drive_path,
@ -1945,6 +1952,16 @@ ValidateSystemModules()
return status;
}
/*
* After some further research it appears that performing integrity checks the same way as validating
* other modules is not as straight forward as there are many (thousands) of hooks that take place in
* a legitmate ntoskrnl.exe image.
*
* Initial ideas are to maybe only validate the text sections of key functions such as MmCopyMemory,
* though this is quite manual and the potential to miss functions could be common.
*
* Need to do some more research & testing in this department.
*/
NTSTATUS
ValidateNtoskrnl()
{

View file

@ -75,8 +75,8 @@ DispatchApcOperation(
}
/*
* Obviously, its important we check that the output buffer size for each IRP is big enough
* to hold whatever we are passing back to usermode.
* Obviously, its important we check that the input and output buffer sizes for each IRP is big
* enough to hold the incoming and outgoing information.
*
* Another important thing to note is that the windows IO manager will only zero out the size
* of the input buffer. Given that we use METHOD_BUFFERED for all communication, the input
@ -151,7 +151,7 @@ DeviceControl(
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION stack_location = IoGetCurrentIrpStackLocation(Irp);
HANDLE handle;
HANDLE handle = NULL;
PKTHREAD thread = NULL;
BOOLEAN security_flag = FALSE;
@ -503,6 +503,8 @@ DeviceCreate(
DEBUG_LOG("Handle opened to DonnaAC");
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}

View file

@ -8,7 +8,7 @@
typedef struct _DRIVER_INITIATION_INFORMATION
{
LONG protected_process_id;
ULONG protected_process_id;
} DRIVER_INITIATION_INFORMATION, * PDRIVER_INITIATION_INFORMATION;

View file

@ -461,6 +461,9 @@ ValidateDriverObjectHasBackingModule(
PRTL_MODULE_EXTENDED_INFO system_module = (PRTL_MODULE_EXTENDED_INFO)(
(uintptr_t)ModuleInformation->address + i * sizeof(RTL_MODULE_EXTENDED_INFO));
if (system_module->ImageSize == 0 || system_module->ImageBase == 0)
return STATUS_INVALID_MEMBER;
if (system_module->ImageBase == DriverObject->DriverStart)
{
*Result = TRUE;
@ -477,7 +480,7 @@ ValidateDriverObjectHasBackingModule(
//https://imphash.medium.com/windows-process-internals-a-few-concepts-to-know-before-jumping-on-memory-forensics-part-3-4a0e195d947b
NTSTATUS
GetSystemModuleInformation(
_Inout_ PSYSTEM_MODULES ModuleInformation
_Out_ PSYSTEM_MODULES ModuleInformation
)
{
PAGED_CODE();
@ -511,7 +514,7 @@ GetSystemModuleInformation(
if (!driver_information)
{
DEBUG_ERROR("Failed to allocate pool LOL");
return STATUS_ABANDONED;
return STATUS_MEMORY_NOT_ALLOCATED;
}
/* Query the modules again this time passing a pointer to the allocated buffer */
@ -635,8 +638,8 @@ ValidateDriverObjects(
while (sub_entry)
{
BOOLEAN flag = FALSE;
PDRIVER_OBJECT current_driver = sub_entry->Object;
BOOLEAN flag;
/* validate driver has backing module */
@ -752,7 +755,7 @@ HandleValidateDriversIOCTL(
goto end;
}
MODULE_VALIDATION_FAILURE_HEADER header;
MODULE_VALIDATION_FAILURE_HEADER header = { 0 };
header.module_count = head->count >= MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT
? MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT
@ -964,7 +967,7 @@ AnalyseNmiData(
* single report.
*/
NMI_CALLBACK_FAILURE report;
NMI_CALLBACK_FAILURE report = { 0 };
report.report_code = REPORT_NMI_CALLBACK_FAILURE;
report.kthread_address = thread_data->kthread_address;
report.invalid_rip = stack_frame;
@ -1310,14 +1313,14 @@ ApcNormalRoutine(
VOID
FlipKThreadMiscFlagsFlag(
_In_ PKTHREAD Thread,
_In_ LONG FlagIndex,
_In_ ULONG FlagIndex,
_In_ BOOLEAN NewValue
)
{
PAGED_CODE();
PLONG misc_flags = (PLONG)((UINT64)Thread + KTHREAD_MISC_FLAGS_OFFSET);
LONG mask = 1U << FlagIndex;
ULONG mask = 1ul << FlagIndex;
if (NewValue)
*misc_flags |= mask;
@ -1348,7 +1351,11 @@ ValidateThreadViaKernelApcCallback(
PAPC_STACKWALK_CONTEXT context = (PAPC_STACKWALK_CONTEXT)Context;
LPCSTR process_name = PsGetProcessImageFileName(ThreadListEntry->owning_process);
/* we dont want to schedule an apc to threads owned by the kernel */
/*
* we dont want to schedule an apc to threads owned by the kernel
*
* Actually we do... todo: fix this.
*/
if (ThreadListEntry->owning_process == PsInitialSystemProcess || !Context)
return;
@ -1546,7 +1553,7 @@ LaunchInterProcessInterrupt(
{
PAGED_CODE();
NTSTATUS status;
NTSTATUS status = STATUS_SUCCESS;
SYSTEM_MODULES system_modules = { 0 };
NMI_CONTEXT ipi_context = { 0 };
PVOID callback_handle;
@ -1564,13 +1571,20 @@ LaunchInterProcessInterrupt(
ExAllocatePool2(POOL_FLAG_NON_PAGED, ipi_context.core_count * STACK_FRAME_POOL_SIZE, STACK_FRAMES_POOL);
if (!ipi_context.stack_frames)
{
status = STATUS_MEMORY_NOT_ALLOCATED;
goto end;
}
ipi_context.thread_data_pool =
ExAllocatePool2(POOL_FLAG_NON_PAGED, ipi_context.core_count * sizeof(NMI_CALLBACK_DATA), THREAD_DATA_POOL);
if (!ipi_context.thread_data_pool)
{
status = STATUS_MEMORY_NOT_ALLOCATED;
goto end;
}
/*
* We query the system modules each time since they can potentially

View file

@ -71,7 +71,7 @@ typedef struct _APC_STACKWALK_CONTEXT
NTSTATUS
GetSystemModuleInformation(
_Inout_ PSYSTEM_MODULES ModuleInformation
_Out_ PSYSTEM_MODULES ModuleInformation
);
NTSTATUS
@ -113,7 +113,7 @@ IsInstructionPointerInInvalidRegion(
BOOLEAN
FlipKThreadMiscFlagsFlag(
_In_ PKTHREAD Thread,
_In_ LONG FlagIndex,
_In_ ULONG FlagIndex,
_In_ BOOLEAN NewValue
);

View file

@ -180,11 +180,11 @@ HandlePeriodicGlobalReportQueueQuery(
INT count = 0;
NTSTATUS status = STATUS_SUCCESS;
PVOID report = NULL;
SIZE_T total_size = NULL;
SIZE_T total_size = 0;
PVOID report_buffer = NULL;
ULONG report_buffer_size = 0;
PREPORT_HEADER report_header;
GLOBAL_REPORT_QUEUE_HEADER header;
PREPORT_HEADER report_header = NULL;
GLOBAL_REPORT_QUEUE_HEADER header = { 0 };
KeAcquireGuardedMutex(&report_queue_config.lock);

View file

@ -11,7 +11,7 @@ std::wstring cstr_to_wstr(std::string cstr)
return std::wstring(cstr.begin(), cstr.end());
}
DWORD get_proc_id_by_name(std::string& process_name)
DWORD get_proc_id_by_name(const std::string& process_name)
{
PROCESSENTRY32 entry = { 0 };
entry.dwSize = sizeof(PROCESSENTRY32);

View file

@ -87,7 +87,7 @@ namespace kernelmode
struct DRIVER_INITIATION_INFORMATION
{
LONG protected_process_id;
ULONG protected_process_id;
};
struct HYPERVISOR_DETECTION_REPORT