mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
implement deferred module hashing
This commit is contained in:
parent
22849e498c
commit
bef7c8a3b5
13 changed files with 351 additions and 167 deletions
|
@ -33,32 +33,4 @@ TestINVDEmulation PROC
|
||||||
|
|
||||||
TestINVDEmulation ENDP
|
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
|
END
|
|
@ -159,6 +159,37 @@ unlock:
|
||||||
ImpKeReleaseGuardedMutex(&list->lock);
|
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
|
NTSTATUS
|
||||||
InitialiseDriverList()
|
InitialiseDriverList()
|
||||||
{
|
{
|
||||||
|
@ -172,6 +203,7 @@ InitialiseDriverList()
|
||||||
|
|
||||||
InterlockedExchange(&list->active, TRUE);
|
InterlockedExchange(&list->active, TRUE);
|
||||||
ListInit(&list->start, &list->lock);
|
ListInit(&list->start, &list->lock);
|
||||||
|
InitializeListHead(&list->deferred_unhashed_x86_modules);
|
||||||
|
|
||||||
status = GetSystemModuleInformation(&modules);
|
status = GetSystemModuleInformation(&modules);
|
||||||
|
|
||||||
|
@ -205,6 +237,9 @@ InitialiseDriverList()
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
|
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
|
||||||
entry->hashed = FALSE;
|
entry->hashed = FALSE;
|
||||||
|
entry->x86 = TRUE;
|
||||||
|
InsertHeadList(&list->deferred_unhashed_x86_modules,
|
||||||
|
&entry->deferred_entry);
|
||||||
}
|
}
|
||||||
else if (!NT_SUCCESS(status))
|
else if (!NT_SUCCESS(status))
|
||||||
{
|
{
|
||||||
|
@ -256,11 +291,12 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
|
||||||
_In_ HANDLE ProcessId,
|
_In_ HANDLE ProcessId,
|
||||||
_In_ PIMAGE_INFO ImageInfo)
|
_In_ PIMAGE_INFO ImageInfo)
|
||||||
{
|
{
|
||||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
PDRIVER_LIST_ENTRY entry = NULL;
|
PDRIVER_LIST_ENTRY entry = NULL;
|
||||||
RTL_MODULE_EXTENDED_INFO module = {0};
|
RTL_MODULE_EXTENDED_INFO module = {0};
|
||||||
PDRIVER_LIST_HEAD list = GetDriverList();
|
PDRIVER_LIST_HEAD list = GetDriverList();
|
||||||
ANSI_STRING ansi_path = {0};
|
ANSI_STRING ansi_path = {0};
|
||||||
|
UINT32 ansi_string_length = 0;
|
||||||
|
|
||||||
if (InterlockedExchange(&list->active, list->active) == FALSE)
|
if (InterlockedExchange(&list->active, list->active) == FALSE)
|
||||||
return;
|
return;
|
||||||
|
@ -273,8 +309,6 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
|
||||||
if (entry)
|
if (entry)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DEBUG_VERBOSE("New system image: %wZ", FullImageName);
|
|
||||||
|
|
||||||
entry =
|
entry =
|
||||||
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(DRIVER_LIST_ENTRY), POOL_TAG_DRIVER_LIST);
|
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(DRIVER_LIST_ENTRY), POOL_TAG_DRIVER_LIST);
|
||||||
|
|
||||||
|
@ -282,26 +316,44 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
entry->hashed = TRUE;
|
entry->hashed = TRUE;
|
||||||
|
entry->x86 = FALSE;
|
||||||
entry->ImageBase = ImageInfo->ImageBase;
|
entry->ImageBase = ImageInfo->ImageBase;
|
||||||
entry->ImageSize = ImageInfo->ImageSize;
|
entry->ImageSize = ImageInfo->ImageSize;
|
||||||
|
|
||||||
/*todo: unicode 2 ansi string -> store in buf */
|
|
||||||
module.ImageBase = ImageInfo->ImageBase;
|
module.ImageBase = ImageInfo->ImageBase;
|
||||||
module.ImageSize = ImageInfo->ImageSize;
|
module.ImageSize = ImageInfo->ImageSize;
|
||||||
|
|
||||||
// if (FullImageName)
|
if (FullImageName)
|
||||||
//{
|
{
|
||||||
// status = RtlUnicodeStringToAnsiString(&ansi_path, FullImageName, TRUE);
|
status = RtlUnicodeStringToAnsiString(&ansi_path, FullImageName, TRUE);
|
||||||
|
|
||||||
// if (!NT_SUCCESS(status))
|
if (!NT_SUCCESS(status))
|
||||||
// DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x", 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);
|
status = HashModule(&module, &entry->text_hash);
|
||||||
|
|
||||||
if (status == STATUS_INVALID_IMAGE_WIN_32)
|
if (status == STATUS_INVALID_IMAGE_WIN_32)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
|
DEBUG_ERROR("32 bit module not hashed, will hash later. %x", status);
|
||||||
|
entry->x86 = TRUE;
|
||||||
entry->hashed = FALSE;
|
entry->hashed = FALSE;
|
||||||
}
|
}
|
||||||
else if (!NT_SUCCESS(status))
|
else if (!NT_SUCCESS(status))
|
||||||
|
@ -411,13 +463,31 @@ unlock:
|
||||||
ImpKeReleaseGuardedMutex(&list->lock);
|
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
|
VOID
|
||||||
ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create)
|
ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create)
|
||||||
{
|
{
|
||||||
PPROCESS_LIST_ENTRY entry = NULL;
|
PPROCESS_LIST_ENTRY entry = NULL;
|
||||||
PKPROCESS parent = NULL;
|
PKPROCESS parent = NULL;
|
||||||
PKPROCESS process = NULL;
|
PKPROCESS process = NULL;
|
||||||
PPROCESS_LIST_HEAD list = GetProcessList();
|
PPROCESS_LIST_HEAD list = GetProcessList();
|
||||||
|
LPCSTR process_name = NULL;
|
||||||
|
|
||||||
if (!list->active)
|
if (!list->active)
|
||||||
return;
|
return;
|
||||||
|
@ -428,6 +498,8 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
|
||||||
if (!parent || !process)
|
if (!parent || !process)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
process_name = ImpPsGetProcessImageFileName(process);
|
||||||
|
|
||||||
if (Create)
|
if (Create)
|
||||||
{
|
{
|
||||||
entry = ExAllocateFromLookasideListEx(&list->lookaside_list);
|
entry = ExAllocateFromLookasideListEx(&list->lookaside_list);
|
||||||
|
@ -442,6 +514,17 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOO
|
||||||
entry->process = process;
|
entry->process = process;
|
||||||
|
|
||||||
ListInsert(&list->start, entry, &list->lock);
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -609,31 +692,31 @@ ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
|
||||||
!strcmp(process_creator_name, "explorer.exe"))
|
!strcmp(process_creator_name, "explorer.exe"))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
//POPEN_HANDLE_FAILURE_REPORT report =
|
// POPEN_HANDLE_FAILURE_REPORT report =
|
||||||
// ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
|
// ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
|
||||||
// sizeof(OPEN_HANDLE_FAILURE_REPORT),
|
// sizeof(OPEN_HANDLE_FAILURE_REPORT),
|
||||||
// REPORT_POOL_TAG);
|
// REPORT_POOL_TAG);
|
||||||
|
|
||||||
//if (!report)
|
// if (!report)
|
||||||
// goto end;
|
// goto end;
|
||||||
|
|
||||||
//report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
|
// report->report_code = REPORT_ILLEGAL_HANDLE_OPERATION;
|
||||||
//report->is_kernel_handle = OperationInformation->KernelHandle;
|
// report->is_kernel_handle = OperationInformation->KernelHandle;
|
||||||
//report->process_id = process_creator_id;
|
// report->process_id = process_creator_id;
|
||||||
//report->thread_id = ImpPsGetCurrentThreadId();
|
// report->thread_id = ImpPsGetCurrentThreadId();
|
||||||
//report->access =
|
// report->access =
|
||||||
// OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
|
// OperationInformation->Parameters->CreateHandleInformation.DesiredAccess;
|
||||||
|
|
||||||
//RtlCopyMemory(report->process_name,
|
// RtlCopyMemory(report->process_name,
|
||||||
// process_creator_name,
|
// process_creator_name,
|
||||||
// HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
|
// HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
|
||||||
|
|
||||||
//if (!NT_SUCCESS(
|
// if (!NT_SUCCESS(
|
||||||
// IrpQueueCompleteIrp(report, sizeof(OPEN_HANDLE_FAILURE_REPORT))))
|
// IrpQueueCompleteIrp(report, sizeof(OPEN_HANDLE_FAILURE_REPORT))))
|
||||||
//{
|
//{
|
||||||
// DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
|
// DEBUG_ERROR("IrpQueueCompleteIrp failed with no status.");
|
||||||
// goto end;
|
// goto end;
|
||||||
//}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,21 @@ typedef struct _DRIVER_LIST_ENTRY
|
||||||
PVOID ImageBase;
|
PVOID ImageBase;
|
||||||
ULONG ImageSize;
|
ULONG ImageSize;
|
||||||
BOOLEAN hashed;
|
BOOLEAN hashed;
|
||||||
|
BOOLEAN x86;
|
||||||
CHAR path[DRIVER_PATH_LENGTH];
|
CHAR path[DRIVER_PATH_LENGTH];
|
||||||
CHAR text_hash[SHA_256_HASH_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;
|
} DRIVER_LIST_ENTRY, *PDRIVER_LIST_ENTRY;
|
||||||
|
|
||||||
|
typedef void (*DRIVERLIST_CALLBACK_ROUTINE)(_In_ PDRIVER_LIST_ENTRY DriverListEntry,
|
||||||
|
_In_opt_ PVOID Context);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
InitialiseDriverList();
|
InitialiseDriverList();
|
||||||
|
|
||||||
|
@ -70,7 +80,7 @@ EnumerateThreadListWithCallbackRoutine(_In_ THREADLIST_CALLBACK_ROUTINE Callback
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
EnumerateProcessListWithCallbackRoutine(_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine,
|
EnumerateProcessListWithCallbackRoutine(_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine,
|
||||||
_In_opt_ PVOID Context);
|
_In_opt_ PVOID Context);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
FindDriverEntryByBaseAddress(_In_ PVOID ImageBase, _Out_ PDRIVER_LIST_ENTRY* Entry);
|
FindDriverEntryByBaseAddress(_In_ PVOID ImageBase, _Out_ PDRIVER_LIST_ENTRY* Entry);
|
||||||
|
@ -110,4 +120,12 @@ RegisterProcessObCallbacks();
|
||||||
VOID
|
VOID
|
||||||
InitialiseObCallbacksConfiguration(_Out_ PACTIVE_SESSION ProcessConfig);
|
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
|
#endif
|
||||||
|
|
|
@ -74,6 +74,7 @@ typedef struct _DRIVER_LIST_HEAD
|
||||||
volatile ULONG count;
|
volatile ULONG count;
|
||||||
volatile BOOLEAN active;
|
volatile BOOLEAN active;
|
||||||
KGUARDED_MUTEX lock;
|
KGUARDED_MUTEX lock;
|
||||||
|
LIST_ENTRY deferred_unhashed_x86_modules;
|
||||||
|
|
||||||
} DRIVER_LIST_HEAD, *PDRIVER_LIST_HEAD;
|
} DRIVER_LIST_HEAD, *PDRIVER_LIST_HEAD;
|
||||||
|
|
||||||
|
@ -183,21 +184,21 @@ typedef struct _DEFERRED_REPORT
|
||||||
|
|
||||||
} DEFERRED_REPORT, *PDEFERRED_REPORT;
|
} DEFERRED_REPORT, *PDEFERRED_REPORT;
|
||||||
|
|
||||||
typedef struct _DEFERRED_REPORTS_HEAD
|
typedef struct _DEFERRED_REPORTS_LIST
|
||||||
{
|
{
|
||||||
LIST_ENTRY head;
|
LIST_ENTRY head;
|
||||||
UINT32 count;
|
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
|
typedef struct _IRP_QUEUE_HEAD
|
||||||
{
|
{
|
||||||
LIST_ENTRY queue;
|
LIST_ENTRY queue;
|
||||||
volatile UINT32 count;
|
volatile UINT32 count;
|
||||||
IO_CSQ csq;
|
IO_CSQ csq;
|
||||||
KGUARDED_MUTEX lock;
|
KSPIN_LOCK lock;
|
||||||
DEFERRED_REPORTS_HEAD reports;
|
DEFERRED_REPORTS_LIST deferred_reports;
|
||||||
|
|
||||||
} IRP_QUEUE_HEAD, *PIRP_QUEUE_HEAD;
|
} IRP_QUEUE_HEAD, *PIRP_QUEUE_HEAD;
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,8 @@ typedef struct _DRIVER_CONFIG
|
||||||
PROCESS_LIST_HEAD process_list;
|
PROCESS_LIST_HEAD process_list;
|
||||||
SHARED_MAPPING mapping;
|
SHARED_MAPPING mapping;
|
||||||
BOOLEAN has_driver_loaded;
|
BOOLEAN has_driver_loaded;
|
||||||
|
BOOLEAN has_winlogon_started;
|
||||||
|
PIO_WORKITEM x86_hash_workitem;
|
||||||
|
|
||||||
} DRIVER_CONFIG, *PDRIVER_CONFIG;
|
} DRIVER_CONFIG, *PDRIVER_CONFIG;
|
||||||
|
|
||||||
|
@ -114,6 +116,32 @@ PDRIVER_CONFIG g_DriverConfig = NULL;
|
||||||
|
|
||||||
#define POOL_TAG_CONFIG 'conf'
|
#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
|
BOOLEAN
|
||||||
HasDriverLoaded()
|
HasDriverLoaded()
|
||||||
{
|
{
|
||||||
|
@ -886,8 +914,9 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_DriverConfig->has_driver_loaded = TRUE;
|
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;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,4 +79,16 @@ IsNmiInProgress();
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
HasDriverLoaded();
|
HasDriverLoaded();
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
HasWinlogonProcessStarted();
|
||||||
|
|
||||||
|
VOID
|
||||||
|
UpdateWinlogonProcessState(_In_ BOOLEAN NewValue);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
Allocatex86HashingWorkItem();
|
||||||
|
|
||||||
|
PIO_WORKITEM
|
||||||
|
Getx86HashingWorkItem();
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -46,7 +46,8 @@ NTSTATUS
|
||||||
StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) PVOID* Buffer,
|
StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) PVOID* Buffer,
|
||||||
_In_ PVOID ModuleBase,
|
_In_ PVOID ModuleBase,
|
||||||
_In_ SIZE_T ModuleSize,
|
_In_ SIZE_T ModuleSize,
|
||||||
_Out_ _Deref_out_range_(>, 0) PSIZE_T BytesWritten);
|
_Out_ _Deref_out_range_(>, 0) PSIZE_T BytesWritten,
|
||||||
|
_In_ BOOLEAN IsModulex86);
|
||||||
|
|
||||||
STATIC
|
STATIC
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
@ -77,15 +78,6 @@ STATIC
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
GetAverageReadTimeAtRoutine(_In_ PVOID RoutineAddress, _Out_ PUINT64 AverageTime);
|
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
|
#ifdef ALLOC_PRAGMA
|
||||||
# pragma alloc_text(PAGE, GetDriverImageSize)
|
# pragma alloc_text(PAGE, GetDriverImageSize)
|
||||||
# pragma alloc_text(PAGE, GetModuleInformationByName)
|
# pragma alloc_text(PAGE, GetModuleInformationByName)
|
||||||
|
@ -102,7 +94,6 @@ RegistryPathQueryTestSigningCallback(IN PWSTR ValueName,
|
||||||
# pragma alloc_text(PAGE, ScanForSignature)
|
# pragma alloc_text(PAGE, ScanForSignature)
|
||||||
# pragma alloc_text(PAGE, InitiateEptFunctionAddressArrays)
|
# pragma alloc_text(PAGE, InitiateEptFunctionAddressArrays)
|
||||||
# pragma alloc_text(PAGE, DetectEptHooksInKeyFunctions)
|
# pragma alloc_text(PAGE, DetectEptHooksInKeyFunctions)
|
||||||
# pragma alloc_text(PAGE, RegistryPathQueryTestSigningCallback)
|
|
||||||
// #pragma alloc_text(PAGE, DetermineIfTestSigningIsEnabled)
|
// #pragma alloc_text(PAGE, DetermineIfTestSigningIsEnabled)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -204,7 +195,8 @@ NTSTATUS
|
||||||
StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) PVOID* Buffer,
|
StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) PVOID* Buffer,
|
||||||
_In_ PVOID ModuleBase,
|
_In_ PVOID ModuleBase,
|
||||||
_In_ SIZE_T ModuleSize,
|
_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();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
@ -244,7 +236,7 @@ StoreModuleExecutableRegionsInBuffer(_Outptr_result_bytebuffer_(*BytesWritten) P
|
||||||
*/
|
*/
|
||||||
dos_header = (PIMAGE_DOS_HEADER)ModuleBase;
|
dos_header = (PIMAGE_DOS_HEADER)ModuleBase;
|
||||||
|
|
||||||
if (!MmIsAddressValid(dos_header))
|
if (!MmIsAddressValid(dos_header) && !IsModulex86)
|
||||||
{
|
{
|
||||||
ImpExFreePoolWithTag(*Buffer, POOL_TAG_INTEGRITY);
|
ImpExFreePoolWithTag(*Buffer, POOL_TAG_INTEGRITY);
|
||||||
*Buffer = NULL;
|
*Buffer = NULL;
|
||||||
|
@ -433,7 +425,8 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
|
||||||
*HashResult = NULL;
|
*HashResult = NULL;
|
||||||
*HashResultSize = 0;
|
*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))
|
if (!NT_SUCCESS(status))
|
||||||
{
|
{
|
||||||
|
@ -566,7 +559,7 @@ RetrieveInMemoryModuleExecutableSections(_Inout_ PIRP Irp)
|
||||||
}
|
}
|
||||||
|
|
||||||
status = StoreModuleExecutableRegionsInBuffer(
|
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))
|
if (!NT_SUCCESS(status))
|
||||||
{
|
{
|
||||||
|
@ -897,8 +890,11 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
|
||||||
*/
|
*/
|
||||||
ImpKeStackAttachProcess(process, &apc_state);
|
ImpKeStackAttachProcess(process, &apc_state);
|
||||||
|
|
||||||
status = StoreModuleExecutableRegionsInBuffer(
|
status = StoreModuleExecutableRegionsInBuffer(&memory_buffer,
|
||||||
&memory_buffer, module_info->module_base, module_info->module_size, &bytes_written);
|
module_info->module_base,
|
||||||
|
module_info->module_size,
|
||||||
|
&bytes_written,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
ImpKeUnstackDetachProcess(&apc_state);
|
ImpKeUnstackDetachProcess(&apc_state);
|
||||||
|
|
||||||
|
@ -918,7 +914,7 @@ ValidateProcessLoadedModule(_Inout_ PIRP Irp)
|
||||||
}
|
}
|
||||||
|
|
||||||
status = StoreModuleExecutableRegionsInBuffer(
|
status = StoreModuleExecutableRegionsInBuffer(
|
||||||
&disk_buffer, section, section_size, &bytes_written);
|
&disk_buffer, section, section_size, &bytes_written, FALSE);
|
||||||
|
|
||||||
if (!NT_SUCCESS(status))
|
if (!NT_SUCCESS(status))
|
||||||
{
|
{
|
||||||
|
@ -1405,11 +1401,75 @@ FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
|
||||||
process_name = ImpPsGetProcessImageFileName(Entry->process);
|
process_name = ImpPsGetProcessImageFileName(Entry->process);
|
||||||
|
|
||||||
if (!strcmp(process_name, "winlogon.exe"))
|
if (!strcmp(process_name, "winlogon.exe"))
|
||||||
{
|
|
||||||
DEBUG_VERBOSE("32 bit WinLogon.exe process found at address: %llx",
|
|
||||||
(UINT64)Entry->process);
|
|
||||||
*process = 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
|
NTSTATUS
|
||||||
|
@ -1423,8 +1483,6 @@ HashModule(_In_ PRTL_MODULE_EXTENDED_INFO Module, _Out_ PVOID Hash)
|
||||||
ULONG memory_hash_size = 0;
|
ULONG memory_hash_size = 0;
|
||||||
PVAL_INTEGRITY_HEADER memory_buffer = NULL;
|
PVAL_INTEGRITY_HEADER memory_buffer = NULL;
|
||||||
ULONG memory_buffer_size = 0;
|
ULONG memory_buffer_size = 0;
|
||||||
PEPROCESS process = NULL;
|
|
||||||
KAPC_STATE apc_state = {0};
|
|
||||||
|
|
||||||
ImpRtlInitAnsiString(&ansi_string, Module->FullPathName);
|
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.
|
* 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,
|
* Then we simply attach to a 32 bit address space, in our case winlogon,
|
||||||
* which will allow us to perform the copy.
|
* 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;
|
status = STATUS_INVALID_IMAGE_WIN_32;
|
||||||
goto end;
|
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
|
else
|
||||||
{
|
{
|
||||||
status = StoreModuleExecutableRegionsInBuffer((PVOID)&memory_buffer,
|
status = StoreModuleExecutableRegionsInBuffer((PVOID)&memory_buffer,
|
||||||
Module->ImageBase,
|
Module->ImageBase,
|
||||||
Module->ImageSize,
|
Module->ImageSize,
|
||||||
&memory_buffer_size);
|
&memory_buffer_size,
|
||||||
|
FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NT_SUCCESS(status))
|
if (!NT_SUCCESS(status))
|
||||||
|
|
|
@ -119,4 +119,7 @@ ValidateSystemModule(_In_ PRTL_MODULE_EXTENDED_INFO Module);
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
ValidateOurDriversDispatchRoutines();
|
ValidateOurDriversDispatchRoutines();
|
||||||
|
|
||||||
|
VOID
|
||||||
|
HashDeferredx86ModuleDeferredRoutine();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
55
driver/io.c
55
driver/io.c
|
@ -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
|
* user mode program will automatically queue another irp when an irp completes, ensuring queue has
|
||||||
* a sufficient supply.
|
* 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
|
VOID
|
||||||
IrpQueueAcquireLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
|
IrpQueueAcquireLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
|
||||||
{
|
{
|
||||||
KeAcquireGuardedMutex(&GetIrpQueueHead()->lock);
|
KeAcquireSpinLock(&GetIrpQueueHead()->lock, Irql);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
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
|
PIRP
|
||||||
|
@ -111,13 +114,13 @@ IrpQueueRemove(_In_ PIO_CSQ Csq, _In_ PIRP Irp)
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
IrpQueueIsThereDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
|
IrpQueueIsThereDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
|
||||||
{
|
{
|
||||||
return Queue->reports.count > 0 ? TRUE : FALSE;
|
return Queue->deferred_reports.count > 0 ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDEFERRED_REPORT
|
PDEFERRED_REPORT
|
||||||
IrpQueueRemoveDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
|
IrpQueueRemoveDeferredReport(_In_ PIRP_QUEUE_HEAD Queue)
|
||||||
{
|
{
|
||||||
return RemoveHeadList(&Queue->reports.head);
|
return RemoveHeadList(&Queue->deferred_reports.head);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC
|
STATIC
|
||||||
|
@ -150,6 +153,7 @@ IrpQueueQueryPendingReports(_In_ PIRP Irp)
|
||||||
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
|
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
|
||||||
PDEFERRED_REPORT report = NULL;
|
PDEFERRED_REPORT report = NULL;
|
||||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
|
KIRQL irql = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Important we hold the lock before we call IsThereDeferredReport to prevent the race
|
* 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
|
* 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.
|
* 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))
|
if (IrpQueueIsThereDeferredReport(queue))
|
||||||
{
|
{
|
||||||
|
@ -167,16 +171,16 @@ IrpQueueQueryPendingReports(_In_ PIRP Irp)
|
||||||
if (!NT_SUCCESS(status))
|
if (!NT_SUCCESS(status))
|
||||||
{
|
{
|
||||||
IrpQueueFreeDeferredReport(report);
|
IrpQueueFreeDeferredReport(report);
|
||||||
KeReleaseGuardedMutex(&queue->reports.lock);
|
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue->reports.count--;
|
queue->deferred_reports.count--;
|
||||||
KeReleaseGuardedMutex(&queue->reports.lock);
|
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeReleaseGuardedMutex(&queue->reports.lock);
|
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,28 +220,34 @@ IrpQueueAllocateDeferredReport(_In_ PVOID Buffer, _In_ UINT32 BufferSize)
|
||||||
VOID
|
VOID
|
||||||
IrpQueueDeferReport(_In_ PIRP_QUEUE_HEAD Queue, _In_ PVOID Buffer, _In_ UINT32 BufferSize)
|
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
|
* arbitrary number, if we ever do have 100 deferred reports, theres probably a catastrophic
|
||||||
* error somewhere else
|
* 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);
|
ImpExFreePoolWithTag(Buffer, REPORT_POOL_TAG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDEFERRED_REPORT report = IrpQueueAllocateDeferredReport(Buffer, BufferSize);
|
report = IrpQueueAllocateDeferredReport(Buffer, BufferSize);
|
||||||
|
|
||||||
if (!report)
|
if (!report)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
KeAcquireGuardedMutex(&Queue->reports.lock);
|
KeAcquireSpinLock(&GetIrpQueueHead()->deferred_reports.lock, &irql);
|
||||||
InsertTailList(&Queue->reports.head, &report->list_entry);
|
InsertTailList(&Queue->deferred_reports.head, &report->list_entry);
|
||||||
Queue->reports.count++;
|
Queue->deferred_reports.count++;
|
||||||
KeReleaseGuardedMutex(&Queue->reports.lock);
|
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
|
NTSTATUS
|
||||||
IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize)
|
IrpQueueCompleteIrp(_In_ PVOID Buffer, _In_ ULONG BufferSize)
|
||||||
{
|
{
|
||||||
|
@ -284,9 +294,10 @@ IrpQueueFreeDeferredReports()
|
||||||
{
|
{
|
||||||
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
|
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
|
||||||
PDEFERRED_REPORT report = NULL;
|
PDEFERRED_REPORT report = NULL;
|
||||||
|
KIRQL irql = 0;
|
||||||
|
|
||||||
/* just in case... */
|
/* just in case... */
|
||||||
KeAcquireGuardedMutex(&queue->reports.lock);
|
KeAcquireSpinLock(&GetIrpQueueHead()->deferred_reports.lock, &irql);
|
||||||
|
|
||||||
while (IrpQueueIsThereDeferredReport(queue))
|
while (IrpQueueIsThereDeferredReport(queue))
|
||||||
{
|
{
|
||||||
|
@ -294,7 +305,7 @@ IrpQueueFreeDeferredReports()
|
||||||
IrpQueueFreeDeferredReport(report);
|
IrpQueueFreeDeferredReport(report);
|
||||||
}
|
}
|
||||||
|
|
||||||
KeReleaseGuardedMutex(&queue->reports.lock);
|
KeReleaseSpinLock(&GetIrpQueueHead()->deferred_reports.lock, irql);
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
@ -303,10 +314,10 @@ IrpQueueInitialise()
|
||||||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||||||
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
|
PIRP_QUEUE_HEAD queue = GetIrpQueueHead();
|
||||||
|
|
||||||
KeInitializeGuardedMutex(&queue->lock);
|
KeInitializeSpinLock(&queue->lock);
|
||||||
KeInitializeGuardedMutex(&queue->reports.lock);
|
KeInitializeSpinLock(&queue->deferred_reports.lock);
|
||||||
InitializeListHead(&queue->queue);
|
InitializeListHead(&queue->queue);
|
||||||
InitializeListHead(&queue->reports.head);
|
InitializeListHead(&queue->deferred_reports.head);
|
||||||
|
|
||||||
status = IoCsqInitialize(&queue->csq,
|
status = IoCsqInitialize(&queue->csq,
|
||||||
IrpQueueInsert,
|
IrpQueueInsert,
|
||||||
|
|
|
@ -684,8 +684,10 @@ HandleValidateDriversIOCTL()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
PMODULE_VALIDATION_FAILURE report = ImpExAllocatePool2(
|
PMODULE_VALIDATION_FAILURE report =
|
||||||
POOL_FLAG_PAGED, sizeof(MODULE_VALIDATION_FAILURE), POOL_TAG_INTEGRITY);
|
ImpExAllocatePool2(POOL_FLAG_NON_PAGED,
|
||||||
|
sizeof(MODULE_VALIDATION_FAILURE),
|
||||||
|
POOL_TAG_INTEGRITY);
|
||||||
|
|
||||||
if (!report)
|
if (!report)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1236,31 +1238,11 @@ ValidateThreadViaKernelApcCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
||||||
PCHAR previous_mode = NULL;
|
PCHAR previous_mode = NULL;
|
||||||
PUCHAR state = NULL;
|
PUCHAR state = NULL;
|
||||||
BOOLEAN apc_queueable = FALSE;
|
BOOLEAN apc_queueable = FALSE;
|
||||||
|
LPCSTR process_name = NULL;
|
||||||
PAPC_STACKWALK_CONTEXT context = (PAPC_STACKWALK_CONTEXT)Context;
|
PAPC_STACKWALK_CONTEXT context = (PAPC_STACKWALK_CONTEXT)Context;
|
||||||
LPCSTR process_name = ImpPsGetProcessImageFileName(ThreadListEntry->owning_process);
|
|
||||||
|
|
||||||
/*
|
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;
|
|
||||||
|
|
||||||
/* 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
|
* 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
|
* 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);
|
previous_mode = (PCHAR)((UINT64)ThreadListEntry->thread + KTHREAD_PREVIOUS_MODE_OFFSET);
|
||||||
state = (PUCHAR)((UINT64)ThreadListEntry->thread + KTHREAD_STATE_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 */
|
/* we dont care about user mode threads */
|
||||||
// if (*previous_mode == UserMode)
|
// if (*previous_mode == UserMode)
|
||||||
// return;
|
// return;
|
||||||
|
|
|
@ -698,7 +698,7 @@ FindUnlinkedProcesses()
|
||||||
allocation);
|
allocation);
|
||||||
|
|
||||||
report_buffer = ImpExAllocatePool2(
|
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)
|
if (!report_buffer)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -47,13 +47,15 @@ void dispatcher::dispatcher::run_io_port_thread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatcher::dispatcher::run() {
|
void dispatcher::dispatcher::run() {
|
||||||
helper::generate_rand_seed();
|
//helper::generate_rand_seed();
|
||||||
|
std::srand(std::time(nullptr));
|
||||||
this->init_timer_callbacks();
|
this->init_timer_callbacks();
|
||||||
this->run_timer_thread();
|
this->run_timer_thread();
|
||||||
this->run_io_port_thread();
|
this->run_io_port_thread();
|
||||||
thread_pool.queue_job([this]() { k_interface.run_completion_port(); });
|
thread_pool.queue_job([this]() { k_interface.run_completion_port(); });
|
||||||
while (true) {
|
while (true) {
|
||||||
this->issue_kernel_job();
|
//this->issue_kernel_job();
|
||||||
|
this->k_interface.initiate_apc_stackwalk();
|
||||||
helper::sleep_thread(DISPATCH_LOOP_SLEEP_TIME);
|
helper::sleep_thread(DISPATCH_LOOP_SLEEP_TIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <random>
|
#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) {
|
void helper::sleep_thread(int seconds) {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(seconds));
|
std::this_thread::sleep_for(std::chrono::seconds(seconds));
|
||||||
|
|
Loading…
Reference in a new issue