internal refactoring (#14)

- Refactor process list. New implementation consists of a hashmap. Each process entry then contains the associated user modules.
- Implement user module integrity checks on timer callback
This commit is contained in:
donnaskiez 2024-06-09 17:22:22 +10:00 committed by GitHub
parent cdd7b09ea0
commit ea2278e7b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 1276 additions and 333 deletions

View file

@ -10,6 +10,10 @@
#include "list.h" #include "list.h"
#include "session.h" #include "session.h"
#include "crypt.h" #include "crypt.h"
#include "map.h"
#include "util.h"
#define PROCESS_HASHMAP_BUCKET_COUNT 101
STATIC STATIC
BOOLEAN BOOLEAN
@ -27,17 +31,6 @@ EnumHandleCallback(_In_ PHANDLE_TABLE HandleTable,
# pragma alloc_text(PAGE, ExUnlockHandleTableEntry) # pragma alloc_text(PAGE, ExUnlockHandleTableEntry)
#endif #endif
/*
* Its important on unload we dereference any objects to ensure the kernels
* reference count remains correct.
*/
VOID
CleanupProcessListFreeCallback(_In_ PPROCESS_LIST_ENTRY ProcessListEntry)
{
ImpObDereferenceObject(ProcessListEntry->parent);
ImpObDereferenceObject(ProcessListEntry->process);
}
VOID VOID
CleanupThreadListFreeCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry) CleanupThreadListFreeCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry)
{ {
@ -48,8 +41,8 @@ CleanupThreadListFreeCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry)
VOID VOID
UnregisterProcessCreateNotifyRoutine() UnregisterProcessCreateNotifyRoutine()
{ {
PPROCESS_LIST_HEAD list = GetProcessList(); PRTL_HASHMAP map = GetProcessHashmap();
InterlockedExchange(&list->active, FALSE); InterlockedExchange(&map->active, FALSE);
ImpPsSetCreateProcessNotifyRoutine(ProcessCreateNotifyRoutine, TRUE); ImpPsSetCreateProcessNotifyRoutine(ProcessCreateNotifyRoutine, TRUE);
} }
@ -69,24 +62,6 @@ UnregisterThreadCreateNotifyRoutine()
ImpPsRemoveCreateThreadNotifyRoutine(ThreadCreateNotifyRoutine); ImpPsRemoveCreateThreadNotifyRoutine(ThreadCreateNotifyRoutine);
} }
/*
* While ExDeleteLookasideListEx already frees each item, we wanna allow
* ourselves to reduce the reference count to any objects we are referencing.
*/
VOID
CleanupProcessListOnDriverUnload()
{
PPROCESS_LIST_HEAD list = GetProcessList();
DEBUG_VERBOSE("Freeing process list");
for (;;) {
if (!LookasideListFreeFirstEntry(
&list->start, &list->lock, CleanupProcessListFreeCallback)) {
ExDeleteLookasideListEx(&list->lookaside_list);
return;
}
}
}
VOID VOID
CleanupThreadListOnDriverUnload() CleanupThreadListOnDriverUnload()
{ {
@ -132,27 +107,6 @@ unlock:
ImpKeReleaseGuardedMutex(&list->lock); ImpKeReleaseGuardedMutex(&list->lock);
} }
VOID
EnumerateProcessListWithCallbackRoutine(
_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context)
{
PPROCESS_LIST_HEAD list = GetProcessList();
ImpKeAcquireGuardedMutex(&list->lock);
if (!CallbackRoutine)
goto unlock;
PPROCESS_LIST_ENTRY entry = list->start.Next;
while (entry) {
CallbackRoutine(entry, Context);
entry = (PPROCESS_LIST_ENTRY)entry->list.Next;
}
unlock:
ImpKeReleaseGuardedMutex(&list->lock);
}
VOID VOID
EnumerateDriverListWithCallbackRoutine( EnumerateDriverListWithCallbackRoutine(
_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context) _In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context)
@ -283,6 +237,79 @@ unlock:
ImpKeReleaseGuardedMutex(&list->lock); ImpKeReleaseGuardedMutex(&list->lock);
} }
STATIC
BOOLEAN
ProcessHashmapCompareFunction(_In_ PVOID Struct1, _In_ PVOID Struct2)
{
HANDLE h1 = *((PHANDLE)Struct1);
HANDLE h2 = *((PHANDLE)Struct2);
return h1 == h2 ? TRUE : FALSE;
}
STATIC
UINT32
ProcessHashmapHashFunction(_In_ UINT64 Key)
{
return ((UINT32)Key) % PROCESS_HASHMAP_BUCKET_COUNT;
}
STATIC
VOID
ImageLoadInsertNonSystemImageIntoProcessHashmap(_In_ PIMAGE_INFO ImageInfo,
_In_ HANDLE ProcessId,
_In_opt_ PUNICODE_STRING
FullImageName)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS process = NULL;
PRTL_HASHMAP map = GetProcessHashmap();
PPROCESS_LIST_ENTRY entry = NULL;
PPROCESS_MAP_MODULE_ENTRY module = NULL;
PPROCESS_MODULE_MAP_CONTEXT context = NULL;
if (!map->active)
return;
status = PsLookupProcessByProcessId(ProcessId, &process);
if (!NT_SUCCESS(status))
return;
KeAcquireGuardedMutex(&map->lock);
/* the PEPROCESS is the first element and is the only thing compared, hence
* we can simply pass it in the context parameter.*/
entry = RtlLookupEntryHashmap(GetProcessHashmap(), ProcessId, &ProcessId);
/* critical error has occured */
if (!entry) {
DEBUG_ERROR("RtlLookupEntryHashmap failed.");
goto end;
}
context = (PPROCESS_MODULE_MAP_CONTEXT)map->context;
module = ExAllocateFromLookasideListEx(&context->pool);
if (!module)
goto end;
/* for now lets just do base and size */
module->base = ImageInfo->ImageBase;
module->size = ImageInfo->ImageSize;
/* We dont care if this errors. */
if (FullImageName)
UnicodeToCharBufString(
FullImageName, module->path, sizeof(module->path));
InsertTailList(&entry->module_list, &module->entry);
entry->list_count++;
end:
KeReleaseGuardedMutex(&map->lock);
}
VOID VOID
ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName, ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
_In_ HANDLE ProcessId, _In_ HANDLE ProcessId,
@ -299,11 +326,15 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
if (InterlockedExchange(&list->active, list->active) == FALSE) if (InterlockedExchange(&list->active, list->active) == FALSE)
return; return;
if (ImageInfo->SystemModeImage == FALSE) if (ImageInfo->SystemModeImage == FALSE) {
ImageLoadInsertNonSystemImageIntoProcessHashmap(
ImageInfo, ProcessId, FullImageName);
return; return;
}
FindDriverEntryByBaseAddress(ImageInfo->ImageBase, &entry); FindDriverEntryByBaseAddress(ImageInfo->ImageBase, &entry);
/* if we image exists, exit */
if (entry) if (entry)
return; return;
@ -322,23 +353,10 @@ ImageLoadNotifyRoutineCallback(_In_opt_ PUNICODE_STRING FullImageName,
module.ImageSize = ImageInfo->ImageSize; module.ImageSize = ImageInfo->ImageSize;
if (FullImageName) { if (FullImageName) {
status = RtlUnicodeStringToAnsiString(&ansi_path, FullImageName, TRUE); UnicodeToCharBufString(
FullImageName, module.FullPathName, sizeof(module.FullPathName));
if (!NT_SUCCESS(status)) { RtlCopyMemory(
DEBUG_ERROR("RtlUnicodeStringToAnsiString failed with status %x", entry->path, module.FullPathName, sizeof(module.FullPathName));
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); DEBUG_VERBOSE("New system image ansi: %s", entry->path);
@ -359,29 +377,172 @@ hash:
ListInsert(&list->start, entry, &list->lock); ListInsert(&list->start, entry, &list->lock);
} }
NTSTATUS /* assumes map lock is held */
InitialiseProcessList() VOID
FreeProcessEntryModuleList(_In_ PPROCESS_LIST_ENTRY Entry,
_In_opt_ PVOID Context)
{ {
NTSTATUS status = STATUS_UNSUCCESSFUL; UNREFERENCED_PARAMETER(Context);
PPROCESS_LIST_HEAD list = GetProcessList();
status = ExInitializeLookasideListEx(&list->lookaside_list, PRTL_HASHMAP map = GetProcessHashmap();
PLIST_ENTRY list = NULL;
PPROCESS_MAP_MODULE_ENTRY list_entry = NULL;
PPROCESS_MODULE_MAP_CONTEXT context = map->context;
while (!IsListEmpty(&Entry->module_list)) {
list = RemoveTailList(&Entry->module_list);
list_entry = CONTAINING_RECORD(list, PROCESS_MAP_MODULE_ENTRY, entry);
ExFreeToLookasideListEx(&context->pool, list_entry);
}
}
VOID
EnumerateProcessModuleList(_In_ HANDLE ProcessId,
_In_ PROCESS_MODULE_CALLBACK Callback,
_In_opt_ PVOID Context)
{
PRTL_HASHMAP map = GetProcessHashmap();
BOOLEAN ret = FALSE;
PPROCESS_LIST_ENTRY entry = NULL;
PLIST_ENTRY list = NULL;
PPROCESS_MAP_MODULE_ENTRY module = NULL;
if (!map->active)
return;
KeAcquireGuardedMutex(&map->lock);
entry = RtlLookupEntryHashmap(map, ProcessId, &ProcessId);
if (!entry)
goto end;
for (list = entry->module_list.Flink; list != &entry->module_list;
list = list->Flink) {
module = CONTAINING_RECORD(list, PROCESS_MAP_MODULE_ENTRY, entry);
if (Callback(module, Context))
goto end;
}
end:
KeReleaseGuardedMutex(&map->lock);
}
VOID
FindOurUserModeModuleEntry(_In_ PROCESS_MODULE_CALLBACK Callback,
_In_opt_ PVOID Context)
{
PRTL_HASHMAP map = GetProcessHashmap();
PPROCESS_LIST_ENTRY entry = NULL;
PACTIVE_SESSION session = GetActiveSession();
PLIST_ENTRY list = NULL;
PPROCESS_MAP_MODULE_ENTRY module = NULL;
if (!map->active)
return;
KeAcquireGuardedMutex(&map->lock);
entry = RtlLookupEntryHashmap(map, session->km_handle, &session->km_handle);
if (!entry)
return;
for (list = entry->module_list.Flink; list != &entry->module_list;
list = list->Flink) {
module = CONTAINING_RECORD(list, PROCESS_MAP_MODULE_ENTRY, entry);
if (module->base == session->module.base_address &&
module->size == session->module.size) {
Callback(module, Context);
goto end;
}
}
end:
KeReleaseGuardedMutex(&map->lock);
}
VOID
CleanupProcessHashmap()
{
PRTL_HASHMAP map = GetProcessHashmap();
PRTL_HASHMAP_ENTRY entry = NULL;
PRTL_HASHMAP_ENTRY temp = NULL;
PLIST_ENTRY list = NULL;
PPROCESS_MODULE_MAP_CONTEXT context = NULL;
map->active = FALSE;
KeAcquireGuardedMutex(&map->lock);
/* First, free all module lists */
RtlEnumerateHashmap(map, FreeProcessEntryModuleList, NULL);
for (UINT32 index = 0; index < map->bucket_count; index++) {
entry = &map->buckets[index];
while (!IsListEmpty(&entry->entry)) {
list = RemoveHeadList(&entry->entry);
temp = CONTAINING_RECORD(list, RTL_HASHMAP_ENTRY, entry);
ExFreePoolWithTag(temp, POOL_TAG_HASHMAP);
}
}
context = map->context;
ExDeleteLookasideListEx(&context->pool);
ExFreePoolWithTag(map->context, POOL_TAG_HASHMAP);
RtlDeleteHashmap(map);
KeReleaseGuardedMutex(&map->lock);
}
NTSTATUS
InitialiseProcessHashmap()
{
PAGED_CODE();
NTSTATUS status = STATUS_UNSUCCESSFUL;
PPROCESS_MODULE_MAP_CONTEXT context = NULL;
context = ExAllocatePool2(POOL_FLAG_NON_PAGED,
sizeof(PROCESS_MODULE_MAP_CONTEXT),
POOL_TAG_HASHMAP);
if (!context)
return STATUS_INSUFFICIENT_RESOURCES;
status = ExInitializeLookasideListEx(&context->pool,
NULL, NULL,
NULL, NULL,
POOL_NX_ALLOCATION, NonPagedPoolNx,
0, 0,
sizeof(PROCESS_LIST_ENTRY), sizeof(PROCESS_MAP_MODULE_ENTRY),
POOL_TAG_PROCESS_LIST, POOL_TAG_MODULE_LIST,
0); 0);
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ExInitializeLookasideListEx failed with status %x", ExFreePoolWithTag(context, POOL_TAG_HASHMAP);
status); return status;
}
status = RtlCreateHashmap(PROCESS_HASHMAP_BUCKET_COUNT,
sizeof(PROCESS_LIST_ENTRY),
ProcessHashmapHashFunction,
ProcessHashmapCompareFunction,
context,
GetProcessHashmap());
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("RtlCreateHashmap: %lx", status);
ExDeleteLookasideListEx(&context->pool);
ExFreePoolWithTag(context, POOL_TAG_HASHMAP);
return status; return status;
} }
InterlockedExchange(&list->active, TRUE);
ListInit(&list->start, &list->lock);
return status; return status;
} }
@ -411,28 +572,6 @@ InitialiseThreadList()
return status; return status;
} }
VOID
FindProcessListEntryByProcess(_In_ PKPROCESS Process,
_Out_ PPROCESS_LIST_ENTRY* Entry)
{
PPROCESS_LIST_HEAD list = GetProcessList();
ImpKeAcquireGuardedMutex(&list->lock);
*Entry = NULL;
PPROCESS_LIST_ENTRY entry = (PPROCESS_LIST_ENTRY)list->start.Next;
while (entry) {
if (entry->process == Process) {
*Entry = entry;
goto unlock;
}
entry = entry->list.Next;
}
unlock:
ImpKeReleaseGuardedMutex(&list->lock);
}
VOID VOID
FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread, FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread,
_Out_ PTHREAD_LIST_ENTRY* Entry) _Out_ PTHREAD_LIST_ENTRY* Entry)
@ -464,19 +603,66 @@ CanInitiateDeferredHashing(_In_ LPCSTR ProcessName, _In_ PDRIVER_LIST_HEAD Head)
: FALSE; : FALSE;
} }
VOID
EnumerateAndPrintProcessHashmap()
{
PRTL_HASHMAP map = GetProcessHashmap();
PRTL_HASHMAP_ENTRY entry = NULL;
PPROCESS_LIST_ENTRY proc_entry = NULL;
PPROCESS_MAP_MODULE_ENTRY mod_entry = NULL;
PLIST_ENTRY list_head = NULL;
PLIST_ENTRY list_entry = NULL;
PLIST_ENTRY mod_list_entry = NULL;
KeAcquireGuardedMutex(&map->lock);
for (UINT32 index = 0; index < map->bucket_count; index++) {
list_head = &map->buckets[index];
list_entry = list_head->Flink;
DEBUG_VERBOSE("Bucket %u:\n", index);
while (list_entry != list_head) {
entry = CONTAINING_RECORD(list_entry, RTL_HASHMAP_ENTRY, entry);
if (entry->in_use == TRUE) {
proc_entry = (PPROCESS_LIST_ENTRY)entry->object;
DEBUG_VERBOSE(" -> process id: %lx", proc_entry->process_id);
DEBUG_VERBOSE(" -> process: %llx", proc_entry->process);
DEBUG_VERBOSE(" -> parent: %llx", proc_entry->parent);
mod_list_entry = proc_entry->module_list.Flink;
while (mod_list_entry != &proc_entry->module_list) {
mod_entry = CONTAINING_RECORD(
mod_list_entry, PROCESS_MAP_MODULE_ENTRY, entry);
DEBUG_VERBOSE(" -> module base: %llx", mod_entry->base);
DEBUG_VERBOSE(" -> module size: %lx", mod_entry->size);
mod_list_entry = mod_list_entry->Flink;
}
}
list_entry = list_entry->Flink;
}
}
KeReleaseGuardedMutex(&map->lock);
}
VOID VOID
ProcessCreateNotifyRoutine(_In_ HANDLE ParentId, ProcessCreateNotifyRoutine(_In_ HANDLE ParentId,
_In_ HANDLE ProcessId, _In_ HANDLE ProcessId,
_In_ BOOLEAN Create) _In_ BOOLEAN Create)
{ {
PPROCESS_LIST_ENTRY entry = NULL; BOOLEAN new = FALSE;
PKPROCESS parent = NULL; PKPROCESS parent = NULL;
PKPROCESS process = NULL; PKPROCESS process = NULL;
PPROCESS_LIST_HEAD list = GetProcessList();
PDRIVER_LIST_HEAD driver_list = GetDriverList(); PDRIVER_LIST_HEAD driver_list = GetDriverList();
LPCSTR process_name = NULL; LPCSTR process_name = NULL;
PRTL_HASHMAP map = GetProcessHashmap();
PPROCESS_LIST_ENTRY entry = NULL;
if (!list->active) if (!map->active)
return; return;
ImpPsLookupProcessByProcessId(ParentId, &parent); ImpPsLookupProcessByProcessId(ParentId, &parent);
@ -487,19 +673,21 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId,
process_name = ImpPsGetProcessImageFileName(process); process_name = ImpPsGetProcessImageFileName(process);
KeAcquireGuardedMutex(&map->lock);
if (Create) { if (Create) {
entry = ExAllocateFromLookasideListEx(&list->lookaside_list); entry = RtlInsertEntryHashmap(map, ProcessId);
if (!entry) if (!entry)
return; goto end;
ImpObfReferenceObject(parent); entry->process_id = ProcessId;
ImpObfReferenceObject(process); entry->process = process;
entry->parent = parent;
entry->parent = parent; InitializeListHead(&entry->module_list);
entry->process = process;
ListInsert(&list->start, entry, &list->lock); entry->list_count = 0;
/* /*
* Notify to our driver that we can hash x86 modules, and hash * Notify to our driver that we can hash x86 modules, and hash
@ -513,16 +701,22 @@ ProcessCreateNotifyRoutine(_In_ HANDLE ParentId,
} }
} }
else { else {
FindProcessListEntryByProcess(process, &entry); entry = RtlLookupEntryHashmap(map, ProcessId, &ProcessId);
if (!entry) if (!entry) {
return; DEBUG_ERROR("UNABLE TO FIND PROCESS NODE!!!");
goto end;
}
ImpObDereferenceObject(entry->parent); ImpObDereferenceObject(entry->parent);
ImpObDereferenceObject(entry->process); ImpObDereferenceObject(entry->process);
LookasideListRemoveEntry(&list->start, entry, &list->lock); FreeProcessEntryModuleList(entry, NULL);
RtlDeleteEntryHashmap(map, ProcessId, &ProcessId);
} }
end:
KeReleaseGuardedMutex(&map->lock);
} }
VOID VOID
@ -954,22 +1148,21 @@ end:
} }
NTSTATUS NTSTATUS
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
_In_opt_ PVOID Context)
{ {
/* Handles are stored in pageable memory */ /* Handles are stored in pageable memory */
PAGED_CODE(); PAGED_CODE();
UNREFERENCED_PARAMETER(Context); UNREFERENCED_PARAMETER(Context);
if (!ProcessListEntry) if (!Entry)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
if (ProcessListEntry->process == PsInitialSystemProcess) if (Entry->process == PsInitialSystemProcess)
return STATUS_SUCCESS; return STATUS_SUCCESS;
PHANDLE_TABLE handle_table = PHANDLE_TABLE handle_table =
*(PHANDLE_TABLE*)((uintptr_t)ProcessListEntry->process + *(PHANDLE_TABLE*)((uintptr_t)Entry->process +
EPROCESS_HANDLE_TABLE_OFFSET); EPROCESS_HANDLE_TABLE_OFFSET);
if (!handle_table) if (!handle_table)
@ -990,14 +1183,43 @@ EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
#define REPEAT_TIME_10_SEC 10000 #define REPEAT_TIME_10_SEC 10000
STATIC
VOID
TimerObjectValidateProcessModuleCallback(_In_ PPROCESS_MAP_MODULE_ENTRY Entry,
_In_opt_ PVOID Context)
{
CHAR hash[SHA_256_HASH_LENGTH] = {0};
NTSTATUS status = STATUS_UNSUCCESSFUL;
PACTIVE_SESSION session = (PACTIVE_SESSION)Context;
if (!ARGUMENT_PRESENT(Context))
return;
status = HashUserModule(Entry, hash, sizeof(hash));
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("HashUserModule: %x", status);
return;
}
if (RtlCompareMemory(hash, session->module.module_hash, sizeof(hash)) !=
sizeof(hash)) {
DEBUG_ERROR("User module hash not matching!! MODIFIED!");
return;
}
DEBUG_VERBOSE("User module hash valid.");
}
STATIC STATIC
VOID VOID
TimerObjectWorkItemRoutine(_In_ PDEVICE_OBJECT DeviceObject, TimerObjectWorkItemRoutine(_In_ PDEVICE_OBJECT DeviceObject,
_In_opt_ PVOID Context) _In_opt_ PVOID Context)
{ {
NTSTATUS status = STATUS_UNSUCCESSFUL; NTSTATUS status = STATUS_UNSUCCESSFUL;
PTIMER_OBJECT timer = (PTIMER_OBJECT)Context; PTIMER_OBJECT timer = (PTIMER_OBJECT)Context;
PDRIVER_LIST_HEAD list = GetDriverList(); PDRIVER_LIST_HEAD list = GetDriverList();
PACTIVE_SESSION session = GetActiveSession();
UNREFERENCED_PARAMETER(DeviceObject); UNREFERENCED_PARAMETER(DeviceObject);
@ -1018,6 +1240,16 @@ TimerObjectWorkItemRoutine(_In_ PDEVICE_OBJECT DeviceObject,
if (!NT_SUCCESS(status)) if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateOurDriverImage failed with status %x", status); DEBUG_ERROR("ValidateOurDriverImage failed with status %x", status);
KeAcquireGuardedMutex(&session->lock);
if (!session->is_session_active) {
KeReleaseGuardedMutex(&session->lock);
goto end;
}
FindOurUserModeModuleEntry(TimerObjectValidateProcessModuleCallback,
session);
KeReleaseGuardedMutex(&session->lock);
end: end:
InterlockedExchange(&timer->state, FALSE); InterlockedExchange(&timer->state, FALSE);
} }

View file

@ -9,9 +9,6 @@
typedef void (*THREADLIST_CALLBACK_ROUTINE)( typedef void (*THREADLIST_CALLBACK_ROUTINE)(
_In_ PTHREAD_LIST_ENTRY ThreadListEntry, _In_opt_ PVOID Context); _In_ PTHREAD_LIST_ENTRY ThreadListEntry, _In_opt_ PVOID Context);
typedef void (*PROCESSLIST_CALLBACK_ROUTINE)(
_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _In_opt_ PVOID Context);
#define DRIVER_PATH_LENGTH 0x100 #define DRIVER_PATH_LENGTH 0x100
#define SHA_256_HASH_LENGTH 32 #define SHA_256_HASH_LENGTH 32
@ -36,6 +33,9 @@ typedef struct _DRIVER_LIST_ENTRY {
typedef void (*DRIVERLIST_CALLBACK_ROUTINE)( typedef void (*DRIVERLIST_CALLBACK_ROUTINE)(
_In_ PDRIVER_LIST_ENTRY DriverListEntry, _In_opt_ PVOID Context); _In_ PDRIVER_LIST_ENTRY DriverListEntry, _In_opt_ PVOID Context);
typedef BOOLEAN (*PROCESS_MODULE_CALLBACK)(_In_ PPROCESS_MAP_MODULE_ENTRY Entry,
_In_opt_ PVOID Context);
NTSTATUS NTSTATUS
InitialiseDriverList(); InitialiseDriverList();
@ -52,16 +52,9 @@ OB_PREOP_CALLBACK_STATUS
ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext, ObPreOpCallbackRoutine(_In_ PVOID RegistrationContext,
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation); _In_ POB_PRE_OPERATION_INFORMATION OperationInformation);
NTSTATUS
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
_In_opt_ PVOID Context);
NTSTATUS NTSTATUS
InitialiseThreadList(); InitialiseThreadList();
NTSTATUS
InitialiseProcessList();
VOID VOID
ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId, ThreadCreateNotifyRoutine(_In_ HANDLE ProcessId,
_In_ HANDLE ThreadId, _In_ HANDLE ThreadId,
@ -76,28 +69,17 @@ VOID
CleanupThreadListOnDriverUnload(); CleanupThreadListOnDriverUnload();
VOID VOID
FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread, FindThreadListEntryByThreadAddress(_In_ PKTHREAD Thread,
_Out_ PTHREAD_LIST_ENTRY* Entry); _Out_ PTHREAD_LIST_ENTRY* Entry);
VOID
FindProcessListEntryByProcess(_In_ PKPROCESS Process,
_Out_ PPROCESS_LIST_ENTRY* Entry);
VOID VOID
EnumerateThreadListWithCallbackRoutine( EnumerateThreadListWithCallbackRoutine(
_In_ THREADLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context); _In_ THREADLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context);
VOID
EnumerateProcessListWithCallbackRoutine(
_In_ PROCESSLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context);
VOID VOID
FindDriverEntryByBaseAddress(_In_ PVOID ImageBase, FindDriverEntryByBaseAddress(_In_ PVOID ImageBase,
_Out_ PDRIVER_LIST_ENTRY* Entry); _Out_ PDRIVER_LIST_ENTRY* Entry);
VOID
CleanupProcessListOnDriverUnload();
VOID VOID
CleanupDriverListOnDriverUnload(); CleanupDriverListOnDriverUnload();
@ -138,4 +120,25 @@ VOID
DriverListEntryToExtendedModuleInfo(_In_ PDRIVER_LIST_ENTRY Entry, DriverListEntryToExtendedModuleInfo(_In_ PDRIVER_LIST_ENTRY Entry,
_Out_ PRTL_MODULE_EXTENDED_INFO Extended); _Out_ PRTL_MODULE_EXTENDED_INFO Extended);
NTSTATUS
InitialiseProcessHashmap();
NTSTATUS
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context);
VOID
EnumerateAndPrintProcessHashmap();
VOID
CleanupProcessHashmap();
VOID
EnumerateProcessModuleList(_In_ HANDLE ProcessId,
_In_ PROCESS_MODULE_CALLBACK Callback,
_In_opt_ PVOID Context);
VOID
FindOurUserModeModuleEntry(_In_ PROCESS_MODULE_CALLBACK Callback,
_In_opt_ PVOID Context);
#endif #endif

View file

@ -45,10 +45,16 @@
"donna-ac : [VERBOSE] : " fmt "\n", \ "donna-ac : [VERBOSE] : " fmt "\n", \
##__VA_ARGS__) ##__VA_ARGS__)
#define HEX_DUMP(fmt, ...) \
DbgPrintEx(DPFLTR_DEFAULT_ID, \
LOG_VERBOSE_LEVEL, \
fmt, \
##__VA_ARGS__)
#define STATIC static #define STATIC static
#define INLINE inline #define INLINE inline
#define MAX_MODULE_PATH 256 #define MAX_MODULE_PATH 260
#define CONVERT_RELATIVE_ADDRESS(Cast, Base, Rel) \ #define CONVERT_RELATIVE_ADDRESS(Cast, Base, Rel) \
((Cast)((DWORD_PTR)(Base) + (DWORD_PTR)(Rel))) ((Cast)((DWORD_PTR)(Base) + (DWORD_PTR)(Rel)))
@ -66,14 +72,6 @@ typedef struct _THREAD_LIST_HEAD {
} THREAD_LIST_HEAD, *PTHREAD_LIST_HEAD; } THREAD_LIST_HEAD, *PTHREAD_LIST_HEAD;
typedef struct _PROCESS_LIST_HEAD {
SINGLE_LIST_ENTRY start;
volatile BOOLEAN active;
KGUARDED_MUTEX lock;
LOOKASIDE_LIST_EX lookaside_list;
} PROCESS_LIST_HEAD, *PPROCESS_LIST_HEAD;
typedef struct _DRIVER_LIST_HEAD { typedef struct _DRIVER_LIST_HEAD {
SINGLE_LIST_ENTRY start; SINGLE_LIST_ENTRY start;
volatile ULONG count; volatile ULONG count;
@ -97,11 +95,24 @@ typedef struct _THREAD_LIST_ENTRY {
} THREAD_LIST_ENTRY, *PTHREAD_LIST_ENTRY; } THREAD_LIST_ENTRY, *PTHREAD_LIST_ENTRY;
typedef struct _PROCESS_LIST_ENTRY { typedef struct _PROCESS_MODULE_MAP_CONTEXT {
SINGLE_LIST_ENTRY list; LOOKASIDE_LIST_EX pool;
PKPROCESS process; } PROCESS_MODULE_MAP_CONTEXT, *PPROCESS_MODULE_MAP_CONTEXT;
PKPROCESS parent;
typedef struct _PROCESS_MAP_MODULE_ENTRY {
LIST_ENTRY entry;
UINT64 base;
UINT32 size;
CHAR path[MAX_MODULE_PATH];
} PROCESS_MAP_MODULE_ENTRY, *PPROCESS_MAP_MODULE_ENTRY;
typedef struct _PROCESS_LIST_ENTRY {
/* IMPORTANT THIS IS FIRST!*/
HANDLE process_id;
PEPROCESS process;
PEPROCESS parent;
LIST_ENTRY module_list;
volatile UINT32 list_count;
} PROCESS_LIST_ENTRY, *PPROCESS_LIST_ENTRY; } PROCESS_LIST_ENTRY, *PPROCESS_LIST_ENTRY;
/* /*
@ -237,16 +248,28 @@ typedef struct _HEARTBEAT_CONFIGURATION {
} HEARTBEAT_CONFIGURATION, *PHEARTBEAT_CONFIGURATION; } HEARTBEAT_CONFIGURATION, *PHEARTBEAT_CONFIGURATION;
#define SHA_256_HASH_LENGTH 32
/* Contains information on our user mode module. */
typedef struct _MODULE_INFORMATION {
PVOID base_address;
UINT32 size;
CHAR path[MAX_MODULE_PATH];
CHAR module_hash[SHA_256_HASH_LENGTH];
} MODULE_INFORMATION, *PMODULE_INFORMATION;
typedef struct _SESSION_INITIATION_PACKET { typedef struct _SESSION_INITIATION_PACKET {
UINT32 cookie; UINT32 cookie;
PVOID process_id; PVOID process_id;
UCHAR aes_key[AES_256_KEY_SIZE]; UCHAR aes_key[AES_256_KEY_SIZE];
UCHAR aes_iv[AES_256_IV_SIZE]; UCHAR aes_iv[AES_256_IV_SIZE];
MODULE_INFORMATION module_info;
} SESSION_INITIATION_PACKET, *PSESSION_INITIATION_PACKET; } SESSION_INITIATION_PACKET, *PSESSION_INITIATION_PACKET;
typedef struct _ACTIVE_SESSION { typedef struct _ACTIVE_SESSION {
BOOLEAN is_session_active; volatile BOOLEAN is_session_active;
PVOID um_handle; PVOID um_handle;
PVOID km_handle; PVOID km_handle;
PEPROCESS process; PEPROCESS process;
@ -269,6 +292,8 @@ typedef struct _ACTIVE_SESSION {
UINT32 heartbeat_count; UINT32 heartbeat_count;
}; };
MODULE_INFORMATION module;
HEARTBEAT_CONFIGURATION heartbeat_config; HEARTBEAT_CONFIGURATION heartbeat_config;
KGUARDED_MUTEX lock; KGUARDED_MUTEX lock;
@ -306,9 +331,13 @@ typedef struct _ACTIVE_SESSION {
#define POOL_TAG_LIST_ITEM 'tsil' #define POOL_TAG_LIST_ITEM 'tsil'
#define POOL_TAG_THREAD_LIST 'list' #define POOL_TAG_THREAD_LIST 'list'
#define POOL_TAG_PROCESS_LIST 'plis' #define POOL_TAG_PROCESS_LIST 'plis'
#define POOL_TAG_USER_MODULE_LIST 'resu'
#define POOL_TAG_USER_MODULE_NODE 'edon'
#define POOL_TAG_DRIVER_LIST 'drvl' #define POOL_TAG_DRIVER_LIST 'drvl'
#define POOL_TAG_IRP_QUEUE 'irpp' #define POOL_TAG_IRP_QUEUE 'irpp'
#define POOL_TAG_TIMER 'time' #define POOL_TAG_TIMER 'time'
#define POOL_TAG_MODULE_LIST 'elom'
#define POOL_TAG_HASHMAP 'hsah'
#define IA32_APERF_MSR 0x000000E8 #define IA32_APERF_MSR 0x000000E8

View file

@ -242,7 +242,7 @@ CryptInitialiseSessionCryptObjects()
UINT32 data_copied = 0; UINT32 data_copied = 0;
PACTIVE_SESSION session = GetActiveSession(); PACTIVE_SESSION session = GetActiveSession();
PBCRYPT_KEY_DATA_BLOB_HEADER blob = NULL; PBCRYPT_KEY_DATA_BLOB_HEADER blob = NULL;
BCRYPT_ALG_HANDLE* handle = GetCryptAlgHandle(); BCRYPT_ALG_HANDLE* handle = GetCryptHandle_AES();
blob = CryptBuildBlobForKeyImport(session); blob = CryptBuildBlobForKeyImport(session);
@ -301,7 +301,7 @@ NTSTATUS
CryptInitialiseProvider() CryptInitialiseProvider()
{ {
NTSTATUS status = STATUS_UNSUCCESSFUL; NTSTATUS status = STATUS_UNSUCCESSFUL;
BCRYPT_ALG_HANDLE* handle = GetCryptAlgHandle(); BCRYPT_ALG_HANDLE* handle = GetCryptHandle_AES();
status = BCryptOpenAlgorithmProvider( status = BCryptOpenAlgorithmProvider(
handle, BCRYPT_AES_ALGORITHM, NULL, BCRYPT_PROV_DISPATCH); handle, BCRYPT_AES_ALGORITHM, NULL, BCRYPT_PROV_DISPATCH);
@ -315,7 +315,7 @@ CryptInitialiseProvider()
VOID VOID
CryptCloseProvider() CryptCloseProvider()
{ {
BCRYPT_ALG_HANDLE* handle = GetCryptAlgHandle(); BCRYPT_ALG_HANDLE* handle = GetCryptHandle_AES();
BCryptCloseAlgorithmProvider(*handle, 0); BCryptCloseAlgorithmProvider(*handle, 0);
} }
@ -448,6 +448,8 @@ TpmGetPtpInterfaceType(_In_ PVOID Register,
return status; return status;
} }
NTSTATUS NTSTATUS
TpmExtractEndorsementKey() TpmExtractEndorsementKey()
{ {

View file

@ -95,14 +95,15 @@ typedef struct _DRIVER_CONFIG {
/* terrible name..lol what is tis timer for ?? */ /* terrible name..lol what is tis timer for ?? */
TIMER_OBJECT timer; TIMER_OBJECT timer;
ACTIVE_SESSION session_information; ACTIVE_SESSION session_information;
THREAD_LIST_HEAD thread_list; THREAD_LIST_HEAD thread_list;
DRIVER_LIST_HEAD driver_list; DRIVER_LIST_HEAD driver_list;
PROCESS_LIST_HEAD process_list; RTL_HASHMAP process_hashmap;
SHARED_MAPPING mapping; SHARED_MAPPING mapping;
BOOLEAN has_driver_loaded; BOOLEAN has_driver_loaded;
BCRYPT_ALG_HANDLE alg_handle; BCRYPT_ALG_HANDLE aes_hash;
BCRYPT_ALG_HANDLE sha256_hash;
} DRIVER_CONFIG, *PDRIVER_CONFIG; } DRIVER_CONFIG, *PDRIVER_CONFIG;
@ -123,9 +124,21 @@ PDRIVER_CONFIG g_DriverConfig = NULL;
#define POOL_TAG_CONFIG 'conf' #define POOL_TAG_CONFIG 'conf'
BCRYPT_ALG_HANDLE* BCRYPT_ALG_HANDLE*
GetCryptAlgHandle() GetCryptHandle_Sha256()
{ {
return &g_DriverConfig->alg_handle; return &g_DriverConfig->sha256_hash;
}
PRTL_HASHMAP
GetProcessHashmap()
{
return &g_DriverConfig->process_hashmap;
}
BCRYPT_ALG_HANDLE*
GetCryptHandle_AES()
{
return &g_DriverConfig->aes_hash;
} }
BOOLEAN BOOLEAN
@ -271,13 +284,6 @@ GetDriverList()
return &g_DriverConfig->driver_list; return &g_DriverConfig->driver_list;
} }
PPROCESS_LIST_HEAD
GetProcessList()
{
PAGED_CODE();
return &g_DriverConfig->process_list;
}
/* /*
* The question is, What happens if we attempt to register our callbacks after * The question is, What happens if we attempt to register our callbacks after
* we unregister them but before we free the pool? Hm.. No Good. * we unregister them but before we free the pool? Hm.. No Good.
@ -350,7 +356,7 @@ VOID
DrvUnloadFreeProcessList() DrvUnloadFreeProcessList()
{ {
PAGED_CODE(); PAGED_CODE();
CleanupProcessListOnDriverUnload(); CleanupProcessHashmap();
} }
STATIC STATIC
@ -361,6 +367,14 @@ DrvUnloadFreeModuleValidationContext()
CleanupValidationContextOnUnload(&g_DriverConfig->sys_val_context); CleanupValidationContextOnUnload(&g_DriverConfig->sys_val_context);
} }
STATIC
VOID
CloseHashingAlgorithmProvider()
{
BCRYPT_ALG_HANDLE* handle = GetCryptHandle_Sha256();
BCryptCloseAlgorithmProvider(*handle, 0);
}
STATIC STATIC
VOID VOID
DriverUnload(_In_ PDRIVER_OBJECT DriverObject) DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
@ -391,6 +405,7 @@ DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
DrvUnloadFreeDriverList(); DrvUnloadFreeDriverList();
CryptCloseProvider(); CryptCloseProvider();
CloseHashingAlgorithmProvider();
DrvUnloadFreeConfigStrings(); DrvUnloadFreeConfigStrings();
DrvUnloadDeleteSymbolicLink(); DrvUnloadDeleteSymbolicLink();
@ -470,7 +485,7 @@ DrvLoadSetupDriverLists()
return status; return status;
} }
status = InitialiseProcessList(); status = InitialiseProcessHashmap();
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
DEBUG_ERROR("InitialiseProcessList failed with status %x", status); DEBUG_ERROR("InitialiseProcessList failed with status %x", status);
@ -826,6 +841,22 @@ DrvLoadInitialiseDriverConfig(_In_ PDRIVER_OBJECT DriverObject,
return status; return status;
} }
STATIC
NTSTATUS
InitialiseHashingAlgorithmProvider()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
BCRYPT_ALG_HANDLE* handle = GetCryptHandle_Sha256();
status = BCryptOpenAlgorithmProvider(
handle, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_PROV_DISPATCH);
if (!NT_SUCCESS(status))
DEBUG_ERROR("BCryptOpenAlgorithmProvider: %x", status);
return status;
}
NTSTATUS NTSTATUS
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{ {
@ -905,10 +936,23 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
return status; return status;
} }
status = InitialiseHashingAlgorithmProvider();
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("InitialiseHashingAlgorithmProvider failed with status %x",
status);
DrvUnloadFreeConfigStrings();
DrvUnloadFreeTimerObject();
DrvUnloadDeleteSymbolicLink();
ImpIoDeleteDevice(DriverObject->DeviceObject);
return status;
}
status = DrvLoadSetupDriverLists(); status = DrvLoadSetupDriverLists();
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
DEBUG_ERROR("DrvLoadSetupDriverLists failed with status %x", status); DEBUG_ERROR("DrvLoadSetupDriverLists failed with status %x", status);
CloseHashingAlgorithmProvider();
DrvUnloadFreeConfigStrings(); DrvUnloadFreeConfigStrings();
DrvUnloadFreeTimerObject(); DrvUnloadFreeTimerObject();
DrvUnloadDeleteSymbolicLink(); DrvUnloadDeleteSymbolicLink();

View file

@ -9,9 +9,13 @@
#include "modules.h" #include "modules.h"
#include "integrity.h" #include "integrity.h"
#include "callbacks.h" #include "callbacks.h"
#include "map.h"
BCRYPT_ALG_HANDLE* BCRYPT_ALG_HANDLE*
GetCryptAlgHandle(); GetCryptHandle_AES();
BCRYPT_ALG_HANDLE*
GetCryptHandle_Sha256();
NTSTATUS NTSTATUS
QueryActiveApcContextsForCompletion(); QueryActiveApcContextsForCompletion();
@ -52,9 +56,6 @@ GetThreadList();
PDRIVER_LIST_HEAD PDRIVER_LIST_HEAD
GetDriverList(); GetDriverList();
PPROCESS_LIST_HEAD
GetProcessList();
PUINT64 PUINT64
GetApcContextArray(); GetApcContextArray();
@ -82,4 +83,10 @@ IsNmiInProgress();
BOOLEAN BOOLEAN
HasDriverLoaded(); HasDriverLoaded();
PRTL_HASHMAP
GetProcessHashmap();
VOID
CleanupProcessTree();
#endif #endif

View file

@ -253,6 +253,7 @@
<ClCompile Include="integrity.c" /> <ClCompile Include="integrity.c" />
<ClCompile Include="io.c" /> <ClCompile Include="io.c" />
<ClCompile Include="list.c" /> <ClCompile Include="list.c" />
<ClCompile Include="map.c" />
<ClCompile Include="modules.c" /> <ClCompile Include="modules.c" />
<ClCompile Include="hw.c" /> <ClCompile Include="hw.c" />
<ClCompile Include="pe.c" /> <ClCompile Include="pe.c" />
@ -275,6 +276,7 @@
<ClInclude Include="integrity.h" /> <ClInclude Include="integrity.h" />
<ClInclude Include="io.h" /> <ClInclude Include="io.h" />
<ClInclude Include="list.h" /> <ClInclude Include="list.h" />
<ClInclude Include="map.h" />
<ClInclude Include="modules.h" /> <ClInclude Include="modules.h" />
<ClInclude Include="pe.h" /> <ClInclude Include="pe.h" />
<ClInclude Include="pool.h" /> <ClInclude Include="pool.h" />

View file

@ -75,6 +75,9 @@
<ClCompile Include="util.c"> <ClCompile Include="util.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="map.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="driver.h"> <ClInclude Include="driver.h">
@ -146,6 +149,9 @@
<ClInclude Include="types\tpm12.h"> <ClInclude Include="types\tpm12.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="map.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<MASM Include="arch.asm"> <MASM Include="arch.asm">

View file

@ -310,13 +310,13 @@ PciDeviceQueryCallback(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
DEBUG_VERBOSE("Flagged DeviceID found. Device: %llx, DeviceId: %lx", DEBUG_VERBOSE("Flagged DeviceID found. Device: %llx, DeviceId: %lx",
(UINT64)DeviceObject, (UINT64)DeviceObject,
header.DeviceID); header.DeviceID);
ReportBlacklistedPcieDevice(DeviceObject, &header);
} }
else { else {
DEBUG_VERBOSE("Device: %llx, DeviceID: %lx, VendorID: %lx", DEBUG_VERBOSE("Device: %llx, DeviceID: %lx, VendorID: %lx",
DeviceObject, DeviceObject,
header.DeviceID, header.DeviceID,
header.VendorID); header.VendorID);
ReportBlacklistedPcieDevice(DeviceObject, &header);
} }
return status; return status;

View file

@ -257,6 +257,9 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer,
MM_COPY_ADDRESS address = {0}; MM_COPY_ADDRESS address = {0};
INTEGRITY_CHECK_HEADER header = {0}; INTEGRITY_CHECK_HEADER header = {0};
//DEBUG_VERBOSE("Storing x regions -> x86 module: %lx", (UINT32)IsModulex86);
//DEBUG_VERBOSE("MmIsAddressValid: %lx", MmIsAddressValid(ModuleBase));
if (!ModuleBase || !ModuleSize) if (!ModuleBase || !ModuleSize)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@ -278,6 +281,10 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer,
if (*Buffer == NULL) if (*Buffer == NULL)
return STATUS_MEMORY_NOT_ALLOCATED; return STATUS_MEMORY_NOT_ALLOCATED;
/* For context, when we are hashing x86 modules, MmIsAddressValid will
* return FALSE. Yet we still need protection for when an invalid address is
* passed for a non-x86 based image.*/
/* /*
* The IMAGE_DOS_HEADER.e_lfanew stores the offset of the * The IMAGE_DOS_HEADER.e_lfanew stores the offset of the
* IMAGE_NT_HEADER from the base of the image. * IMAGE_NT_HEADER from the base of the image.
@ -434,7 +441,7 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
PAGED_CODE(); PAGED_CODE();
NTSTATUS status = STATUS_UNSUCCESSFUL; NTSTATUS status = STATUS_UNSUCCESSFUL;
BCRYPT_ALG_HANDLE algo_handle = NULL; BCRYPT_ALG_HANDLE* algo_handle = GetCryptHandle_Sha256();
BCRYPT_HASH_HANDLE hash_handle = NULL; BCRYPT_HASH_HANDLE hash_handle = NULL;
ULONG bytes_copied = 0; ULONG bytes_copied = 0;
ULONG resulting_hash_size = 0; ULONG resulting_hash_size = 0;
@ -445,21 +452,12 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
*HashResult = NULL; *HashResult = NULL;
*HashResultSize = 0; *HashResultSize = 0;
status = BCryptOpenAlgorithmProvider(
&algo_handle, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_PROV_DISPATCH);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("BCryptOpenAlogrithmProvider failed with status %x",
status);
goto end;
}
/* /*
* Request the size of the hash object buffer, this is different then * Request the size of the hash object buffer, this is different then
* the buffer that will store the resulting hash, instead this will be * the buffer that will store the resulting hash, instead this will be
* used to store the hash object used to create the hash. * used to store the hash object used to create the hash.
*/ */
status = BCryptGetProperty(algo_handle, status = BCryptGetProperty(*algo_handle,
BCRYPT_OBJECT_LENGTH, BCRYPT_OBJECT_LENGTH,
(PCHAR)&hash_object_size, (PCHAR)&hash_object_size,
sizeof(ULONG), sizeof(ULONG),
@ -483,7 +481,7 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
* This call gets the size of the resulting hash, which we will use to * This call gets the size of the resulting hash, which we will use to
* allocate the resulting hash buffer. * allocate the resulting hash buffer.
*/ */
status = BCryptGetProperty(algo_handle, status = BCryptGetProperty(*algo_handle,
BCRYPT_HASH_LENGTH, BCRYPT_HASH_LENGTH,
(PCHAR)&resulting_hash_size, (PCHAR)&resulting_hash_size,
sizeof(ULONG), sizeof(ULONG),
@ -507,7 +505,7 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
* Here we create our hash object and store it in the hash_object * Here we create our hash object and store it in the hash_object
* buffer. * buffer.
*/ */
status = BCryptCreateHash(algo_handle, status = BCryptCreateHash(*algo_handle,
&hash_handle, &hash_handle,
hash_object, hash_object,
hash_object_size, hash_object_size,
@ -549,9 +547,6 @@ ComputeHashOfBuffer(_In_ PVOID Buffer,
end: end:
if (algo_handle)
BCryptCloseAlgorithmProvider(algo_handle, NULL);
if (hash_handle) if (hash_handle)
BCryptDestroyHash(hash_handle); BCryptDestroyHash(hash_handle);
@ -1027,6 +1022,66 @@ end:
return status; return status;
} }
NTSTATUS
HashUserModule(_In_ PPROCESS_MAP_MODULE_ENTRY Entry,
_Out_ PVOID OutBuffer,
_In_ UINT32 OutBufferSize)
{
PAGED_CODE();
NTSTATUS status = STATUS_UNSUCCESSFUL;
KAPC_STATE apc_state = {0};
PVAL_INTEGRITY_HEADER memory_buffer = NULL;
PVOID memory_hash = NULL;
ULONG memory_hash_size = 0;
SIZE_T bytes_written = 0;
PACTIVE_SESSION session = GetActiveSession();
/*
* Attach because the offsets given are from the process' context.
*/
ImpKeStackAttachProcess(session->process, &apc_state);
status = StoreModuleExecutableRegionsInBuffer(
&memory_buffer, Entry->base, Entry->size, &bytes_written, FALSE);
ImpKeUnstackDetachProcess(&apc_state);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR(
"StoreModuleExecutableRegionsInBuffer failed with status %x",
status);
goto end;
}
status = ComputeHashOfBuffer(memory_buffer->section_base,
memory_buffer->section_header.SizeOfRawData,
&memory_hash,
&memory_hash_size);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ComputeHashOfBuffer failed with status %x", status);
goto end;
}
if (OutBufferSize > memory_hash_size) {
status = STATUS_BUFFER_TOO_SMALL;
goto end;
}
RtlCopyMemory(OutBuffer, memory_hash, memory_hash_size);
end:
if (memory_buffer)
ImpExFreePoolWithTag(memory_buffer, POOL_TAG_INTEGRITY);
if (memory_hash)
ImpExFreePoolWithTag(memory_hash, POOL_TAG_INTEGRITY);
return status;
}
FORCEINLINE FORCEINLINE
STATIC STATIC
PCHAR PCHAR
@ -1258,6 +1313,9 @@ GetAverageReadTimeAtRoutine(_In_ PVOID RoutineAddress,
if (!RoutineAddress || !AverageTime) if (!RoutineAddress || !AverageTime)
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
if (!MmIsAddressValid(RoutineAddress))
return STATUS_INVALID_ADDRESS;
*AverageTime = MeasureReads(RoutineAddress, EPT_CHECK_NUM_ITERATIONS); *AverageTime = MeasureReads(RoutineAddress, EPT_CHECK_NUM_ITERATIONS);
return *AverageTime == 0 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS; return *AverageTime == 0 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
@ -1304,8 +1362,11 @@ WCHAR PROTECTED_FUNCTIONS[EPT_PROTECTED_FUNCTIONS_COUNT]
* call thereafter fails. So will be storing the routine addresses in arrays * call thereafter fails. So will be storing the routine addresses in arrays
* since they dont change once the kernel is loaded. * since they dont change once the kernel is loaded.
*/ */
UINT64 CONTROL_FUNCTION_ADDRESSES[EPT_CONTROL_FUNCTIONS_COUNT] = {0}; #pragma section("NonPagedPool", read, write)
UINT64 PROTECTED_FUNCTION_ADDRESSES[EPT_PROTECTED_FUNCTIONS_COUNT] = {0}; __declspec(allocate("NonPagedPool")) UINT64
CONTROL_FUNCTION_ADDRESSES[EPT_CONTROL_FUNCTIONS_COUNT] = {0};
__declspec(allocate("NonPagedPool")) UINT64
PROTECTED_FUNCTION_ADDRESSES[EPT_PROTECTED_FUNCTIONS_COUNT] = {0};
STATIC STATIC
NTSTATUS NTSTATUS
@ -1407,7 +1468,7 @@ DetectEptHooksInKeyFunctions()
} }
VOID VOID
FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context) FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Node, _In_opt_ PVOID Context)
{ {
LPCSTR process_name = NULL; LPCSTR process_name = NULL;
PEPROCESS* process = (PEPROCESS*)Context; PEPROCESS* process = (PEPROCESS*)Context;
@ -1415,10 +1476,10 @@ FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
if (!Context) if (!Context)
return; return;
process_name = ImpPsGetProcessImageFileName(Entry->process); process_name = ImpPsGetProcessImageFileName(Node->process);
if (!strcmp(process_name, "winlogon.exe")) if (!strcmp(process_name, "winlogon.exe"))
*process = Entry->process; *process = Node->process;
} }
STATIC STATIC
@ -1431,7 +1492,7 @@ StoreModuleExecutableRegionsx86(_In_ PRTL_MODULE_EXTENDED_INFO Module,
PEPROCESS process = NULL; PEPROCESS process = NULL;
KAPC_STATE apc_state = {0}; KAPC_STATE apc_state = {0};
EnumerateProcessListWithCallbackRoutine(FindWinLogonProcess, &process); RtlEnumerateHashmap(GetProcessHashmap(), FindWinLogonProcess, &process);
if (!process) if (!process)
return STATUS_NOT_FOUND; return STATUS_NOT_FOUND;
@ -2224,33 +2285,6 @@ WaitForHeartbeatCompletion(_In_ PHEARTBEAT_CONFIGURATION Configuration)
YieldProcessor(); YieldProcessor();
} }
STATIC
VOID
HeartbeatWorkItem(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
{
UNREFERENCED_PARAMETER(DeviceObject);
if (!ARGUMENT_PRESENT(Context))
return;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PHEARTBEAT_CONFIGURATION config = (PHEARTBEAT_CONFIGURATION)Context;
/* Ensure we wait until our heartbeats DPC has terminated. */
KeFlushQueuedDpcs();
FreeHeartbeatObjects(config);
status = AllocateHeartbeatObjects(config);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("AllocateHeartbeatObjects %x", status);
return;
}
InitialiseHeartbeatObjects(config);
SetHeartbeatInactive(config);
}
FORCEINLINE FORCEINLINE
STATIC STATIC
VOID VOID
@ -2291,22 +2325,17 @@ BuildHeartbeatPacket(_In_ UINT32 PacketSize)
STATIC STATIC
VOID VOID
HeartbeatDpcRoutine(_In_ PKDPC Dpc, HeartbeatWorkItem(_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
_In_opt_ PVOID DeferredContext,
_In_opt_ PVOID SystemArgument1,
_In_opt_ PVOID SystemArgument2)
{ {
UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
if (!ARGUMENT_PRESENT(DeferredContext)) if (!ARGUMENT_PRESENT(Context))
return; return;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PHEARTBEAT_CONFIGURATION config = (PHEARTBEAT_CONFIGURATION)DeferredContext;
PHEARTBEAT_PACKET packet = NULL;
UINT32 packet_size = 0; UINT32 packet_size = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PHEARTBEAT_PACKET packet = NULL;
PHEARTBEAT_CONFIGURATION config = (PHEARTBEAT_CONFIGURATION)Context;
DEBUG_VERBOSE("Heartbeat timer alerted. Generating heartbeat packet."); DEBUG_VERBOSE("Heartbeat timer alerted. Generating heartbeat packet.");
@ -2321,14 +2350,45 @@ HeartbeatDpcRoutine(_In_ PKDPC Dpc,
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
DEBUG_ERROR("CryptEncryptBuffer: %lx", status); DEBUG_ERROR("CryptEncryptBuffer: %lx", status);
ImpExFreePoolWithTag(packet, POOL_TAG_HEARTBEAT); ImpExFreePoolWithTag(packet, POOL_TAG_HEARTBEAT);
goto end; goto queue_next;
} }
IrpQueueSchedulePacket(packet, packet_size); IrpQueueSchedulePacket(packet, packet_size);
IncrementHeartbeatCounter(config); IncrementHeartbeatCounter(config);
} }
end: queue_next:
/* Ensure we wait until our heartbeats DPC has terminated. */
KeFlushQueuedDpcs();
FreeHeartbeatObjects(config);
status = AllocateHeartbeatObjects(config);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("AllocateHeartbeatObjects %x", status);
return;
}
InitialiseHeartbeatObjects(config);
SetHeartbeatInactive(config);
}
STATIC
VOID
HeartbeatDpcRoutine(_In_ PKDPC Dpc,
_In_opt_ PVOID DeferredContext,
_In_opt_ PVOID SystemArgument1,
_In_opt_ PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
if (!ARGUMENT_PRESENT(DeferredContext))
return;
PHEARTBEAT_CONFIGURATION config = (PHEARTBEAT_CONFIGURATION)DeferredContext;
IoQueueWorkItem( IoQueueWorkItem(
config->work_item, HeartbeatWorkItem, NormalWorkQueue, config); config->work_item, HeartbeatWorkItem, NormalWorkQueue, config);
} }

View file

@ -119,7 +119,7 @@ DeferredModuleHashingCallback(_In_ PDEVICE_OBJECT DeviceObject,
_In_opt_ PVOID Context); _In_opt_ PVOID Context);
VOID VOID
FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context); FindWinLogonProcess(_In_ PPROCESS_LIST_ENTRY Node, _In_opt_ PVOID Context);
NTSTATUS NTSTATUS
InitialiseHeartbeatConfiguration( InitialiseHeartbeatConfiguration(
@ -128,4 +128,9 @@ InitialiseHeartbeatConfiguration(
VOID VOID
FreeHeartbeatConfiguration(_Inout_ PHEARTBEAT_CONFIGURATION Configuration); FreeHeartbeatConfiguration(_Inout_ PHEARTBEAT_CONFIGURATION Configuration);
NTSTATUS
HashUserModule(_In_ PPROCESS_MAP_MODULE_ENTRY Entry,
_Out_ PVOID OutBuffer,
_In_ UINT32 OutBufferSize);
#endif #endif

View file

@ -12,6 +12,7 @@
#include "list.h" #include "list.h"
#include "session.h" #include "session.h"
#include "hw.h" #include "hw.h"
#include "map.h"
STATIC STATIC
NTSTATUS NTSTATUS
@ -446,19 +447,20 @@ SharedMappingWorkRoutine(_In_ PDEVICE_OBJECT DeviceObject,
/* can maybe implement this better so we can extract a status /* can maybe implement this better so we can extract a status
* value */ * value */
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles, NULL); RtlEnumerateHashmap(GetProcessHashmap(), EnumerateProcessHandles, NULL);
break; break;
case ssScanForUnlinkedProcesses: case ssScanForUnlinkedProcesses:
DEBUG_INFO( // DEBUG_INFO(
"SHARED_STATE_OPERATION_ID: ScanForUnlinkedProcesses Received"); // "SHARED_STATE_OPERATION_ID: ScanForUnlinkedProcesses Received");
status = FindUnlinkedProcesses(); // status = FindUnlinkedProcesses();
if (!NT_SUCCESS(status)) // if (!NT_SUCCESS(status))
DEBUG_ERROR("FindUnlinkedProcesses failed with status %x", status); // DEBUG_ERROR("FindUnlinkedProcesses failed with status %x",
// status);
break; break;
@ -896,7 +898,7 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
/* can maybe implement this better so we can extract a status /* can maybe implement this better so we can extract a status
* value */ * value */
EnumerateProcessListWithCallbackRoutine(EnumerateProcessHandles, NULL); RtlEnumerateHashmap(GetProcessHashmap(), EnumerateProcessHandles, NULL);
break; break;
@ -961,12 +963,13 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
case IOCTL_SCAN_FOR_UNLINKED_PROCESS: case IOCTL_SCAN_FOR_UNLINKED_PROCESS:
DEBUG_INFO("IOCTL_SCAN_FOR_UNLINKED_PROCESS Received"); // DEBUG_INFO("IOCTL_SCAN_FOR_UNLINKED_PROCESS Received");
status = FindUnlinkedProcesses(); // status = FindUnlinkedProcesses();
if (!NT_SUCCESS(status)) // if (!NT_SUCCESS(status))
DEBUG_ERROR("FindUnlinkedProcesses failed with status %x", status); // DEBUG_ERROR("FindUnlinkedProcesses failed with status %x",
// status);
break; break;
@ -1124,11 +1127,20 @@ DeviceControl(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
DEBUG_INFO("IOCTL_VALIDATE_PCI_DEVICES Received"); DEBUG_INFO("IOCTL_VALIDATE_PCI_DEVICES Received");
status = ValidatePciDevices(); status = ImpPsCreateSystemThread(&handle,
PROCESS_ALL_ACCESS,
NULL,
NULL,
NULL,
ValidatePciDevices,
NULL);
if (!NT_SUCCESS(status)) if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ValidatePciDevices failed with status %x", status); DEBUG_ERROR("PsCreateSystemThread failed with status %x", status);
goto end;
}
ImpZwClose(handle);
break; break;
case IOCTL_VALIDATE_WIN32K_TABLES: case IOCTL_VALIDATE_WIN32K_TABLES:
@ -1179,7 +1191,6 @@ DeviceCreate(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp)
PAGED_CODE(); PAGED_CODE();
UNREFERENCED_PARAMETER(DeviceObject); UNREFERENCED_PARAMETER(DeviceObject);
DEBUG_INFO("Handle to driver opened."); DEBUG_INFO("Handle to driver opened.");
// NTSTATUS status = ValidatePciDevices(); // NTSTATUS status = ValidatePciDevices();
// if (!NT_SUCCESS(status)) // if (!NT_SUCCESS(status))

241
driver/map.c Normal file
View file

@ -0,0 +1,241 @@
#include "map.h"
NTSTATUS
RtlCreateHashmap(_In_ UINT32 BucketCount,
_In_ UINT32 EntryObjectSize,
_In_ HASH_FUNCTION HashFunction,
_In_ COMPARE_FUNCTION CompareFunction,
_In_ PVOID Context,
_Out_ PRTL_HASHMAP Hashmap)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
UINT32 entry_size = sizeof(RTL_HASHMAP_ENTRY) + EntryObjectSize;
PRTL_HASHMAP_ENTRY entry = NULL;
Hashmap->buckets = ExAllocatePool2(
POOL_FLAG_NON_PAGED, BucketCount * entry_size, POOL_TAG_HASHMAP);
if (!Hashmap->buckets)
return STATUS_INSUFFICIENT_RESOURCES;
for (UINT32 index = 0; index < BucketCount; index++) {
entry = &Hashmap->buckets[index];
entry->in_use = FALSE;
InitializeListHead(&entry->entry);
}
KeInitializeGuardedMutex(&Hashmap->lock);
Hashmap->bucket_count = BucketCount;
Hashmap->hash_function = HashFunction;
Hashmap->compare_function = CompareFunction;
Hashmap->object_size = EntryObjectSize;
Hashmap->active = TRUE;
Hashmap->context = Context;
return STATUS_SUCCESS;
}
FORCEINLINE
STATIC
PRTL_HASHMAP_ENTRY
RtlFindUnusedHashmapEntry(_In_ PRTL_HASHMAP_ENTRY Head)
{
PRTL_HASHMAP_ENTRY entry = Head;
while (entry) {
if (entry->in_use == FALSE)
return entry;
entry = CONTAINING_RECORD(entry->entry.Flink, RTL_HASHMAP_ENTRY, entry);
}
return NULL;
}
FORCEINLINE
STATIC
PRTL_HASHMAP_ENTRY
RtlAllocateBucketListEntry(_In_ PRTL_HASHMAP Hashmap)
{
PRTL_HASHMAP_ENTRY entry =
ExAllocatePool2(POOL_FLAG_NON_PAGED,
Hashmap->object_size + sizeof(RTL_HASHMAP_ENTRY),
POOL_TAG_HASHMAP);
if (!entry)
return NULL;
entry->in_use = TRUE;
return entry;
}
FORCEINLINE
STATIC
BOOLEAN
RtlIsIndexInHashmapRange(_In_ PRTL_HASHMAP Hashmap, _In_ UINT32 Index)
{
return Index < Hashmap->bucket_count ? TRUE : FALSE;
}
/* assumes map lock is held */
PVOID
RtlInsertEntryHashmap(_In_ PRTL_HASHMAP Hashmap, _In_ UINT64 Key)
{
UINT32 index = 0;
PLIST_ENTRY list_head = NULL;
PLIST_ENTRY list_entry = NULL;
PRTL_HASHMAP_ENTRY entry = NULL;
PRTL_HASHMAP_ENTRY new_entry = NULL;
index = Hashmap->hash_function(Key);
if (!RtlIsIndexInHashmapRange(Hashmap, index)) {
DEBUG_ERROR("Key is not in range of buckets");
return NULL;
}
list_head = &(&Hashmap->buckets[index])->entry;
list_entry = list_head->Flink;
while (list_entry != list_head) {
entry = CONTAINING_RECORD(list_entry, RTL_HASHMAP_ENTRY, entry);
if (entry->in_use == FALSE) {
entry->in_use = TRUE;
return entry->object;
}
list_entry = list_entry->Flink;
}
new_entry = RtlAllocateBucketListEntry(Hashmap);
if (!new_entry) {
DEBUG_ERROR("Failed to allocate new entry");
return NULL;
}
InsertHeadList(list_head, &new_entry->entry);
return new_entry->object;
}
/* Returns a pointer to the start of the entries caller defined data. i.e
* &PRTL_HASHMAP_ENTRY->Object
*
* Also assumes lock is held.
*/
PVOID
RtlLookupEntryHashmap(_In_ PRTL_HASHMAP Hashmap,
_In_ UINT64 Key,
_In_ PVOID Compare)
{
UINT32 index = 0;
PRTL_HASHMAP_ENTRY entry = NULL;
index = Hashmap->hash_function(Key);
if (!RtlIsIndexInHashmapRange(Hashmap, index)) {
DEBUG_ERROR("Key is not in range of buckets");
return NULL;
}
entry = &Hashmap->buckets[index];
while (entry) {
if (entry->in_use == FALSE)
goto increment;
if (Hashmap->compare_function(entry->object, Compare))
return entry->object;
increment:
entry = CONTAINING_RECORD(entry->entry.Flink, RTL_HASHMAP_ENTRY, entry);
}
DEBUG_ERROR("Unable to find entry in hashmap.");
return NULL;
}
/* Assumes lock is held */
BOOLEAN
RtlDeleteEntryHashmap(_In_ PRTL_HASHMAP Hashmap,
_In_ UINT64 Key,
_In_ PVOID Compare)
{
UINT32 index = 0;
PRTL_HASHMAP_ENTRY entry = NULL;
PRTL_HASHMAP_ENTRY next = NULL;
index = Hashmap->hash_function(Key);
if (!RtlIsIndexInHashmapRange(Hashmap, index)) {
DEBUG_ERROR("Key is not in range of buckets");
return FALSE;
}
entry = &Hashmap->buckets[index];
while (entry) {
if (entry->in_use == FALSE) {
next =
CONTAINING_RECORD(entry->entry.Flink, RTL_HASHMAP_ENTRY, entry);
if (next == &Hashmap->buckets[index])
break;
entry = next;
continue;
}
if (Hashmap->compare_function(entry->object, Compare)) {
if (entry == &Hashmap->buckets[index]) {
entry->in_use = FALSE;
}
else {
RemoveEntryList(&entry->entry);
ExFreePoolWithTag(entry, POOL_TAG_HASHMAP);
}
return TRUE;
}
next = CONTAINING_RECORD(entry->entry.Flink, RTL_HASHMAP_ENTRY, entry);
if (next == &Hashmap->buckets[index])
break;
entry = next;
}
return FALSE;
}
VOID
RtlEnumerateHashmap(_In_ PRTL_HASHMAP Hashmap,
_In_ ENUMERATE_HASHMAP EnumerationCallback,
_In_opt_ PVOID Context)
{
PRTL_HASHMAP_ENTRY entry = NULL;
for (UINT32 index = 0; index < Hashmap->bucket_count; index++) {
PLIST_ENTRY list_head = &Hashmap->buckets[index];
PLIST_ENTRY list_entry = list_head->Flink;
while (list_entry != list_head) {
entry = CONTAINING_RECORD(list_entry, RTL_HASHMAP_ENTRY, entry);
if (entry->in_use == TRUE) {
EnumerationCallback(entry->object, Context);
}
list_entry = list_entry->Flink;
}
}
}
VOID
RtlDeleteHashmap(_In_ PRTL_HASHMAP Hashmap)
{
ExFreePoolWithTag(Hashmap->buckets, POOL_TAG_HASHMAP);
}

78
driver/map.h Normal file
View file

@ -0,0 +1,78 @@
#ifndef MAP_H
#define MAP_H
#include "common.h"
typedef UINT32 (*HASH_FUNCTION)(_In_ UINT64 Key);
/* Struct1 being the node being compared to the value in Struct 2*/
typedef BOOLEAN (*COMPARE_FUNCTION)(_In_ PVOID Struct1, _In_ PVOID Struct2);
/* To improve efficiency, each entry contains a common header
* RTL_HASHMAP_ENTRY*, reducing the need to store a seperate pointer to the
* entrys data. */
typedef struct _RTL_HASHMAP_ENTRY {
LIST_ENTRY entry;
UINT32 in_use;
CHAR object[];
} RTL_HASHMAP_ENTRY, *PRTL_HASHMAP_ENTRY;
typedef VOID (*ENUMERATE_HASHMAP)(_In_ PRTL_HASHMAP_ENTRY Entry,
_In_opt_ PVOID Context);
typedef struct _RTL_HASHMAP {
/* Array of RTL_HASHMAP_ENTRIES with length = bucket_count */
PRTL_HASHMAP_ENTRY buckets;
/* Number of buckets, ideally a prime number */
UINT32 bucket_count;
/* Size of each custom object existing after the RTL_HASHMAP_ENTRY */
UINT32 object_size;
/* Pointer to caller-designated callback routines */
HASH_FUNCTION hash_function;
COMPARE_FUNCTION compare_function;
KGUARDED_MUTEX lock;
/* in the future bucket entries will use this */
LOOKASIDE_LIST_EX pool;
/* user allocated context */
PVOID context;
volatile UINT32 active;
} RTL_HASHMAP, *PRTL_HASHMAP;
/* Hashmap is caller allocated */
NTSTATUS
RtlCreateHashmap(_In_ UINT32 BucketCount,
_In_ UINT32 EntryObjectSize,
_In_ HASH_FUNCTION HashFunction,
_In_ COMPARE_FUNCTION CompareFunction,
_In_ PVOID Context,
_Out_ PRTL_HASHMAP Hashmap);
PVOID
RtlInsertEntryHashmap(_In_ PRTL_HASHMAP Hashmap, _In_ UINT64 Key);
PVOID
RtlLookupEntryHashmap(_In_ PRTL_HASHMAP Hashmap,
_In_ UINT64 Key,
_In_ PVOID Compare);
BOOLEAN
RtlDeleteEntryHashmap(_In_ PRTL_HASHMAP Hashmap,
_In_ UINT64 Key,
_In_ PVOID Compare);
VOID
RtlEnumerateHashmap(_In_ PRTL_HASHMAP Hashmap,
_In_ ENUMERATE_HASHMAP EnumerationCallback,
_In_opt_ PVOID Context);
VOID
RtlDeleteHashmap(_In_ PRTL_HASHMAP Hashmap);
#endif

View file

@ -1377,15 +1377,12 @@ end:
/* todo: walk the chain of pointers to prevent jmp chaining */ /* todo: walk the chain of pointers to prevent jmp chaining */
STATIC STATIC
NTSTATUS VOID
ValidateTableDispatchRoutines(_In_ PVOID* Base, ValidateTableDispatchRoutines(_In_ PVOID* Base,
_In_ UINT32 Entries, _In_ UINT32 Entries,
_In_ PSYSTEM_MODULES Modules, _In_ PSYSTEM_MODULES Modules,
_Out_ PVOID* Routine) _Out_ PVOID* Routine)
{ {
NTSTATUS status = STATUS_UNSUCCESSFUL;
BOOLEAN flag = FALSE;
for (UINT32 index = 0; index < Entries; index++) { for (UINT32 index = 0; index < Entries; index++) {
if (!Base[index]) if (!Base[index])
continue; continue;
@ -1393,8 +1390,6 @@ ValidateTableDispatchRoutines(_In_ PVOID* Base,
if (IsInstructionPointerInInvalidRegion(Base[index], Modules)) if (IsInstructionPointerInInvalidRegion(Base[index], Modules))
*Routine = Base[index]; *Routine = Base[index];
} }
return status;
} }
/* /*
@ -1447,24 +1442,14 @@ ValidateHalPrivateDispatchTable(_Out_ PVOID* Routine,
base = (UINT64)table + sizeof(UINT64); base = (UINT64)table + sizeof(UINT64);
count = GetHalPrivateDispatchTableRoutineCount(&os_info); count = GetHalPrivateDispatchTableRoutineCount(&os_info);
status = ValidateTableDispatchRoutines(base, count, Modules, Routine); ValidateTableDispatchRoutines(base, count, Modules, Routine);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ValidateTableDispatchRoutines failed with status %x",
status);
return status;
}
return status; return status;
} }
STATIC STATIC
NTSTATUS VOID
ValidateHalDispatchTable(_Out_ PVOID* Routine, _In_ PSYSTEM_MODULES Modules) ValidateHalDispatchTable(_Out_ PVOID* Routine, _In_ PSYSTEM_MODULES Modules)
{ {
NTSTATUS status = STATUS_UNSUCCESSFUL;
BOOLEAN flag = FALSE;
*Routine = NULL; *Routine = NULL;
DEBUG_VERBOSE("Validating HalDispatchTable."); DEBUG_VERBOSE("Validating HalDispatchTable.");
@ -1488,7 +1473,7 @@ ValidateHalDispatchTable(_Out_ PVOID* Routine, _In_ PSYSTEM_MODULES Modules)
goto end; goto end;
} }
if (IsInstructionPointerInInvalidRegion(HalQueryBusSlots, Modules)) { if (IsInstructionPointerInInvalidRegion(HalQueryBusSlots, Modules)) {
*Routine = HalQueryBusSlots; *Routine = HalQueryBusSlots;
goto end; goto end;
} }
@ -1573,7 +1558,7 @@ ValidateHalDispatchTable(_Out_ PVOID* Routine, _In_ PSYSTEM_MODULES Modules)
} }
end: end:
return status; return;
} }
STATIC STATIC
@ -1627,12 +1612,7 @@ ValidateHalDispatchTables()
return status; return status;
} }
status = ValidateHalDispatchTable(&routine1, &modules); ValidateHalDispatchTable(&routine1, &modules);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ValidateHalDispatchTable failed with status %x", status);
goto end;
}
if (routine1) if (routine1)
ReportDataTableInvalidRoutine(HalDispatch, routine1); ReportDataTableInvalidRoutine(HalDispatch, routine1);
@ -1977,7 +1957,7 @@ ValidateWin32kBase_gDxgInterface()
goto end; goto end;
} }
EnumerateProcessListWithCallbackRoutine(FindWinLogonProcess, &winlogon); RtlEnumerateHashmap(GetProcessHashmap(), FindWinLogonProcess, &winlogon);
if (!winlogon) { if (!winlogon) {
status = STATUS_UNSUCCESSFUL; status = STATUS_UNSUCCESSFUL;

View file

@ -1,5 +1,19 @@
#include "pe.h" #include "pe.h"
PNT_HEADER_64
PeGetNtHeaderSafe(_In_ PVOID Image)
{
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)Image;
if (!MmIsAddressValid(Image))
return NULL;
if (dos->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
return CONVERT_RELATIVE_ADDRESS(PNT_HEADER_64, Image, dos->e_lfanew);
}
PNT_HEADER_64 PNT_HEADER_64
PeGetNtHeader(_In_ PVOID Image) PeGetNtHeader(_In_ PVOID Image)
{ {
@ -23,6 +37,21 @@ PeGetExportDataDirectory(_In_ PVOID Image)
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
} }
PIMAGE_DATA_DIRECTORY
PeGetExportDataDirectorySafe(_In_ PVOID Image)
{
PNT_HEADER_64 nt = PeGetNtHeader(Image);
if (!MmIsAddressValid(Image))
return NULL;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= nt->OptionalHeader.NumberOfRvaAndSizes)
return NULL;
return (PIMAGE_DATA_DIRECTORY)&nt->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
}
PIMAGE_EXPORT_DIRECTORY PIMAGE_EXPORT_DIRECTORY
PeGetExportDirectory(_In_ PVOID Image, PeGetExportDirectory(_In_ PVOID Image,
_In_ PIMAGE_DATA_DIRECTORY ExportDataDirectory) _In_ PIMAGE_DATA_DIRECTORY ExportDataDirectory)
@ -34,12 +63,35 @@ PeGetExportDirectory(_In_ PVOID Image,
PIMAGE_EXPORT_DIRECTORY, Image, ExportDataDirectory->VirtualAddress); PIMAGE_EXPORT_DIRECTORY, Image, ExportDataDirectory->VirtualAddress);
} }
PIMAGE_EXPORT_DIRECTORY
PeGetExportDirectorySafe(_In_ PVOID Image,
_In_ PIMAGE_DATA_DIRECTORY ExportDataDirectory)
{
if (!MmIsAddressValid(Image))
return NULL;
if (!ExportDataDirectory->VirtualAddress || !ExportDataDirectory->Size)
return NULL;
return CONVERT_RELATIVE_ADDRESS(
PIMAGE_EXPORT_DIRECTORY, Image, ExportDataDirectory->VirtualAddress);
}
UINT32 UINT32
GetSectionCount(_In_ PNT_HEADER_64 Header) GetSectionCount(_In_ PNT_HEADER_64 Header)
{ {
return Header->FileHeader.NumberOfSections; return Header->FileHeader.NumberOfSections;
} }
UINT32
GetSectionCountSafe(_In_ PNT_HEADER_64 Header)
{
if (!MmIsAddressValid(Header))
return NULL;
return Header->FileHeader.NumberOfSections;
}
PVOID PVOID
PeFindExportByName(_In_ PVOID Image, _In_ PCHAR Name) PeFindExportByName(_In_ PVOID Image, _In_ PCHAR Name)
{ {

View file

@ -22,4 +22,17 @@ PeGetExportDirectory(_In_ PVOID Image,
UINT32 UINT32
GetSectionCount(_In_ PNT_HEADER_64 Header); GetSectionCount(_In_ PNT_HEADER_64 Header);
PIMAGE_EXPORT_DIRECTORY
PeGetExportDirectorySafe(_In_ PVOID Image,
_In_ PIMAGE_DATA_DIRECTORY ExportDataDirectory);
PIMAGE_DATA_DIRECTORY
PeGetExportDataDirectorySafe(_In_ PVOID Image);
PNT_HEADER_64
PeGetNtHeaderSafe(_In_ PVOID Image);
UINT32
GetSectionCountSafe(_In_ PNT_HEADER_64 Header);
#endif #endif

View file

@ -83,13 +83,12 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context);
STATIC STATIC
VOID VOID
IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY Node, _In_opt_ PVOID Context);
_Inout_opt_ PVOID Context);
STATIC STATIC
VOID VOID
CheckIfProcessAllocationIsInProcessList( CheckIfProcessAllocationIsInProcessList(_In_ PPROCESS_LIST_ENTRY Node,
_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _Inout_opt_ PVOID Context); _In_opt_ PVOID Context);
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
# pragma alloc_text(PAGE, GetGlobalDebuggerData) # pragma alloc_text(PAGE, GetGlobalDebuggerData)
@ -629,12 +628,11 @@ WalkKernelPageTables(_In_ PPROCESS_SCAN_CONTEXT Context)
STATIC STATIC
VOID VOID
IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry, IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY Node, _In_opt_ PVOID Context)
_Inout_opt_ PVOID Context)
{ {
PAGED_CODE(); PAGED_CODE();
UNREFERENCED_PARAMETER(ProcessListEntry); UNREFERENCED_PARAMETER(Node);
PPROCESS_SCAN_CONTEXT context = (PPROCESS_SCAN_CONTEXT)Context; PPROCESS_SCAN_CONTEXT context = (PPROCESS_SCAN_CONTEXT)Context;
@ -646,8 +644,8 @@ IncrementProcessCounter(_In_ PPROCESS_LIST_ENTRY ProcessListEntry,
STATIC STATIC
VOID VOID
CheckIfProcessAllocationIsInProcessList( CheckIfProcessAllocationIsInProcessList(_In_ PPROCESS_LIST_ENTRY Node,
_In_ PPROCESS_LIST_ENTRY ProcessListEntry, _Inout_opt_ PVOID Context) _In_opt_ PVOID Context)
{ {
PAGED_CODE(); PAGED_CODE();
@ -660,9 +658,9 @@ CheckIfProcessAllocationIsInProcessList(
for (INT i = 0; i < context->process_count; i++) { for (INT i = 0; i < context->process_count; i++) {
allocation_address = (PUINT64)context->process_buffer; allocation_address = (PUINT64)context->process_buffer;
if ((UINT64)ProcessListEntry->process >= if ((UINT64)Node->process >=
allocation_address[i] - PROCESS_OBJECT_ALLOCATION_MARGIN && allocation_address[i] - PROCESS_OBJECT_ALLOCATION_MARGIN &&
(UINT64)ProcessListEntry->process <= (UINT64)Node->process <=
allocation_address[i] + PROCESS_OBJECT_ALLOCATION_MARGIN) { allocation_address[i] + PROCESS_OBJECT_ALLOCATION_MARGIN) {
RtlZeroMemory((UINT64)context->process_buffer + i * sizeof(UINT64), RtlZeroMemory((UINT64)context->process_buffer + i * sizeof(UINT64),
sizeof(UINT64)); sizeof(UINT64));
@ -686,7 +684,7 @@ FindUnlinkedProcesses()
UINT32 packet_size = CryptRequestRequiredBufferLength( UINT32 packet_size = CryptRequestRequiredBufferLength(
sizeof(INVALID_PROCESS_ALLOCATION_REPORT)); sizeof(INVALID_PROCESS_ALLOCATION_REPORT));
EnumerateProcessListWithCallbackRoutine(IncrementProcessCounter, &context); RtlEnumerateHashmap(GetProcessHashmap(), IncrementProcessCounter, &context);
if (context.process_count == 0) { if (context.process_count == 0) {
DEBUG_ERROR("IncrementProcessCounter failed with no status."); DEBUG_ERROR("IncrementProcessCounter failed with no status.");
@ -703,8 +701,8 @@ FindUnlinkedProcesses()
WalkKernelPageTables(&context); WalkKernelPageTables(&context);
EnumerateProcessListWithCallbackRoutine( RtlEnumerateHashmap(
CheckIfProcessAllocationIsInProcessList, &context); GetProcessHashmap(), CheckIfProcessAllocationIsInProcessList, &context);
allocation_address = (PUINT64)context.process_buffer; allocation_address = (PUINT64)context.process_buffer;

View file

@ -2,6 +2,7 @@
#include "imports.h" #include "imports.h"
#include "crypt.h" #include "crypt.h"
#include "util.h"
NTSTATUS NTSTATUS
SessionInitialiseStructure() SessionInitialiseStructure()
@ -83,6 +84,34 @@ SessionTerminate()
KeReleaseGuardedMutex(&session->lock); KeReleaseGuardedMutex(&session->lock);
} }
/* Return type for this doesnt matter */
STATIC
BOOLEAN
HashOurUserModuleOnEntryCallback(_In_ PPROCESS_MAP_MODULE_ENTRY Entry,
_In_opt_ PVOID Context)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PACTIVE_SESSION session = (PACTIVE_SESSION)Context;
if (!ARGUMENT_PRESENT(Context))
return FALSE;
status = HashUserModule(Entry,
session->module.module_hash,
sizeof(session->module.module_hash));
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("HashUserModule: %lx", status);
return FALSE;
}
DEBUG_VERBOSE("User module hashed!");
DumpBufferToKernelDebugger(session->module.module_hash,
sizeof(session->module.module_hash));
return TRUE;
}
NTSTATUS NTSTATUS
SessionInitialise(_In_ PIRP Irp) SessionInitialise(_In_ PIRP Irp)
{ {
@ -94,7 +123,8 @@ SessionInitialise(_In_ PIRP Irp)
DEBUG_VERBOSE("Initialising new session."); DEBUG_VERBOSE("Initialising new session.");
status = ValidateIrpInputBuffer(Irp, sizeof(SESSION_INITIATION_PACKET)); status = ValidateIrpInputBuffer(
Irp, sizeof(SESSION_INITIATION_PACKET) - SHA_256_HASH_LENGTH);
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ValidateIrpInputBuffer failed with status %x", status); DEBUG_ERROR("ValidateIrpInputBuffer failed with status %x", status);
@ -123,6 +153,16 @@ SessionInitialise(_In_ PIRP Irp)
RtlCopyMemory(session->aes_key, initiation->aes_key, AES_256_KEY_SIZE); RtlCopyMemory(session->aes_key, initiation->aes_key, AES_256_KEY_SIZE);
RtlCopyMemory(session->iv, initiation->aes_iv, AES_256_IV_SIZE); RtlCopyMemory(session->iv, initiation->aes_iv, AES_256_IV_SIZE);
session->module.base_address = initiation->module_info.base_address;
session->module.size = initiation->module_info.size;
RtlCopyMemory(
session->module.path, initiation->module_info.path, MAX_MODULE_PATH);
DEBUG_VERBOSE("Module base: %llx", session->module.base_address);
DEBUG_VERBOSE("Module size: %lx ", session->module.size);
DEBUG_VERBOSE("Module path: %s", session->module.path);
status = CryptInitialiseSessionCryptObjects(); status = CryptInitialiseSessionCryptObjects();
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
@ -137,6 +177,8 @@ SessionInitialise(_In_ PIRP Irp)
goto end; goto end;
} }
FindOurUserModeModuleEntry(HashOurUserModuleOnEntryCallback, session);
end: end:
KeReleaseGuardedMutex(&session->lock); KeReleaseGuardedMutex(&session->lock);
return status; return status;

View file

@ -40,4 +40,68 @@ MapAndReadPhysical(_In_ UINT64 PhysicalAddress,
MmUnmapIoSpace(va, ReadLength); MmUnmapIoSpace(va, ReadLength);
return STATUS_SUCCESS; return STATUS_SUCCESS;
}
NTSTATUS
UnicodeToCharBufString(_In_ PUNICODE_STRING UnicodeString,
_Out_ PVOID OutBuffer,
_In_ UINT32 OutBufferSize)
{
ANSI_STRING string = {0};
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = RtlUnicodeStringToAnsiString(&string, UnicodeString, TRUE);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("RtlUnicodeStringToAnsiString: %x", status);
return status;
}
if (string.Length > OutBufferSize) {
RtlFreeAnsiString(&string);
return STATUS_BUFFER_TOO_SMALL;
}
RtlCopyMemory(OutBuffer, string.Buffer, string.Length);
RtlFreeAnsiString(&string);
return STATUS_SUCCESS;
}
#define BYTES_PER_LINE 16
VOID
DumpBufferToKernelDebugger(_In_ PCHAR Buffer, _In_ UINT32 BufferLength)
{
UINT32 i = 0;
UINT32 j = 0;
for (i = 0; i < BufferLength; i += BYTES_PER_LINE) {
HEX_DUMP("%08x ", i);
for (j = 0; j < BYTES_PER_LINE; ++j) {
if (i + j < BufferLength) {
HEX_DUMP("%02x ", (unsigned char)Buffer[i + j]);
}
else {
HEX_DUMP(" ");
}
}
HEX_DUMP(" ");
for (j = 0; j < BYTES_PER_LINE; ++j) {
if (i + j < BufferLength) {
char c = Buffer[i + j];
if (c >= 32 && c <= 126) {
HEX_DUMP("%c", c);
}
else {
HEX_DUMP(".");
}
}
}
HEX_DUMP("\n");
}
} }

View file

@ -12,4 +12,12 @@ MapAndReadPhysical(_In_ UINT64 PhysicalAddress,
_Out_ PVOID OutputBuffer, _Out_ PVOID OutputBuffer,
_In_ UINT32 OutputBufferLength); _In_ UINT32 OutputBufferLength);
NTSTATUS
UnicodeToCharBufString(_In_ PUNICODE_STRING UnicodeString,
_Out_ PVOID OutBuffer,
_In_ UINT32 OutBufferSize);
VOID
DumpBufferToKernelDebugger(_In_ PCHAR Buffer, _In_ UINT32 BufferLength);
#endif #endif

View file

@ -1,16 +1,19 @@
#include "dispatcher.h" #include "dispatcher.h"
#include "../client/message_queue.h" #include "../client/message_queue.h"
#include "../helper.h"
#include "../crypt/crypt.h" #include "../crypt/crypt.h"
#include "../helper.h"
#include <bcrypt.h> #include <bcrypt.h>
#include <chrono> #include <chrono>
dispatcher::dispatcher::dispatcher(LPCWSTR driver_name, dispatcher::dispatcher::dispatcher(LPCWSTR driver_name,
client::message_queue &message_queue) client::message_queue &message_queue,
module::module_information *module_info)
: thread_pool(DISPATCHER_THREAD_COUNT), : thread_pool(DISPATCHER_THREAD_COUNT),
k_interface(driver_name, message_queue) {} k_interface(driver_name, message_queue, module_info) {
this->module_info = module_info;
}
void dispatcher::dispatcher::request_session_pk() { void dispatcher::dispatcher::request_session_pk() {
#ifdef NO_SERVER #ifdef NO_SERVER
@ -56,7 +59,7 @@ void dispatcher::dispatcher::run() {
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) {
LOG_INFO("issueing kernel job!"); LOG_INFO("issueing kernel job!");
this->issue_kernel_job(); this->issue_kernel_job();
helper::sleep_thread(DISPATCH_LOOP_SLEEP_TIME); helper::sleep_thread(DISPATCH_LOOP_SLEEP_TIME);
} }

View file

@ -3,8 +3,11 @@
#include "threadpool.h" #include "threadpool.h"
#include "timer.h" #include "timer.h"
#include "../kernel_interface/kernel_interface.h" #include "../kernel_interface/kernel_interface.h"
#include "../module.h"
namespace dispatcher { namespace dispatcher {
constexpr int DISPATCH_LOOP_SLEEP_TIME = 30; constexpr int DISPATCH_LOOP_SLEEP_TIME = 30;
@ -18,6 +21,7 @@ class dispatcher {
timer timers; timer timers;
thread_pool thread_pool; thread_pool thread_pool;
kernel_interface::kernel_interface k_interface; kernel_interface::kernel_interface k_interface;
module::module_information *module_info;
void issue_kernel_job(); void issue_kernel_job();
void write_shared_mapping_operation(); void write_shared_mapping_operation();
@ -27,7 +31,7 @@ class dispatcher {
void request_session_pk(); void request_session_pk();
public: public:
dispatcher(LPCWSTR driver_name, client::message_queue &queue); dispatcher(LPCWSTR driver_name, client::message_queue &queue, module::module_information* module_info);
void run(); void run();
}; };
} // namespace dispatcher } // namespace dispatcher

View file

@ -3,8 +3,8 @@
#include <iostream> #include <iostream>
#include "../common.h" #include "../common.h"
#include "../helper.h"
#include "../crypt/crypt.h" #include "../crypt/crypt.h"
#include "../helper.h"
#include <TlHelp32.h> #include <TlHelp32.h>
#include <winternl.h> #include <winternl.h>
@ -95,9 +95,11 @@ void *kernel_interface::kernel_interface::get_buffer_from_event_object(
} }
kernel_interface::kernel_interface::kernel_interface( kernel_interface::kernel_interface::kernel_interface(
LPCWSTR driver_name, client::message_queue &queue) LPCWSTR driver_name, client::message_queue &queue,
module::module_information *module_info)
: message_queue(queue) { : message_queue(queue) {
this->driver_name = driver_name; this->driver_name = driver_name;
this->module_info = module_info;
this->port = INVALID_HANDLE_VALUE; this->port = INVALID_HANDLE_VALUE;
this->driver_handle = CreateFileW( this->driver_handle = CreateFileW(
driver_name, GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE, 0, 0, driver_name, GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE, 0, 0,
@ -146,6 +148,8 @@ void kernel_interface::kernel_interface::notify_driver_on_process_launch() {
packet.session_cookie = 123; packet.session_cookie = 123;
memcpy(packet.aes_key, crypt::get_test_key(), 32); memcpy(packet.aes_key, crypt::get_test_key(), 32);
memcpy(packet.aes_iv, crypt::get_test_iv(), 16); memcpy(packet.aes_iv, crypt::get_test_iv(), 16);
memcpy(&packet.module_info, (void*)this->module_info,
sizeof(module::module_information));
generic_driver_call_input(ioctl_code::NotifyDriverOnProcessLaunch, &packet, generic_driver_call_input(ioctl_code::NotifyDriverOnProcessLaunch, &packet,
sizeof(session_initiation_packet), &bytes_returned); sizeof(session_initiation_packet), &bytes_returned);
} }

View file

@ -4,6 +4,8 @@
#include "../client/message_queue.h" #include "../client/message_queue.h"
#include "../module.h"
namespace kernel_interface { namespace kernel_interface {
static constexpr int EVENT_COUNT = 5; static constexpr int EVENT_COUNT = 5;
@ -130,17 +132,17 @@ struct process_module_validation_report {
}; };
struct system_module_integrity_check_report { struct system_module_integrity_check_report {
report_header header; report_header header;
uint64_t image_base; uint64_t image_base;
uint32_t image_size; uint32_t image_size;
char path_name[0x100]; char path_name[0x100];
}; };
struct driver_self_integrity_check_report { struct driver_self_integrity_check_report {
report_header header; report_header header;
uint64_t image_base; uint64_t image_base;
uint32_t image_size; uint32_t image_size;
char path_name[0x100]; char path_name[0x100];
}; };
struct heartbeat_packet { struct heartbeat_packet {
@ -152,10 +154,10 @@ struct heartbeat_packet {
}; };
struct blacklisted_pcie_device_report { struct blacklisted_pcie_device_report {
report_header header; report_header header;
uint64_t device_object; uint64_t device_object;
uint16_t device_id; uint16_t device_id;
uint16_t vendor_id; uint16_t vendor_id;
}; };
enum apc_operation { operation_stackwalk = 0x1 }; enum apc_operation { operation_stackwalk = 0x1 };
@ -224,6 +226,7 @@ class kernel_interface {
void *process_id; void *process_id;
unsigned char aes_key[32]; unsigned char aes_key[32];
unsigned char aes_iv[16]; unsigned char aes_iv[16];
struct module::module_information module_info;
}; };
struct hv_detection_packet { struct hv_detection_packet {
@ -247,6 +250,7 @@ class kernel_interface {
HANDLE port; HANDLE port;
std::mutex lock; std::mutex lock;
std::vector<event_dispatcher> events; std::vector<event_dispatcher> events;
module::module_information* module_info;
struct shared_data { struct shared_data {
unsigned __int32 status; unsigned __int32 status;
@ -278,7 +282,8 @@ class kernel_interface {
void generic_driver_call_apc(apc_operation operation); void generic_driver_call_apc(apc_operation operation);
public: public:
kernel_interface(LPCWSTR driver_name, client::message_queue &queue); kernel_interface(LPCWSTR driver_name, client::message_queue &queue,
module::module_information *module_info);
~kernel_interface(); ~kernel_interface();
void run_completion_port(); void run_completion_port();

View file

@ -6,6 +6,38 @@
#include "dispatcher/dispatcher.h" #include "dispatcher/dispatcher.h"
#include "crypt/crypt.h" #include "crypt/crypt.h"
#include <Psapi.h>
bool module::get_module_information(module_information *out) {
BOOL ret = FALSE;
HMODULE module = {0};
MODULEINFO info = {0};
ret = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCSTR)get_module_information, &module);
if (!ret)
return false;
ret = GetModuleInformation(GetCurrentProcess(), module, (LPMODULEINFO)&info,
sizeof(info));
if (!ret)
return false;
if (!GetModuleFileNameA(module, out->path, MAX_PATH))
return false;
out->base_address = info.lpBaseOfDll;
out->size = info.SizeOfImage;
LOG_INFO("base: %llx", out->base_address);
LOG_INFO("size: %lx", out->size);
LOG_INFO("path: %s", out->path);
return true;
}
void module::run(HINSTANCE hinstDLL) { void module::run(HINSTANCE hinstDLL) {
AllocConsole(); AllocConsole();
@ -16,8 +48,18 @@ void module::run(HINSTANCE hinstDLL) {
LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe"; LPTSTR pipe_name = (LPTSTR)L"\\\\.\\pipe\\DonnaACPipe";
LPCWSTR driver_name = L"\\\\.\\DonnaAC"; LPCWSTR driver_name = L"\\\\.\\DonnaAC";
module::module_information info = {0};
if (!module::get_module_information(&info)) {
LOG_ERROR("get_module_information: %x", GetLastError());
fclose(stdout);
fclose(stdin);
FreeConsole();
FreeLibraryAndExitThread(hinstDLL, 0);
return;
}
client::message_queue queue(pipe_name); client::message_queue queue(pipe_name);
dispatcher::dispatcher dispatch(driver_name, queue); dispatcher::dispatcher dispatch(driver_name, queue, &info);
dispatch.run(); dispatch.run();
fclose(stdout); fclose(stdout);

View file

@ -7,4 +7,12 @@
namespace module { namespace module {
void run(HINSTANCE hinstDLL); void run(HINSTANCE hinstDLL);
void terminate(); void terminate();
struct module_information {
void *base_address;
uint32_t size;
char path[MAX_PATH];
};
bool get_module_information(module_information *info);
} // namespace module } // namespace module