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
|
||||
|
||||
|
||||
;
|
||||
; 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
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -79,4 +79,16 @@ IsNmiInProgress();
|
|||
BOOLEAN
|
||||
HasDriverLoaded();
|
||||
|
||||
BOOLEAN
|
||||
HasWinlogonProcessStarted();
|
||||
|
||||
VOID
|
||||
UpdateWinlogonProcessState(_In_ BOOLEAN NewValue);
|
||||
|
||||
NTSTATUS
|
||||
Allocatex86HashingWorkItem();
|
||||
|
||||
PIO_WORKITEM
|
||||
Getx86HashingWorkItem();
|
||||
|
||||
#endif
|
|
@ -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))
|
||||
|
|
|
@ -119,4 +119,7 @@ ValidateSystemModule(_In_ PRTL_MODULE_EXTENDED_INFO Module);
|
|||
BOOLEAN
|
||||
ValidateOurDriversDispatchRoutines();
|
||||
|
||||
VOID
|
||||
HashDeferredx86ModuleDeferredRoutine();
|
||||
|
||||
#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
|
||||
* 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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue