implement deferred module hashing

This commit is contained in:
lhodges1 2024-02-12 01:34:28 +11:00
parent 22849e498c
commit bef7c8a3b5
13 changed files with 351 additions and 167 deletions

View file

@ -33,32 +33,4 @@ TestINVDEmulation PROC
TestINVDEmulation ENDP
;
; Note: fild and fistp respectively are used for loading and storing integers in the FPU,
; while fld and fstp are used for floating point numbers. No need to use xmm registers
; as we dont need that level of precision and we need to be as efficient as possible
;
; compiler will take care of saving the SSE state for us and restoring it source:
; https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-floating-point-or-mmx-in-a-wdm-driver
;
; arguments: INT64 in RCX
; returns resulting number lol
MySqrt PROC
push rbp
mov rbp, rsp
sub rsp, 16
mov [rsp + 8], rcx ; cannot directly move from a register into a fp register
fild qword ptr[rsp + 8] ; push our number onto the FPU stack
fsqrt ; perform the square root
fistp qword ptr[rsp] ; pop the value from the floating point stack into our general purpose stack
mov rax, qword ptr[rsp] ; store value in rax for return
add rsp, 16
pop rbp
ret
MySqrt ENDP
END

View file

@ -159,6 +159,37 @@ unlock:
ImpKeReleaseGuardedMutex(&list->lock);
}
VOID
EnumerateDriverListWithCallbackRoutine(_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context)
{
PDRIVER_LIST_HEAD list = GetDriverList();
ImpKeAcquireGuardedMutex(&list->lock);
if (!CallbackRoutine)
goto unlock;
PDRIVER_LIST_ENTRY entry = list->start.Next;
while (entry)
{
CallbackRoutine(entry, Context);
entry = entry->list.Next;
}
unlock:
ImpKeReleaseGuardedMutex(&list->lock);
}
VOID
DriverListEntryToExtendedModuleInfo(_In_ PDRIVER_LIST_ENTRY Entry,
_Out_ PRTL_MODULE_EXTENDED_INFO Extended)
{
Extended->ImageBase = Entry->ImageBase;
Extended->ImageSize = Entry->ImageSize;
RtlCopyMemory(Extended->FullPathName, Entry->path, sizeof(Extended->FullPathName));
}
NTSTATUS
InitialiseDriverList()
{
@ -172,6 +203,7 @@ InitialiseDriverList()
InterlockedExchange(&list->active, TRUE);
ListInit(&list->start, &list->lock);
InitializeListHead(&list->deferred_unhashed_x86_modules);
status = GetSystemModuleInformation(&modules);
@ -205,6 +237,9 @@ InitialiseDriverList()
{
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
entry->hashed = FALSE;
entry->x86 = TRUE;
InsertHeadList(&list->deferred_unhashed_x86_modules,
&entry->deferred_entry);
}
else if (!NT_SUCCESS(status))
{
@ -261,6 +296,7 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
RTL_MODULE_EXTENDED_INFO module = {0};
PDRIVER_LIST_HEAD list = GetDriverList();
ANSI_STRING ansi_path = {0};
UINT32 ansi_string_length = 0;
if (InterlockedExchange(&list->active, list->active) == FALSE)
return;
@ -273,8 +309,6 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
if (entry)
return;
DEBUG_VERBOSE("New system image: %wZ", FullImageName);
entry =
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(DRIVER_LIST_ENTRY), POOL_TAG_DRIVER_LIST);
@ -282,26 +316,44 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
return;
entry->hashed = TRUE;
entry->x86 = FALSE;
entry->ImageBase = ImageInfo->ImageBase;
entry->ImageSize = ImageInfo->ImageSize;
/*todo: unicode 2 ansi string -> store in buf */
module.ImageBase = ImageInfo->ImageBase;
module.ImageSize = ImageInfo->ImageSize;
// if (FullImageName)
//{
// status = RtlUnicodeStringToAnsiString(&ansi_path, FullImageName, TRUE);
if (FullImageName)
{
status = RtlUnicodeStringToAnsiString(&ansi_path, FullImageName, TRUE);
// if (!NT_SUCCESS(status))
// DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x", status);
//}
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x", status);
goto hash;
}
if (ansi_path.Length > sizeof(module.FullPathName))
{
RtlFreeAnsiString(&ansi_path);
goto hash;
}
RtlCopyMemory(module.FullPathName, ansi_path.Buffer, ansi_path.Length);
RtlCopyMemory(entry->path, ansi_path.Buffer, ansi_path.Length);
RtlFreeAnsiString(&ansi_path);
}
DEBUG_VERBOSE("New system image ansi: %s", entry->path);
hash:
status = HashModule(&module, &entry->text_hash);
if (status == STATUS_INVALID_IMAGE_WIN_32)
{
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
entry->x86 = TRUE;
entry->hashed = FALSE;
}
else if (!NT_SUCCESS(status))
@ -411,6 +463,23 @@ unlock:
ImpKeReleaseGuardedMutex(&list->lock);
}
VOID
Hashx86ModulesOnWinlogonLoad()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = Allocatex86HashingWorkItem();
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("Allocatex86HashingWorkItem failed with status %x", status);
return status;
}
IoQueueWorkItem(
Getx86HashingWorkItem(), HashDeferredx86ModuleDeferredRoutine, NormalWorkQueue, NULL);
}
VOID
ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create)
{
@ -418,6 +487,7 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
PKPROCESS parent = NULL;
PKPROCESS process = NULL;
PPROCESS_LIST_HEAD list = GetProcessList();
LPCSTR process_name = NULL;
if (!list->active)
return;
@ -428,6 +498,8 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
if (!parent || !process)
return;
process_name = ImpPsGetProcessImageFileName(process);
if (Create)
{
entry = ExAllocateFromLookasideListEx(&list->lookaside_list);
@ -442,6 +514,17 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
entry->process = process;
ListInsert(&list->start, entry, &list->lock);
/*
* Notify to our driver that we can hash x86 modules, and hash any x86 modules that
* werent hashed.
*/
if (!strcmp(process_name, "winlogon.exe"))
{
DEBUG_VERBOSE("Winlogon process has started");
UpdateWinlogonProcessState(TRUE);
Hashx86ModulesOnWinlogonLoad();
}
}
else
{
@ -609,31 +692,31 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
!strcmp(process_creator_name, "explorer.exe"))
goto end;
//POPEN_HANDLE_FAILURE_REPORT report =
// POPEN_HANDLE_FAILURE_REPORT report =
// ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
// sizeof(OPEN_HANDLE_FAILURE_REPORT),
// REPORT_POOL_TAG);
//if (!report)
// if (!report)
// goto end;
//report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
//report->is_kernel_handle = OperationInformation->KernelHandle;
//report->process_id = process_creator_id;
//report->thread_id = ImpPsGetCurrentThreadId();
//report->access =
// report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
// report->is_kernel_handle = OperationInformation->KernelHandle;
// report->process_id = process_creator_id;
// report->thread_id = ImpPsGetCurrentThreadId();
// report->access =
// OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
//RtlCopyMemory(report->process_name,
// RtlCopyMemory(report->process_name,
// process_creator_name,
// HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
//if (!NT_SUCCESS(
// if (!NT_SUCCESS(
// IrpQueueCompleteIrp(report, sizeof(OPEN_HANDLE_FAILURE_REPORT))))
//{
// DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
// goto end;
//}
// }
}
}

View file

@ -21,11 +21,21 @@ typedef struct _DRIVER_LIST_ENTRY
PVOID ImageBase;
ULONG ImageSize;
BOOLEAN hashed;
BOOLEAN x86;
CHAR path[DRIVER_PATH_LENGTH];
CHAR text_hash[SHA_256_HASH_LENGTH];
/*
* This LIST_ENTRY is to be used for modules where the hashing needs to be deferred.
* For example, when x86 modules can't be hashed on driver load.
*/
LIST_ENTRY deferred_entry;
} DRIVER_LIST_ENTRY, *PDRIVER_LIST_ENTRY;
typedef void (*DRIVERLIST_CALLBACK_ROUTINE)(_In_ PDRIVER_LIST_ENTRY DriverListEntry,
_In_opt_ PVOID Context);
NTSTATUS
InitialiseDriverList();
@ -110,4 +120,12 @@ RegisterProcessObCallbacks();
VOID
InitialiseObCallbacksConfiguration(_Out_ PACTIVE_SESSION ProcessConfig);
VOID
EnumerateDriverListWithCallbackRoutine(_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine,
_In_opt_ PVOID Context);
VOID
DriverListEntryToExtendedModuleInfo(_In_ PDRIVER_LIST_ENTRY Entry,
_Out_ PRTL_MODULE_EXTENDED_INFO Extended);
#endif

View file

@ -74,6 +74,7 @@ typedef struct _DRIVER_LIST_HEAD
volatile ULONG count;
volatile BOOLEAN active;
KGUARDED_MUTEX lock;
LIST_ENTRY deferred_unhashed_x86_modules;
} DRIVER_LIST_HEAD, *PDRIVER_LIST_HEAD;
@ -183,21 +184,21 @@ typedef struct _DEFERRED_REPORT
} DEFERRED_REPORT, *PDEFERRED_REPORT;
typedef struct _DEFERRED_REPORTS_HEAD
typedef struct _DEFERRED_REPORTS_LIST
{
LIST_ENTRY head;
UINT32 count;
KGUARDED_MUTEX lock;
KSPIN_LOCK lock;
} DEFERRED_REPORTS_HEAD, *PDEFERRED_REPORTS_HEAD;
} DEFERRED_REPORTS_LIST, *PDEFERRED_REPORTS_LIST;
typedef struct _IRP_QUEUE_HEAD
{
LIST_ENTRY queue;
volatile UINT32 count;
IO_CSQ csq;
KGUARDED_MUTEX lock;
DEFERRED_REPORTS_HEAD reports;
KSPIN_LOCK lock;
DEFERRED_REPORTS_LIST deferred_reports;
} IRP_QUEUE_HEAD, *PIRP_QUEUE_HEAD;

View file

@ -96,6 +96,8 @@ typedef struct _DRIVER_CONFIG
PROCESS_LIST_HEAD process_list;
SHARED_MAPPING mapping;
BOOLEAN has_driver_loaded;
BOOLEAN has_winlogon_started;
PIO_WORKITEM x86_hash_workitem;
} DRIVER_CONFIG, *PDRIVER_CONFIG;
@ -114,6 +116,32 @@ PDRIVER_CONFIG g_DriverConfig = NULL;
#define POOL_TAG_CONFIG 'conf'
PIO_WORKITEM
Getx86HashingWorkItem()
{
return g_DriverConfig->x86_hash_workitem;
}
NTSTATUS
Allocatex86HashingWorkItem()
{
g_DriverConfig->x86_hash_workitem = IoAllocateWorkItem(g_DriverConfig->device_object);
return g_DriverConfig->x86_hash_workitem != NULL ? STATUS_SUCCESS
: STATUS_INSUFFICIENT_RESOURCES;
}
BOOLEAN
HasWinlogonProcessStarted()
{
return g_DriverConfig->has_winlogon_started;
}
VOID
UpdateWinlogonProcessState(_In_ BOOLEAN NewValue)
{
g_DriverConfig->has_winlogon_started = NewValue;
}
BOOLEAN
HasDriverLoaded()
{
@ -887,7 +915,8 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
}
g_DriverConfig->has_driver_loaded = TRUE;
g_DriverConfig->has_winlogon_started = FALSE;
DEBUG_VERBOSE("Driver Entry Complete.");
DEBUG_INFO("Driver Entry Complete.");
return STATUS_SUCCESS;
}

View file

@ -79,4 +79,16 @@ IsNmiInProgress();
BOOLEAN
HasDriverLoaded();
BOOLEAN
HasWinlogonProcessStarted();
VOID
UpdateWinlogonProcessState(_In_ BOOLEAN NewValue);
NTSTATUS
Allocatex86HashingWorkItem();
PIO_WORKITEM
Getx86HashingWorkItem();
#endif

View file

@ -46,7 +46,8 @@ NTSTATUS
StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) PVOID* Buffer,
_In_ PVOID ModuleBase,
_In_ SIZE_T ModuleSize,
_Out_ _Deref_out_range_(>, 0) PSIZE_T BytesWritten);
_Out_ _Deref_out_range_(>, 0) PSIZE_T BytesWritten,
_In_ BOOLEAN IsModulex86);
STATIC
NTSTATUS
@ -77,15 +78,6 @@ STATIC
NTSTATUS
GetAverageReadTimeAtRoutine(_In_ PVOID RoutineAddress, _Out_ PUINT64 AverageTime);
STATIC
NTSTATUS
RegistryPathQueryTestSigningCallback(IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext);
#ifdef ALLOC_PRAGMA
# pragma alloc_text(PAGE, GetDriverImageSize)
# pragma alloc_text(PAGE, GetModuleInformationByName)
@ -102,7 +94,6 @@ RegistryPathQueryTestSigningCallback(IN PWSTR ValueName,
# pragma alloc_text(PAGE, ScanForSignature)
# pragma alloc_text(PAGE, InitiateEptFunctionAddressArrays)
# pragma alloc_text(PAGE, DetectEptHooksInKeyFunctions)
# pragma alloc_text(PAGE, RegistryPathQueryTestSigningCallback)
// #pragma alloc_text(PAGE, DetermineIfTestSigningIsEnabled)
#endif
@ -204,7 +195,8 @@ NTSTATUS
StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) PVOID* Buffer,
_In_ PVOID ModuleBase,
_In_ SIZE_T ModuleSize,
_Out_ _Deref_out_range_(>, 0) PSIZE_T BytesWritten)
_Out_ _Deref_out_range_(>, 0) PSIZE_T BytesWritten,
_In_ BOOLEAN IsModulex86)
{
PAGED_CODE();
@ -244,7 +236,7 @@ StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) P
*/
dos_header = (PIMAGE_DOS_HEADER)ModuleBase;
if (!MmIsAddressValid(dos_header))
if (!MmIsAddressValid(dos_header) && !IsModulex86)
{
ImpExFreePoolWithTag(*Buffer, POOL_TAG_INTEGRITY);
*Buffer = NULL;
@ -433,7 +425,8 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
*HashResult = NULL;
*HashResultSize = 0;
status = BCryptOpenAlgorithmProvider(&algo_handle, BCRYPT_SHA256_ALGORITHM, NULL, NULL);
status = BCryptOpenAlgorithmProvider(
&algo_handle, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_PROV_DISPATCH);
if (!NT_SUCCESS(status))
{
@ -566,7 +559,7 @@ RetrieveInMemoryModuleExecutableSections(_Inout_ PIRP Irp)
}
status = StoreModuleExecutableRegionsInBuffer(
&buffer, module_info.ImageBase, module_info.ImageSize, &bytes_written);
&buffer, module_info.ImageBase, module_info.ImageSize, &bytes_written, FALSE);
if (!NT_SUCCESS(status))
{
@ -897,8 +890,11 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
*/
ImpKeStackAttachProcess(process, &apc_state);
status = StoreModuleExecutableRegionsInBuffer(
&memory_buffer, module_info->module_base, module_info->module_size, &bytes_written);
status = StoreModuleExecutableRegionsInBuffer(&memory_buffer,
module_info->module_base,
module_info->module_size,
&bytes_written,
FALSE);
ImpKeUnstackDetachProcess(&apc_state);
@ -918,7 +914,7 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
}
status = StoreModuleExecutableRegionsInBuffer(
&disk_buffer, section, section_size, &bytes_written);
&disk_buffer, section, section_size, &bytes_written, FALSE);
if (!NT_SUCCESS(status))
{
@ -1405,11 +1401,75 @@ FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
process_name = ImpPsGetProcessImageFileName(Entry->process);
if (!strcmp(process_name, "winlogon.exe"))
{
DEBUG_VERBOSE("32 bit WinLogon.exe process found at address: %llx",
(UINT64)Entry->process);
*process = Entry->process;
}
STATIC
NTSTATUS
StoreModuleExecutableRegionsx86(_In_ PRTL_MODULE_EXTENDED_INFO Module,
_In_ PVOID* Buffer,
_In_ PULONG BufferSize)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS process = NULL;
KAPC_STATE apc_state = {0};
EnumerateProcessListWithCallbackRoutine(FindWinLogonProcess, &process);
if (!process)
return STATUS_NOT_FOUND;
ImpKeStackAttachProcess(process, &apc_state);
status = StoreModuleExecutableRegionsInBuffer(
Buffer, Module->ImageBase, Module->ImageSize, BufferSize, TRUE);
ImpKeUnstackDetachProcess(&apc_state);
if (!NT_SUCCESS(status))
DEBUG_ERROR("StoreModuleExecutableRegionsInBuffer-x86 failed with status %x",
status);
return status;
}
VOID
HashDeferredx86ModuleDeferredRoutine()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
RTL_MODULE_EXTENDED_INFO module = {0};
PLIST_ENTRY deferred_head = &GetDriverList()->deferred_unhashed_x86_modules;
PLIST_ENTRY list_entry = NULL;
PDRIVER_LIST_ENTRY entry = NULL;
list_entry = RemoveHeadList(deferred_head);
if (list_entry == deferred_head)
goto end;
entry = CONTAINING_RECORD(list_entry, DRIVER_LIST_ENTRY, deferred_entry);
while (list_entry != deferred_head)
{
entry = CONTAINING_RECORD(list_entry, DRIVER_LIST_ENTRY, deferred_entry);
DriverListEntryToExtendedModuleInfo(entry, &module);
status = HashModule(&module, &entry->text_hash);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("HashModule-x86 failed with status %x", status);
return;
}
entry->hashed = TRUE;
list_entry = RemoveHeadList(deferred_head);
}
end:
DEBUG_VERBOSE("All deferred x86 modules hashed.");
ImpIoFreeWorkItem(Getx86HashingWorkItem());
}
NTSTATUS
@ -1423,8 +1483,6 @@ HashModule(_In_ PRTL_MODULE_EXTENDED_INFO Module, _Out_ PVOID Hash)
ULONG memory_hash_size = 0;
PVAL_INTEGRITY_HEADER memory_buffer = NULL;
ULONG memory_buffer_size = 0;
PEPROCESS process = NULL;
KAPC_STATE apc_state = {0};
ImpRtlInitAnsiString(&ansi_string, Module->FullPathName);
@ -1448,33 +1506,32 @@ HashModule(_In_ PRTL_MODULE_EXTENDED_INFO Module, _Out_ PVOID Hash)
* 32 bit image base wont be a valid address, while this is hacky it works.
* Then we simply attach to a 32 bit address space, in our case winlogon,
* which will allow us to perform the copy.
*
* Since the driver loads at system startup, our driver is loaded before the WinLogon
* process has started, so to combat this return return early with a status code. This will
* mark the module as not hashed and x86. We will then queue a work item to hash these
* modules later once WinLogon has started.
*/
if (!ImpMmIsAddressValid(Module->ImageBase))
if (!ImpMmIsAddressValid(Module->ImageBase) && !HasWinlogonProcessStarted())
{
// DEBUG_VERBOSE("Win32k related module found, acquiring 32 bit address space...");
// EnumerateProcessListWithCallbackRoutine(FindWinLogonProcess, &process);
// if (!process)
// goto end;
// ImpKeStackAttachProcess(process, &apc_state);
// status = StoreModuleExecutableRegionsInBuffer((PVOID)&memory_buffer,
// Module->ImageBase,
// Module->ImageSize,
// &memory_buffer_size);
// ImpKeUnstackDetachProcess(&apc_state);
status = STATUS_INVALID_IMAGE_WIN_32;
goto end;
}
else if (!ImpMmIsAddressValid(Module->ImageBase) && HasWinlogonProcessStarted())
{
/*
* Once the WinLogon process has started, we can then hash new x86 modules.
*/
status = StoreModuleExecutableRegionsx86(
Module, (PVOID)&memory_buffer, &memory_buffer_size);
}
else
{
status = StoreModuleExecutableRegionsInBuffer((PVOID)&memory_buffer,
Module->ImageBase,
Module->ImageSize,
&memory_buffer_size);
&memory_buffer_size,
FALSE);
}
if (!NT_SUCCESS(status))

View file

@ -119,4 +119,7 @@ ValidateSystemModule(_In_ PRTL_MODULE_EXTENDED_INFO Module);
BOOLEAN
ValidateOurDriversDispatchRoutines();
VOID
HashDeferredx86ModuleDeferredRoutine();
#endif

View file

@ -75,17 +75,20 @@ DispatchApcOperation(_In_ PAPC_OPERATION_ID Operation);
*
* user mode program will automatically queue another irp when an irp completes, ensuring queue has
* a sufficient supply.
*
* note: maybe we should use a spinlock here? Dont really want competing threads sleeping. I think
* spinlock should be used here.
*/
VOID
IrpQueueAcquireLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
{
KeAcquireGuardedMutex(&GetIrpQueueHead()->lock);
KeAcquireSpinLock(&GetIrpQueueHead()->lock, Irql);
}
VOID
IrpQueueReleaseLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
IrpQueueReleaseLock(_In_ PIO_CSQ Csq, _In_ KIRQL Irql)
{
KeReleaseGuardedMutex(&GetIrpQueueHead()->lock);
KeReleaseSpinLock(&GetIrpQueueHead()->lock, Irql);
}
PIRP
@ -111,13 +114,13 @@ IrpQueueRemove(_In_ PIO_CSQ Csq, _In_ PIRP Irp)
BOOLEAN
IrpQueueIsThereDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
{
return Queue->reports.count > 0 ? TRUE : FALSE;
return Queue->deferred_reports.count > 0 ? TRUE : FALSE;
}
PDEFERRED_REPORT
IrpQueueRemoveDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
{
return RemoveHeadList(&Queue->reports.head);
return RemoveHeadList(&Queue->deferred_reports.head);
}
STATIC
@ -150,6 +153,7 @@ IrpQueueQueryPendingReports(_In_ PIRP Irp)
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
PDEFERRED_REPORT report = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
KIRQL irql = 0;
/*
* Important we hold the lock before we call IsThereDeferredReport to prevent the race
@ -157,7 +161,7 @@ IrpQueueQueryPendingReports(_In_ PIRP Irp)
* removes the last entry from the list. We then request a deferred report and will receive
* a null value leading to a bugcheck in the subsequent call to CompleteDeferredReport.
*/
KeAcquireGuardedMutex(&queue->reports.lock);
KeAcquireSpinLock(&GetIrpQueueHead()->deferred_reports.lock, &irql);
if (IrpQueueIsThereDeferredReport(queue))
{
@ -167,16 +171,16 @@ IrpQueueQueryPendingReports(_In_ PIRP Irp)
if (!NT_SUCCESS(status))
{
IrpQueueFreeDeferredReport(report);
KeReleaseGuardedMutex(&queue->reports.lock);
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
return status;
}
queue->reports.count--;
KeReleaseGuardedMutex(&queue->reports.lock);
queue->deferred_reports.count--;
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
return status;
}
KeReleaseGuardedMutex(&queue->reports.lock);
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
return status;
}
@ -216,28 +220,34 @@ IrpQueueAllocateDeferredReport(_In_ PVOID Buffer, _In_ UINT32 BufferSize)
VOID
IrpQueueDeferReport(_In_ PIRP_QUEUE_HEAD Queue, _In_ PVOID Buffer, _In_ UINT32 BufferSize)
{
PDEFERRED_REPORT report = NULL;
KIRQL irql = 0;
/*
* arbitrary number, if we ever do have 100 deferred reports, theres probably a catastrophic
* error somewhere else
*/
if (Queue->reports.count > MAX_DEFERRED_REPORTS_COUNT)
if (Queue->deferred_reports.count > MAX_DEFERRED_REPORTS_COUNT)
{
ImpExFreePoolWithTag(Buffer, REPORT_POOL_TAG);
return;
}
PDEFERRED_REPORT report = IrpQueueAllocateDeferredReport(Buffer, BufferSize);
report = IrpQueueAllocateDeferredReport(Buffer, BufferSize);
if (!report)
return;
KeAcquireGuardedMutex(&Queue->reports.lock);
InsertTailList(&Queue->reports.head, &report->list_entry);
Queue->reports.count++;
KeReleaseGuardedMutex(&Queue->reports.lock);
KeAcquireSpinLock(&GetIrpQueueHead()->deferred_reports.lock, &irql);
InsertTailList(&Queue->deferred_reports.head, &report->list_entry);
Queue->deferred_reports.count++;
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
}
/* takes ownership of the buffer, and regardless of the outcome will free it. */
/*
* takes ownership of the buffer, and regardless of the outcome will free it.
*
* IMPORTANT: All report buffers must be allocated in non paged memory.
*/
NTSTATUS
IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize)
{
@ -284,9 +294,10 @@ IrpQueueFreeDeferredReports()
{
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
PDEFERRED_REPORT report = NULL;
KIRQL irql = 0;
/* just in case... */
KeAcquireGuardedMutex(&queue->reports.lock);
KeAcquireSpinLock(&GetIrpQueueHead()->deferred_reports.lock, &irql);
while (IrpQueueIsThereDeferredReport(queue))
{
@ -294,7 +305,7 @@ IrpQueueFreeDeferredReports()
IrpQueueFreeDeferredReport(report);
}
KeReleaseGuardedMutex(&queue->reports.lock);
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
}
NTSTATUS
@ -303,10 +314,10 @@ IrpQueueInitialise()
NTSTATUS status = STATUS_UNSUCCESSFUL;
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
KeInitializeGuardedMutex(&queue->lock);
KeInitializeGuardedMutex(&queue->reports.lock);
KeInitializeSpinLock(&queue->lock);
KeInitializeSpinLock(&queue->deferred_reports.lock);
InitializeListHead(&queue->queue);
InitializeListHead(&queue->reports.head);
InitializeListHead(&queue->deferred_reports.head);
status = IoCsqInitialize(&queue->csq,
IrpQueueInsert,

View file

@ -684,8 +684,10 @@ HandleValidateDriversIOCTL()
continue;
}
PMODULE_VALIDATION_FAILURE report = ImpExAllocatePool2(
POOL_FLAG_PAGED, sizeof(MODULE_VALIDATION_FAILURE), POOL_TAG_INTEGRITY);
PMODULE_VALIDATION_FAILURE report =
ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(MODULE_VALIDATION_FAILURE),
POOL_TAG_INTEGRITY);
if (!report)
continue;
@ -1236,31 +1238,11 @@ ValidateThreadViaKernelApcCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
PCHAR previous_mode = NULL;
PUCHAR state = NULL;
BOOLEAN apc_queueable = FALSE;
LPCSTR process_name = NULL;
PAPC_STACKWALK_CONTEXT context = (PAPC_STACKWALK_CONTEXT)Context;
LPCSTR process_name = ImpPsGetProcessImageFileName(ThreadListEntry->owning_process);
/*
* 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;
process_name = ImpPsGetProcessImageFileName(ThreadListEntry->owning_process);
/* We are not interested in these processess.. for now lol */
if (!strcmp(process_name, "svchost.exe") || !strcmp(process_name, "Registry") ||
!strcmp(process_name, "smss.exe") || !strcmp(process_name, "csrss.exe") ||
!strcmp(process_name, "explorer.exe") || !strcmp(process_name, "svchost.exe") ||
!strcmp(process_name, "lsass.exe") || !strcmp(process_name, "MemCompression") ||
!strcmp(process_name, "WerFault.exe"))
return;
DEBUG_VERBOSE("Validating thread: %llx, process name: %s via kernel APC stackwalk.",
ThreadListEntry->thread,
process_name);
if (ThreadListEntry->thread == KeGetCurrentThread() || !ThreadListEntry->thread)
return;
/*
* Its possible to set the KThread->ApcQueueable flag to false ensuring that no APCs
* can be queued to the thread, as KeInsertQueueApc will check this flag before
@ -1271,6 +1253,20 @@ ValidateThreadViaKernelApcCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
previous_mode = (PCHAR)((UINT64)ThreadListEntry->thread + KTHREAD_PREVIOUS_MODE_OFFSET);
state = (PUCHAR)((UINT64)ThreadListEntry->thread + KTHREAD_STATE_OFFSET);
/*
* For now, lets only check for system threads. However, we also want to check for threads
* executing in kernel mode, i.e KTHREAD->PreviousMode == UserMode.
*/
if (ThreadListEntry->owning_process != PsInitialSystemProcess)
return;
if (ThreadListEntry->thread == KeGetCurrentThread() || !ThreadListEntry->thread)
return;
DEBUG_VERBOSE("Validating thread: %llx, process name: %s via kernel APC stackwalk.",
ThreadListEntry->thread,
process_name);
/* we dont care about user mode threads */
// if (*previous_mode == UserMode)
// return;

View file

@ -698,7 +698,7 @@ FindUnlinkedProcesses()
allocation);
report_buffer = ImpExAllocatePool2(
POOL_FLAG_PAGED, sizeof(INVALID_PROCESS_ALLOCATION_REPORT), REPORT_POOL_TAG);
POOL_FLAG_NON_PAGED, sizeof(INVALID_PROCESS_ALLOCATION_REPORT), REPORT_POOL_TAG);
if (!report_buffer)
continue;

View file

@ -47,13 +47,15 @@ void dispatcher::dispatcher::run_io_port_thread() {
}
void dispatcher::dispatcher::run() {
helper::generate_rand_seed();
//helper::generate_rand_seed();
std::srand(std::time(nullptr));
this->init_timer_callbacks();
this->run_timer_thread();
this->run_io_port_thread();
thread_pool.queue_job([this]() { k_interface.run_completion_port(); });
while (true) {
this->issue_kernel_job();
//this->issue_kernel_job();
this->k_interface.initiate_apc_stackwalk();
helper::sleep_thread(DISPATCH_LOOP_SLEEP_TIME);
}
}

View file

@ -3,9 +3,9 @@
#include <chrono>
#include <random>
void helper::generate_rand_seed() { srand(time(nullptr)); }
void helper::generate_rand_seed() { srand(time(0)); }
int helper::generate_rand_int(int max) { return rand() % max; }
int helper::generate_rand_int(int max) { return std::rand() % max; }
void helper::sleep_thread(int seconds) {
std::this_thread::sleep_for(std::chrono::seconds(seconds));