mirror-ac/driver/callbacks.c

1415 lines
38 KiB
C
Raw Permalink Normal View History

2023-08-20 16:12:04 +02:00
#include "callbacks.h"
2024-08-04 08:30:31 +02:00
#include "containers/map.h"
#include "containers/tree.h"
2024-08-01 06:21:53 +02:00
#include "crypt.h"
2024-08-04 08:30:31 +02:00
#include "driver.h"
#include "imports.h"
2024-08-04 08:30:31 +02:00
#include "lib/stdlib.h"
2024-08-01 06:21:53 +02:00
#include "modules.h"
#include "pool.h"
2024-01-31 08:32:13 +01:00
#include "session.h"
2024-08-01 06:21:53 +02:00
#include "thread.h"
#include "util.h"
#define PROCESS_HASHMAP_BUCKET_COUNT 101
2023-08-20 16:12:04 +02:00
2023-12-13 05:06:27 +01:00
STATIC
BOOLEAN
2024-08-01 06:21:53 +02:00
EnumHandleCallback(
_In_ PHANDLE_TABLE HandleTable,
_In_ PHANDLE_TABLE_ENTRY Entry,
_In_ HANDLE Handle,
_In_ PVOID Context);
2023-10-07 17:37:47 +02:00
#ifdef ALLOC_PRAGMA
2024-04-13 10:23:14 +02:00
# pragma alloc_text(PAGE, ObPostOpCallbackRoutine)
# pragma alloc_text(PAGE, ObPreOpCallbackRoutine)
# pragma alloc_text(PAGE, EnumHandleCallback)
# pragma alloc_text(PAGE, EnumerateProcessHandles)
# pragma alloc_text(PAGE, InitialiseThreadList)
# pragma alloc_text(PAGE, ExUnlockHandleTableEntry)
2023-10-07 17:37:47 +02:00
#endif
2023-10-12 13:27:40 +02:00
VOID
2023-12-13 05:06:27 +01:00
CleanupThreadListFreeCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry)
2023-10-12 13:27:40 +02:00
{
2024-04-13 10:23:14 +02:00
ImpObDereferenceObject(ThreadListEntry->thread);
ImpObDereferenceObject(ThreadListEntry->owning_process);
2023-10-12 13:27:40 +02:00
}
2023-12-13 05:06:27 +01:00
VOID
2024-01-14 05:31:19 +01:00
UnregisterProcessCreateNotifyRoutine()
2023-10-10 19:49:17 +02:00
{
2024-06-11 13:41:55 +02:00
RtlHashmapSetInactive(GetProcessHashmap());
2024-04-13 10:23:14 +02:00
ImpPsSetCreateProcessNotifyRoutine(ProcessCreateNotifyRoutine, TRUE);
2024-01-14 05:31:19 +01:00
}
VOID
UnregisterImageLoadNotifyRoutine()
{
2024-08-04 08:30:31 +02:00
InterlockedExchange(&GetDriverList()->active, FALSE);
2024-04-13 10:23:14 +02:00
PsRemoveLoadImageNotifyRoutine(ImageLoadNotifyRoutineCallback);
2024-01-14 05:31:19 +01:00
}
VOID
UnregisterThreadCreateNotifyRoutine()
{
2024-08-04 08:30:31 +02:00
InterlockedExchange(&GetThreadTree()->active, FALSE);
2024-04-13 10:23:14 +02:00
ImpPsRemoveCreateThreadNotifyRoutine(ThreadCreateNotifyRoutine);
2024-01-14 05:31:19 +01:00
}
2023-12-13 05:06:27 +01:00
2023-10-08 16:07:49 +02:00
VOID
CleanupThreadListOnDriverUnload()
{
2024-08-04 08:30:31 +02:00
RtlRbTreeEnumerate(GetThreadTree(), CleanupThreadListFreeCallback, NULL);
RtlRbTreeDeleteTree(GetThreadTree());
}
VOID
CleanupDriverListOnDriverUnload()
{
2024-08-01 06:21:53 +02:00
PLIST_ENTRY entry = NULL;
2024-08-04 08:30:31 +02:00
PDRIVER_LIST_HEAD head = GetDriverList();
2024-08-01 06:21:53 +02:00
PDRIVER_LIST_ENTRY driver = NULL;
ImpKeAcquireGuardedMutex(&head->lock);
while (!IsListEmpty(&head->list_entry)) {
entry = RemoveHeadList(&head->list_entry);
2024-08-01 06:21:53 +02:00
driver = CONTAINING_RECORD(entry, DRIVER_LIST_ENTRY, list_entry);
ExFreePoolWithTag(entry, POOL_TAG_DRIVER_LIST);
2024-04-13 10:23:14 +02:00
}
ImpKeReleaseGuardedMutex(&head->lock);
2023-10-08 16:07:49 +02:00
}
2024-02-11 15:34:28 +01:00
VOID
EnumerateDriverListWithCallbackRoutine(
_In_ DRIVERLIST_CALLBACK_ROUTINE CallbackRoutine, _In_opt_ PVOID Context)
2024-02-11 15:34:28 +01:00
{
2024-08-04 08:30:31 +02:00
NT_ASSERT(CallbackRoutine != NULL);
2024-08-01 06:21:53 +02:00
PDRIVER_LIST_HEAD head = GetDriverList();
2024-08-04 08:30:31 +02:00
PLIST_ENTRY entry = NULL;
PDRIVER_LIST_ENTRY driver = NULL;
ImpKeAcquireGuardedMutex(&head->lock);
if (CallbackRoutine) {
2024-08-04 08:30:31 +02:00
entry = head->list_entry.Flink;
while (entry != &head->list_entry) {
driver = CONTAINING_RECORD(entry, DRIVER_LIST_ENTRY, list_entry);
CallbackRoutine(driver, Context);
entry = entry->Flink;
}
2024-04-13 10:23:14 +02:00
}
2024-02-11 15:34:28 +01:00
ImpKeReleaseGuardedMutex(&head->lock);
2024-02-11 15:34:28 +01:00
}
VOID
2024-08-01 06:21:53 +02:00
DriverListEntryToExtendedModuleInfo(
_In_ PDRIVER_LIST_ENTRY Entry, _Out_ PRTL_MODULE_EXTENDED_INFO Extended)
2024-02-11 15:34:28 +01:00
{
2024-04-13 10:23:14 +02:00
Extended->ImageBase = Entry->ImageBase;
Extended->ImageSize = Entry->ImageSize;
2024-07-22 12:43:09 +02:00
IntCopyMemory(
2024-08-01 06:21:53 +02:00
Extended->FullPathName,
Entry->path,
sizeof(Extended->FullPathName));
2024-02-11 15:34:28 +01:00
}
NTSTATUS
InitialiseDriverList()
{
2024-04-13 10:23:14 +02:00
PAGED_CODE();
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
SYSTEM_MODULES modules = {0};
PDRIVER_LIST_ENTRY entry = NULL;
2024-04-13 10:23:14 +02:00
PRTL_MODULE_EXTENDED_INFO module_entry = NULL;
2024-08-01 06:21:53 +02:00
PDRIVER_LIST_HEAD head = GetDriverList();
InterlockedExchange(&head->active, TRUE);
InitializeListHead(&head->list_entry);
InitializeListHead(&head->deferred_list);
KeInitializeGuardedMutex(&head->lock);
2024-03-04 05:12:44 +01:00
head->can_hash_x86 = FALSE;
2024-08-01 06:21:53 +02:00
head->work_item = IoAllocateWorkItem(GetDriverDeviceObject());
2024-03-04 05:12:44 +01:00
if (!head->work_item)
2024-04-13 10:23:14 +02:00
return STATUS_INSUFFICIENT_RESOURCES;
2024-04-13 10:23:14 +02:00
status = GetSystemModuleInformation(&modules);
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("GetSystemModuleInformation failed with status %x", status);
return status;
}
2024-06-16 11:52:27 +02:00
KeAcquireGuardedMutex(&head->lock);
2024-04-13 10:23:14 +02:00
/* skip hal.dll and ntoskrnl.exe */
for (UINT32 index = 2; index < modules.module_count; index++) {
2024-08-01 06:21:53 +02:00
entry = ImpExAllocatePool2(
POOL_FLAG_NON_PAGED,
sizeof(DRIVER_LIST_ENTRY),
POOL_TAG_DRIVER_LIST);
2024-04-13 10:23:14 +02:00
if (!entry)
continue;
module_entry = &((PRTL_MODULE_EXTENDED_INFO)modules.address)[index];
2024-08-01 06:21:53 +02:00
entry->hashed = TRUE;
2024-04-13 10:23:14 +02:00
entry->ImageBase = module_entry->ImageBase;
entry->ImageSize = module_entry->ImageSize;
2024-08-01 06:21:53 +02:00
IntCopyMemory(
entry->path,
module_entry->FullPathName,
sizeof(module_entry->FullPathName));
2024-04-13 10:23:14 +02:00
status = HashModule(module_entry, entry->text_hash);
if (status == STATUS_INVALID_IMAGE_WIN_32) {
2024-08-01 06:21:53 +02:00
DEBUG_ERROR(
"32 bit module not hashed, will hash later. %x",
status);
2024-04-13 10:23:14 +02:00
entry->hashed = FALSE;
2024-08-01 06:21:53 +02:00
entry->x86 = TRUE;
InsertHeadList(&head->deferred_list, &entry->deferred_entry);
2024-04-13 10:23:14 +02:00
}
else if (!NT_SUCCESS(status)) {
DEBUG_ERROR("HashModule failed with status %x", status);
entry->hashed = FALSE;
}
InsertHeadList(&head->list_entry, &entry->list_entry);
2024-04-13 10:23:14 +02:00
}
2024-06-16 11:52:27 +02:00
KeReleaseGuardedMutex(&head->lock);
head->active = TRUE;
2024-01-14 01:48:31 +01:00
2024-04-13 10:23:14 +02:00
if (modules.address)
ImpExFreePoolWithTag(modules.address, SYSTEM_MODULES_POOL);
2024-04-13 10:23:14 +02:00
return STATUS_SUCCESS;
}
2024-01-07 05:42:40 +01:00
/*
* I actually think a spinlock here for the driver list is what we want rather
* then a mutex, but implementing a spinlock has its challenges... todo: have a
* think!
2024-01-07 05:42:40 +01:00
*/
VOID
2024-08-01 06:21:53 +02:00
FindDriverEntryByBaseAddress(
_In_ PVOID ImageBase, _Out_ PDRIVER_LIST_ENTRY* Entry)
{
2024-08-04 08:30:31 +02:00
NT_ASSERT(ImageBase != NULL);
NT_ASSERT(Entry != NULL);
2024-08-01 06:21:53 +02:00
PDRIVER_LIST_HEAD head = GetDriverList();
2024-08-04 08:30:31 +02:00
PLIST_ENTRY entry = NULL;
PDRIVER_LIST_ENTRY driver = NULL;
2024-04-13 10:23:14 +02:00
*Entry = NULL;
2024-08-04 08:30:31 +02:00
ImpKeAcquireGuardedMutex(&head->lock);
entry = head->list_entry.Flink;
2024-08-04 08:30:31 +02:00
while (entry != &head->list_entry) {
driver = CONTAINING_RECORD(entry, DRIVER_LIST_ENTRY, list_entry);
2024-08-04 08:30:31 +02:00
if (driver->ImageBase == ImageBase) {
*Entry = driver;
2024-04-13 10:23:14 +02:00
goto unlock;
}
2024-04-13 10:23:14 +02:00
2024-08-04 08:30:31 +02:00
entry = entry->Flink;
2024-04-13 10:23:14 +02:00
}
unlock:
ImpKeReleaseGuardedMutex(&head->lock);
}
STATIC
BOOLEAN
ProcessHashmapCompareFunction(_In_ PVOID Struct1, _In_ PVOID Struct2)
{
2024-08-04 08:30:31 +02:00
NT_ASSERT(Struct1 != NULL);
NT_ASSERT(Struct2 != NULL);
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
2024-08-01 06:21:53 +02:00
ImageLoadInsertNonSystemImageIntoProcessHashmap(
_In_ PIMAGE_INFO ImageInfo,
_In_ HANDLE ProcessId,
_In_opt_ PUNICODE_STRING FullImageName)
{
2024-08-01 06:21:53 +02:00
INT32 index = 0;
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;
2024-06-13 14:53:37 +02:00
index = RtlHashmapHashKeyAndAcquireBucket(map, ProcessId);
2024-06-13 14:53:37 +02:00
if (index == STATUS_INVALID_HASHMAP_INDEX)
return;
entry = RtlHashmapEntryLookup(GetProcessHashmap(), index, &ProcessId);
/* critical error has occured */
if (!entry) {
DEBUG_ERROR("RtlLookupEntryHashmap failed.");
goto end;
}
context = (PPROCESS_MODULE_MAP_CONTEXT)map->context;
2024-08-01 06:21:53 +02:00
module = ExAllocateFromLookasideListEx(&context->pool);
if (!module)
goto end;
/* for now lets just do base and size */
module->base = ImageInfo->ImageBase;
module->size = ImageInfo->ImageSize;
2024-06-16 10:04:28 +02:00
/*
* 1. We dont care if this errors
* 2. There is a bug with the conversion need 2 look into...
*/
if (FullImageName)
UnicodeToCharBufString(
2024-08-01 06:21:53 +02:00
FullImageName,
module->path,
sizeof(module->path));
InsertTailList(&entry->module_list, &module->entry);
entry->list_count++;
end:
2024-06-13 14:53:37 +02:00
RtlHashmapReleaseBucket(map, index);
}
VOID
2024-08-01 06:21:53 +02:00
ImageLoadNotifyRoutineCallback(
_In_opt_ PUNICODE_STRING FullImageName,
_In_ HANDLE ProcessId,
_In_ PIMAGE_INFO ImageInfo)
{
2024-05-11 14:54:58 +02:00
UNREFERENCED_PARAMETER(ProcessId);
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
PDRIVER_LIST_ENTRY entry = NULL;
RTL_MODULE_EXTENDED_INFO module = {0};
PDRIVER_LIST_HEAD head = GetDriverList();
ANSI_STRING ansi_path = {0};
if (InterlockedExchange(&head->active, head->active) == FALSE)
2024-04-13 10:23:14 +02:00
return;
if (ImageInfo->SystemModeImage == FALSE) {
ImageLoadInsertNonSystemImageIntoProcessHashmap(
2024-08-01 06:21:53 +02:00
ImageInfo,
ProcessId,
FullImageName);
2024-04-13 10:23:14 +02:00
return;
}
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
FindDriverEntryByBaseAddress(ImageInfo->ImageBase, &entry);
/* if we image exists, exit */
2024-04-13 10:23:14 +02:00
if (entry)
return;
2024-04-13 10:23:14 +02:00
entry = ExAllocatePool2(
2024-08-01 06:21:53 +02:00
POOL_FLAG_NON_PAGED,
sizeof(DRIVER_LIST_ENTRY),
POOL_TAG_DRIVER_LIST);
2024-04-13 10:23:14 +02:00
if (!entry)
return;
2024-08-01 06:21:53 +02:00
entry->hashed = TRUE;
entry->x86 = FALSE;
2024-04-13 10:23:14 +02:00
entry->ImageBase = ImageInfo->ImageBase;
entry->ImageSize = ImageInfo->ImageSize;
2024-02-11 15:34:28 +01:00
2024-04-13 10:23:14 +02:00
module.ImageBase = ImageInfo->ImageBase;
module.ImageSize = ImageInfo->ImageSize;
2024-02-11 15:34:28 +01:00
2024-04-13 10:23:14 +02:00
if (FullImageName) {
UnicodeToCharBufString(
2024-08-01 06:21:53 +02:00
FullImageName,
module.FullPathName,
sizeof(module.FullPathName));
2024-07-22 12:43:09 +02:00
IntCopyMemory(
2024-08-01 06:21:53 +02:00
entry->path,
module.FullPathName,
sizeof(module.FullPathName));
2024-04-13 10:23:14 +02:00
}
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);
2024-08-01 06:21:53 +02:00
entry->x86 = TRUE;
2024-04-13 10:23:14 +02:00
entry->hashed = FALSE;
}
else if (!NT_SUCCESS(status)) {
DEBUG_ERROR("HashModule failed with status %x", status);
entry->hashed = FALSE;
}
KeAcquireGuardedMutex(&head->lock);
InsertHeadList(&head->list_entry, &entry->list_entry);
KeReleaseGuardedMutex(&head->lock);
2023-10-10 19:49:17 +02:00
}
/* assumes map lock is held */
VOID
2024-08-01 06:21:53 +02:00
FreeProcessEntryModuleList(
_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
{
UNREFERENCED_PARAMETER(Context);
2024-08-04 08:30:31 +02:00
NT_ASSERT(Entry != NULL);
2024-08-01 06:21:53 +02:00
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)) {
2024-08-01 06:21:53 +02:00
list = RemoveTailList(&Entry->module_list);
list_entry = CONTAINING_RECORD(list, PROCESS_MAP_MODULE_ENTRY, entry);
ExFreeToLookasideListEx(&context->pool, list_entry);
}
}
VOID
2024-08-01 06:21:53 +02:00
EnumerateProcessModuleList(
_In_ HANDLE ProcessId,
_In_ PROCESS_MODULE_CALLBACK Callback,
_In_opt_ PVOID Context)
{
2024-08-01 06:21:53 +02:00
INT32 index = 0;
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;
2024-06-13 14:53:37 +02:00
index = RtlHashmapHashKeyAndAcquireBucket(map, ProcessId);
if (index == STATUS_INVALID_HASHMAP_INDEX)
return;
2024-06-13 14:53:37 +02:00
entry = RtlHashmapEntryLookup(map, index, &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:
2024-06-13 14:53:37 +02:00
RtlHashmapReleaseBucket(map, index);
}
VOID
2024-08-01 06:21:53 +02:00
FindOurUserModeModuleEntry(
_In_ PROCESS_MODULE_CALLBACK Callback, _In_opt_ PVOID Context)
{
2024-08-04 08:30:31 +02:00
NT_ASSERT(Callback != NULL);
2024-08-01 06:21:53 +02:00
INT32 index = 0;
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;
2024-06-13 14:53:37 +02:00
index = RtlHashmapHashKeyAndAcquireBucket(map, session->km_handle);
2024-06-13 14:53:37 +02:00
if (index == STATUS_INVALID_HASHMAP_INDEX)
return;
entry = RtlHashmapEntryLookup(map, index, &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:
2024-06-13 14:53:37 +02:00
RtlHashmapReleaseBucket(map, index);
}
VOID
CleanupProcessHashmap()
{
2024-08-01 06:21:53 +02:00
PRTL_HASHMAP map = GetProcessHashmap();
PRTL_HASHMAP_ENTRY entry = NULL;
PRTL_HASHMAP_ENTRY temp = NULL;
PLIST_ENTRY list = NULL;
PPROCESS_MODULE_MAP_CONTEXT context = NULL;
2024-06-11 13:41:55 +02:00
RtlHashmapSetInactive(map);
/* First, free all module lists */
2024-06-11 13:41:55 +02:00
RtlHashmapEnumerate(map, FreeProcessEntryModuleList, NULL);
for (UINT32 index = 0; index < map->bucket_count; index++) {
entry = &map->buckets[index];
2024-06-13 14:53:37 +02:00
KeAcquireGuardedMutex(&map->locks[index]);
while (!IsListEmpty(&entry->entry)) {
list = RemoveHeadList(&entry->entry);
temp = CONTAINING_RECORD(list, RTL_HASHMAP_ENTRY, entry);
ExFreePoolWithTag(temp, POOL_TAG_HASHMAP);
}
2024-06-13 14:53:37 +02:00
KeReleaseGuardedMutex(&map->locks[index]);
}
context = map->context;
ExDeleteLookasideListEx(&context->pool);
ExFreePoolWithTag(map->context, POOL_TAG_HASHMAP);
2024-06-11 13:41:55 +02:00
RtlHashmapDelete(map);
}
2024-01-14 05:31:19 +01:00
NTSTATUS
InitialiseProcessHashmap()
2023-10-10 19:49:17 +02:00
{
PAGED_CODE();
2024-04-13 10:23:14 +02:00
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
PPROCESS_MODULE_MAP_CONTEXT context = NULL;
2024-08-01 06:21:53 +02:00
context = ExAllocatePool2(
POOL_FLAG_NON_PAGED,
sizeof(PROCESS_MODULE_MAP_CONTEXT),
POOL_TAG_HASHMAP);
if (!context)
return STATUS_INSUFFICIENT_RESOURCES;
2024-08-01 06:21:53 +02:00
status = ExInitializeLookasideListEx(
&context->pool,
NULL,
NULL,
NonPagedPoolNx,
0,
sizeof(PROCESS_MAP_MODULE_ENTRY),
POOL_TAG_MODULE_LIST,
0);
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status)) {
ExFreePoolWithTag(context, POOL_TAG_HASHMAP);
return status;
}
2024-08-01 06:21:53 +02:00
status = RtlHashmapCreate(
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);
2024-01-14 05:31:19 +01:00
return status;
2024-04-13 10:23:14 +02:00
}
return status;
2023-10-10 19:49:17 +02:00
}
2024-06-16 10:04:28 +02:00
STATIC
UINT32
ThreadListTreeCompare(_In_ PVOID Key, _In_ PVOID Object)
{
2024-08-04 08:30:31 +02:00
NT_ASSERT(Key != NULL);
NT_ASSERT(Object != NULL);
2024-06-16 10:04:28 +02:00
HANDLE tid_1 = *((PHANDLE)Object);
HANDLE tid_2 = *((PHANDLE)Key);
if (tid_2 < tid_1)
return RB_TREE_LESS_THAN;
else if (tid_2 > tid_1)
return RB_TREE_GREATER_THAN;
else
return RB_TREE_EQUAL;
}
2024-01-14 05:31:19 +01:00
NTSTATUS
2023-10-08 16:07:49 +02:00
InitialiseThreadList()
{
2024-06-16 10:04:28 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
2024-08-01 06:21:53 +02:00
PRB_TREE tree = GetThreadTree();
2024-04-13 10:23:14 +02:00
2024-06-16 10:04:28 +02:00
status =
RtlRbTreeCreate(ThreadListTreeCompare, sizeof(THREAD_LIST_ENTRY), tree);
2024-04-13 10:23:14 +02:00
2024-08-04 08:30:31 +02:00
if (!NT_SUCCESS(status)) {
2024-06-16 10:04:28 +02:00
DEBUG_ERROR("RtlRbTreeCreate: %x", status);
2024-08-04 08:30:31 +02:00
return status;
}
2024-04-13 10:23:14 +02:00
2024-06-16 10:04:28 +02:00
tree->active = TRUE;
2024-04-13 10:23:14 +02:00
return status;
2023-10-08 16:07:49 +02:00
}
VOID
2024-08-01 06:21:53 +02:00
FindThreadListEntryByThreadAddress(
_In_ HANDLE ThreadId, _Out_ PTHREAD_LIST_ENTRY* Entry)
2023-10-08 16:07:49 +02:00
{
2024-06-16 10:04:28 +02:00
PRB_TREE tree = GetThreadTree();
RtlRbTreeAcquireLock(tree);
2024-06-16 11:52:27 +02:00
*Entry = RtlRbTreeFindNodeObject(tree, &ThreadId);
2024-06-16 10:04:28 +02:00
RtlRbTreeReleaselock(tree);
2023-10-08 16:07:49 +02:00
}
2024-05-06 10:40:55 +02:00
FORCEINLINE
STATIC
BOOLEAN
CanInitiateDeferredHashing(_In_ LPCSTR ProcessName, _In_ PDRIVER_LIST_HEAD Head)
{
2024-08-01 06:21:53 +02:00
return !IntCompareString(ProcessName, "winlogon.exe") && Head->work_item
? TRUE
: FALSE;
2024-05-06 10:40:55 +02:00
}
2024-08-04 08:30:31 +02:00
#ifdef DEBUG
2024-06-13 14:53:37 +02:00
STATIC
VOID
2024-06-13 14:53:37 +02:00
PrintHashmapCallback(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
{
2024-06-13 14:53:37 +02:00
PPROCESS_MAP_MODULE_ENTRY module = NULL;
2024-08-01 06:21:53 +02:00
PLIST_ENTRY list = NULL;
2024-06-13 14:53:37 +02:00
UNREFERENCED_PARAMETER(Context);
DEBUG_VERBOSE("Process ID: %p", Entry->process_id);
2024-06-13 14:53:37 +02:00
for (list = Entry->module_list.Flink; list != &Entry->module_list;
list = list->Flink) {
module = CONTAINING_RECORD(list, PROCESS_MAP_MODULE_ENTRY, entry);
2024-08-01 06:21:53 +02:00
DEBUG_VERBOSE(
" -> Module Base: %p, size: %lx, path: %s",
(PVOID)module->base,
module->size,
module->path);
}
2024-06-13 14:53:37 +02:00
}
2024-06-13 14:53:37 +02:00
VOID
EnumerateAndPrintProcessHashmap()
{
RtlHashmapEnumerate(GetProcessHashmap(), PrintHashmapCallback, NULL);
}
2024-08-04 08:30:31 +02:00
#endif
2023-10-10 19:49:17 +02:00
VOID
2024-08-01 06:21:53 +02:00
ProcessCreateNotifyRoutine(
_In_ HANDLE ParentId, _In_ HANDLE ProcessId, _In_ BOOLEAN Create)
2023-10-10 19:49:17 +02:00
{
2024-08-01 06:21:53 +02:00
INT32 index = 0;
PKPROCESS parent = NULL;
PKPROCESS process = NULL;
PDRIVER_LIST_HEAD driver_list = GetDriverList();
LPCSTR process_name = NULL;
PRTL_HASHMAP map = GetProcessHashmap();
PPROCESS_LIST_ENTRY entry = NULL;
2023-10-10 19:49:17 +02:00
if (!map->active)
2024-04-13 10:23:14 +02:00
return;
2023-10-10 19:49:17 +02:00
2024-04-13 10:23:14 +02:00
ImpPsLookupProcessByProcessId(ParentId, &parent);
ImpPsLookupProcessByProcessId(ProcessId, &process);
2023-10-10 19:49:17 +02:00
2024-04-13 10:23:14 +02:00
if (!parent || !process)
return;
2023-10-10 19:49:17 +02:00
2024-04-13 10:23:14 +02:00
process_name = ImpPsGetProcessImageFileName(process);
2024-08-01 06:21:53 +02:00
index = RtlHashmapHashKeyAndAcquireBucket(map, ProcessId);
2024-02-11 15:34:28 +01:00
2024-06-13 14:53:37 +02:00
if (index == STATUS_INVALID_HASHMAP_INDEX)
return;
2024-04-13 10:23:14 +02:00
if (Create) {
2024-07-20 11:07:17 +02:00
entry = RtlHashmapEntryInsert(map, index);
2023-10-10 19:49:17 +02:00
2024-04-13 10:23:14 +02:00
if (!entry)
goto end;
2023-10-10 19:49:17 +02:00
entry->process_id = ProcessId;
2024-08-01 06:21:53 +02:00
entry->process = process;
entry->parent = parent;
2023-10-12 13:27:40 +02:00
InitializeListHead(&entry->module_list);
2023-10-10 19:49:17 +02:00
entry->list_count = 0;
2024-02-11 15:34:28 +01:00
2024-04-13 10:23:14 +02:00
/*
* Notify to our driver that we can hash x86 modules, and hash
* any x86 modules that werent hashed.
*/
2024-05-06 10:40:55 +02:00
if (CanInitiateDeferredHashing(process_name, driver_list)) {
2024-08-01 06:21:53 +02:00
IoQueueWorkItem(
driver_list->work_item,
DeferredModuleHashingCallback,
NormalWorkQueue,
NULL);
2023-12-13 05:06:27 +01:00
}
2024-04-13 10:23:14 +02:00
}
else {
2024-06-11 13:41:55 +02:00
entry = RtlHashmapEntryLookup(map, ProcessId, &ProcessId);
2023-10-10 19:49:17 +02:00
if (!entry) {
DEBUG_ERROR("UNABLE TO FIND PROCESS NODE!!!");
goto end;
}
2023-10-10 19:49:17 +02:00
2024-04-13 10:23:14 +02:00
ImpObDereferenceObject(entry->parent);
ImpObDereferenceObject(entry->process);
2023-10-12 13:27:40 +02:00
FreeProcessEntryModuleList(entry, NULL);
2024-07-20 11:07:17 +02:00
RtlHashmapEntryDelete(map, index, &ProcessId);
2024-04-13 10:23:14 +02:00
}
end:
2024-06-13 14:53:37 +02:00
RtlHashmapReleaseBucket(map, index);
2023-10-10 19:49:17 +02:00
}
2023-10-08 16:07:49 +02:00
VOID
2024-08-01 06:21:53 +02:00
ThreadCreateNotifyRoutine(
_In_ HANDLE ProcessId, _In_ HANDLE ThreadId, _In_ BOOLEAN Create)
2023-10-08 16:07:49 +02:00
{
2024-08-01 06:21:53 +02:00
PTHREAD_LIST_ENTRY entry = NULL;
PKTHREAD thread = NULL;
PKPROCESS process = NULL;
PRB_TREE tree = GetThreadTree();
2023-10-08 16:07:49 +02:00
2024-04-13 10:23:14 +02:00
/* ensure we don't insert new entries if we are unloading */
2024-06-16 10:04:28 +02:00
if (!tree->active)
2024-04-13 10:23:14 +02:00
return;
2023-10-08 16:07:49 +02:00
2024-04-13 10:23:14 +02:00
ImpPsLookupThreadByThreadId(ThreadId, &thread);
ImpPsLookupProcessByProcessId(ProcessId, &process);
2023-10-08 16:07:49 +02:00
2024-06-17 10:51:39 +02:00
/* ideally we should dereference the other but this shouldnt really ever
* fail */
2024-04-13 10:23:14 +02:00
if (!thread || !process)
return;
2023-10-08 16:07:49 +02:00
2024-06-16 10:04:28 +02:00
RtlRbTreeAcquireLock(tree);
2024-04-13 10:23:14 +02:00
if (Create) {
2024-06-16 10:04:28 +02:00
entry = RtlRbTreeInsertNode(tree, &ThreadId);
2023-10-08 16:07:49 +02:00
2024-04-13 10:23:14 +02:00
if (!entry)
2024-06-16 10:04:28 +02:00
goto end;
2023-10-08 16:07:49 +02:00
2024-08-01 06:21:53 +02:00
entry->thread_id = ThreadId;
entry->thread = thread;
2024-04-13 10:23:14 +02:00
entry->owning_process = process;
2024-08-01 06:21:53 +02:00
entry->apc = NULL;
entry->apc_queued = FALSE;
2024-04-13 10:23:14 +02:00
}
else {
2024-06-16 11:52:27 +02:00
entry = RtlRbTreeFindNodeObject(tree, &ThreadId);
2023-10-08 16:30:05 +02:00
2024-04-13 10:23:14 +02:00
if (!entry)
2024-06-16 10:04:28 +02:00
goto end;
2023-10-08 16:30:05 +02:00
2024-04-13 10:23:14 +02:00
ImpObDereferenceObject(entry->thread);
ImpObDereferenceObject(entry->owning_process);
2023-10-12 13:27:40 +02:00
2024-06-16 10:04:28 +02:00
RtlRbTreeDeleteNode(tree, &ThreadId);
2024-04-13 10:23:14 +02:00
}
2024-06-16 10:04:28 +02:00
end:
RtlRbTreeReleaselock(tree);
2023-10-08 16:07:49 +02:00
}
2023-10-05 08:27:17 +02:00
VOID
2024-08-01 06:21:53 +02:00
ObPostOpCallbackRoutine(
_In_ PVOID RegistrationContext,
_In_ POB_POST_OPERATION_INFORMATION OperationInformation)
2023-08-20 16:12:04 +02:00
{
2024-04-13 10:23:14 +02:00
PAGED_CODE();
UNREFERENCED_PARAMETER(RegistrationContext);
UNREFERENCED_PARAMETER(OperationInformation);
2023-08-20 16:12:04 +02:00
}
2024-05-11 14:54:58 +02:00
#define MAX_PROCESS_NAME_LENGTH 30
#define PROCESS_HANDLE_OPEN_DOWNGRADE_COUNT 4
2024-05-30 07:42:35 +02:00
#define DOWNGRADE_LSASS 0
#define DOWNGRADE_CSRSS 1
#define DOWNGRADE_WERFAULT 2
#define DOWNGRADE_MSMPENG 3
2024-05-11 14:54:58 +02:00
CHAR PROCESS_HANDLE_OPEN_DOWNGRADE[PROCESS_HANDLE_OPEN_DOWNGRADE_COUNT]
2024-08-01 06:21:53 +02:00
[MAX_PROCESS_NAME_LENGTH] = {
"lsass.exe",
"csrss.exe",
"WerFault.exe",
"MsMpEng.exe"};
2024-05-11 14:54:58 +02:00
#define PROCESS_HANDLE_OPEN_WHITELIST_COUNT 3
CHAR PROCESS_HANDLE_OPEN_WHITELIST[PROCESS_HANDLE_OPEN_WHITELIST_COUNT]
2024-08-01 06:21:53 +02:00
[MAX_PROCESS_NAME_LENGTH] = {
"Discord.exe",
"svchost.exe",
"explorer.exe"};
2024-05-11 14:54:58 +02:00
STATIC
BOOLEAN
IsWhitelistedHandleOpenProcess(_In_ LPCSTR ProcessName)
{
for (UINT32 index = 0; index < PROCESS_HANDLE_OPEN_WHITELIST_COUNT;
index++) {
2024-08-01 06:21:53 +02:00
if (!IntCompareString(
ProcessName,
PROCESS_HANDLE_OPEN_WHITELIST[index]))
2024-05-11 14:54:58 +02:00
return TRUE;
}
return FALSE;
}
STATIC
BOOLEAN
IsDowngradeHandleOpenProcess(_In_ LPCSTR ProcessName)
{
for (UINT32 index = 0; index < PROCESS_HANDLE_OPEN_DOWNGRADE_COUNT;
index++) {
2024-08-01 06:21:53 +02:00
if (!IntCompareString(
ProcessName,
PROCESS_HANDLE_OPEN_DOWNGRADE[index]))
2024-05-11 14:54:58 +02:00
return TRUE;
}
return FALSE;
}
2024-01-15 02:01:14 +01:00
// https://www.sysnative.com/forums/threads/object-headers-handles-and-types.34987/
#define GET_OBJECT_HEADER_FROM_HANDLE(x) ((x << 4) | 0xffff000000000000);
2023-10-05 08:27:17 +02:00
OB_PREOP_CALLBACK_STATUS
2024-08-01 06:21:53 +02:00
ObPreOpCallbackRoutine(
_In_ PVOID RegistrationContext,
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation)
2023-08-20 16:12:04 +02:00
{
2024-04-13 10:23:14 +02:00
PAGED_CODE();
UNREFERENCED_PARAMETER(RegistrationContext);
/* access mask to completely strip permissions */
ACCESS_MASK deny_access = SYNCHRONIZE | PROCESS_TERMINATE;
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS process_creator = PsGetCurrentProcess();
PEPROCESS protected_process = NULL;
PEPROCESS target_process = (PEPROCESS)OperationInformation->Object;
HANDLE process_creator_id = ImpPsGetProcessId(process_creator);
LONG protected_process_id = 0;
LPCSTR process_creator_name = NULL;
LPCSTR target_process_name = NULL;
LPCSTR protected_process_name = NULL;
2024-04-13 10:23:14 +02:00
POB_CALLBACKS_CONFIG configuration = NULL;
2024-08-01 06:21:53 +02:00
UINT32 report_size = 0;
2024-04-13 10:23:14 +02:00
/*
* This is to prevent the condition where the thread executing this
* function is scheduled whilst we are cleaning up the callbacks on
* driver unload. We must hold the driver config lock to ensure the pool
* containing the callback configuration lock is not freed
*/
SessionGetCallbackConfiguration(&configuration);
if (!configuration)
return OB_PREOP_SUCCESS;
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
ImpKeAcquireGuardedMutex(&configuration->lock);
SessionGetProcessId(&protected_process_id);
SessionGetProcess(&protected_process);
if (!protected_process_id || !protected_process)
goto end;
2024-08-01 06:21:53 +02:00
process_creator_name = ImpPsGetProcessImageFileName(process_creator);
target_process_name = ImpPsGetProcessImageFileName(target_process);
2024-04-13 10:23:14 +02:00
protected_process_name = ImpPsGetProcessImageFileName(protected_process);
if (!protected_process_name || !target_process_name)
goto end;
2024-07-22 12:43:09 +02:00
if (IntCompareString(protected_process_name, target_process_name))
2024-04-13 10:23:14 +02:00
goto end;
/*
* WerFault is some windows 11 application that cries when it
* cant get a handle, so well allow it for now... todo; learn
* more about it
*
* todo: perform stricter checks rather then the image name.
* perhapds check some certificate or something.
*/
2024-05-11 14:54:58 +02:00
if (IsDowngradeHandleOpenProcess(process_creator_name) ||
2024-07-22 12:43:09 +02:00
!IntCompareString(process_creator_name, target_process_name)) {
2024-04-13 10:23:14 +02:00
/* We will downgrade these handles later */
// DEBUG_LOG("Handles created by CSRSS, LSASS and
// WerFault are allowed for now...");
}
else if (target_process == process_creator) {
// DEBUG_LOG("handles made by NOTEPAD r okay :)");
/* handles created by the game (notepad) are okay */
}
else {
OperationInformation->Parameters->CreateHandleInformation
.DesiredAccess = deny_access;
OperationInformation->Parameters->DuplicateHandleInformation
.DesiredAccess = deny_access;
2023-12-13 05:06:27 +01:00
/*
2024-04-13 10:23:14 +02:00
* These processes will constantly open handles to any
* open process for various reasons, so we will still
* strip them but we won't report them.. for now
* atleast.
2023-12-13 05:06:27 +01:00
*/
2024-05-11 14:54:58 +02:00
if (IsWhitelistedHandleOpenProcess(process_creator_name))
2024-04-13 10:23:14 +02:00
goto end;
2024-05-11 14:54:58 +02:00
report_size = CryptRequestRequiredBufferLength(
sizeof(OPEN_HANDLE_FAILURE_REPORT));
POPEN_HANDLE_FAILURE_REPORT report = ImpExAllocatePool2(
2024-08-01 06:21:53 +02:00
POOL_FLAG_NON_PAGED,
report_size,
REPORT_POOL_TAG);
2024-05-05 12:42:22 +02:00
2024-05-06 09:08:39 +02:00
if (!report)
goto end;
2024-05-05 12:42:22 +02:00
2024-05-11 14:54:58 +02:00
INIT_REPORT_PACKET(report, REPORT_ILLEGAL_HANDLE_OPERATION, 0);
2024-05-05 12:42:22 +02:00
2024-05-06 09:08:39 +02:00
report->is_kernel_handle = OperationInformation->KernelHandle;
2024-08-01 06:21:53 +02:00
report->process_id = process_creator_id;
report->thread_id = ImpPsGetCurrentThreadId();
report->access = OperationInformation->Parameters
2024-05-06 09:08:39 +02:00
->CreateHandleInformation.DesiredAccess;
2024-05-05 12:42:22 +02:00
2024-08-01 06:21:53 +02:00
IntCopyMemory(
report->process_name,
process_creator_name,
HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
2024-05-05 12:42:22 +02:00
2024-05-11 14:54:58 +02:00
status = CryptEncryptBuffer(report, report_size);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("CryptEncryptBuffer: %x", status);
ExFreePoolWithTag(report, report_size);
goto end;
}
2024-05-11 17:27:18 +02:00
IrpQueueSchedulePacket(report, report_size);
2024-04-13 10:23:14 +02:00
}
2023-08-20 16:12:04 +02:00
2023-08-20 17:04:53 +02:00
end:
2024-04-13 10:23:14 +02:00
ImpKeReleaseGuardedMutex(&configuration->lock);
return OB_PREOP_SUCCESS;
2023-08-20 16:12:04 +02:00
}
2023-08-22 10:51:52 +02:00
/* stolen from ReactOS xD */
2023-12-13 05:06:27 +01:00
VOID NTAPI
2024-08-01 06:21:53 +02:00
ExUnlockHandleTableEntry(
IN PHANDLE_TABLE HandleTable, IN PHANDLE_TABLE_ENTRY HandleTableEntry)
2023-08-22 10:51:52 +02:00
{
2024-04-13 10:23:14 +02:00
INT64 old_value;
PAGED_CODE();
2023-08-22 10:51:52 +02:00
2024-04-13 10:23:14 +02:00
/* Set the lock bit and make sure it wasn't earlier */
old_value = InterlockedOr((PLONG)&HandleTableEntry->VolatileLowValue, 1);
2023-08-22 10:51:52 +02:00
2024-04-13 10:23:14 +02:00
/* Unblock any waiters */
2024-05-11 14:54:58 +02:00
#pragma warning(push)
#pragma warning(disable : C6387)
2024-04-13 10:23:14 +02:00
ImpExfUnblockPushLock(&HandleTable->HandleContentionEvent, NULL);
2024-05-11 14:54:58 +02:00
#pragma warning(pop)
}
FORCEINLINE
STATIC
ACCESS_MASK
GetHandleAccessMask(_In_ PHANDLE_TABLE_ENTRY Entry)
{
return (ACCESS_MASK)Entry->GrantedAccessBits;
2023-08-22 10:51:52 +02:00
}
2024-01-15 02:01:14 +01:00
static UNICODE_STRING OBJECT_TYPE_PROCESS = RTL_CONSTANT_STRING(L"Process");
2024-08-01 06:21:53 +02:00
static UNICODE_STRING OBJECT_TYPE_THREAD = RTL_CONSTANT_STRING(L"Thread");
2024-01-15 02:01:14 +01:00
2023-09-27 06:22:14 +02:00
STATIC
2023-10-05 08:27:17 +02:00
BOOLEAN
2024-08-01 06:21:53 +02:00
EnumHandleCallback(
_In_ PHANDLE_TABLE HandleTable,
_In_ PHANDLE_TABLE_ENTRY Entry,
_In_ HANDLE Handle,
_In_ PVOID Context)
2023-08-22 10:51:52 +02:00
{
2024-04-13 10:23:14 +02:00
PAGED_CODE();
2023-12-13 05:06:27 +01:00
2024-05-11 14:54:58 +02:00
UNREFERENCED_PARAMETER(Context);
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID object = NULL;
PVOID object_header = NULL;
POBJECT_TYPE object_type = NULL;
PEPROCESS process = NULL;
PEPROCESS protected_process = NULL;
LPCSTR process_name = NULL;
LPCSTR protected_process_name = NULL;
ACCESS_MASK handle_access_mask = 0;
UINT32 report_size = 0;
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
object_header = GET_OBJECT_HEADER_FROM_HANDLE(Entry->ObjectPointerBits);
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
/* Object header is the first 30 bytes of the object */
2024-08-01 06:21:53 +02:00
object = (uintptr_t)object_header + OBJECT_HEADER_SIZE;
2024-04-13 10:23:14 +02:00
object_type = ImpObGetObjectType(object);
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
/* TODO: check for threads aswell */
if (ImpRtlCompareUnicodeString(
2024-08-01 06:21:53 +02:00
&object_type->Name,
&OBJECT_TYPE_PROCESS,
TRUE)) {
2024-04-13 10:23:14 +02:00
goto end;
}
2023-12-13 05:06:27 +01:00
2024-08-01 06:21:53 +02:00
process = (PEPROCESS)object;
2024-04-13 10:23:14 +02:00
process_name = ImpPsGetProcessImageFileName(process);
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
SessionGetProcess(&protected_process);
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
protected_process_name = ImpPsGetProcessImageFileName(protected_process);
2023-12-13 05:06:27 +01:00
2024-07-22 12:43:09 +02:00
if (IntCompareString(process_name, protected_process_name))
2024-04-13 10:23:14 +02:00
goto end;
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
DEBUG_VERBOSE(
"Handle references our protected process with access mask: %lx",
(ACCESS_MASK)Entry->GrantedAccessBits);
2023-12-13 05:06:27 +01:00
2024-05-11 14:54:58 +02:00
handle_access_mask = GetHandleAccessMask(Entry);
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
/* These permissions can be stripped from every process
* including CSRSS and LSASS */
if (handle_access_mask & PROCESS_CREATE_PROCESS) {
Entry->GrantedAccessBits &= ~PROCESS_CREATE_PROCESS;
DEBUG_VERBOSE("Stripped PROCESS_CREATE_PROCESS");
}
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
if (handle_access_mask & PROCESS_CREATE_THREAD) {
Entry->GrantedAccessBits &= ~PROCESS_CREATE_THREAD;
DEBUG_VERBOSE("Stripped PROCESS_CREATE_THREAD");
}
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
if (handle_access_mask & PROCESS_DUP_HANDLE) {
Entry->GrantedAccessBits &= ~PROCESS_DUP_HANDLE;
DEBUG_VERBOSE("Stripped PROCESS_DUP_HANDLE");
}
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
if (handle_access_mask & PROCESS_QUERY_INFORMATION) {
Entry->GrantedAccessBits &= ~PROCESS_QUERY_INFORMATION;
DEBUG_VERBOSE("Stripped PROCESS_QUERY_INFORMATION");
}
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
if (handle_access_mask & PROCESS_QUERY_LIMITED_INFORMATION) {
Entry->GrantedAccessBits &= ~PROCESS_QUERY_LIMITED_INFORMATION;
DEBUG_VERBOSE("Stripped PROCESS_QUERY_LIMITED_INFORMATION");
}
2023-12-13 05:06:27 +01:00
2024-04-13 10:23:14 +02:00
if (handle_access_mask & PROCESS_VM_READ) {
Entry->GrantedAccessBits &= ~PROCESS_VM_READ;
DEBUG_VERBOSE("Stripped PROCESS_VM_READ");
}
2023-12-13 05:06:27 +01:00
2024-07-22 12:43:09 +02:00
if (!IntCompareString(process_name, "csrss.exe") ||
!IntCompareString(process_name, "lsass.exe")) {
2024-04-13 10:23:14 +02:00
DEBUG_VERBOSE(
"Required system process allowed, only stripping some permissions");
goto end;
}
/* Permissions beyond here can only be stripped from non
* critical processes */
if (handle_access_mask & PROCESS_SET_INFORMATION) {
Entry->GrantedAccessBits &= ~PROCESS_SET_INFORMATION;
DEBUG_VERBOSE("Stripped PROCESS_SET_INFORMATION");
}
if (handle_access_mask & PROCESS_SET_QUOTA) {
Entry->GrantedAccessBits &= ~PROCESS_SET_QUOTA;
DEBUG_VERBOSE("Stripped PROCESS_SET_QUOTA");
}
if (handle_access_mask & PROCESS_SUSPEND_RESUME) {
Entry->GrantedAccessBits &= ~PROCESS_SUSPEND_RESUME;
DEBUG_VERBOSE("Stripped PROCESS_SUSPEND_RESUME ");
}
if (handle_access_mask & PROCESS_TERMINATE) {
Entry->GrantedAccessBits &= ~PROCESS_TERMINATE;
DEBUG_VERBOSE("Stripped PROCESS_TERMINATE");
}
if (handle_access_mask & PROCESS_VM_OPERATION) {
Entry->GrantedAccessBits &= ~PROCESS_VM_OPERATION;
DEBUG_VERBOSE("Stripped PROCESS_VM_OPERATION");
}
if (handle_access_mask & PROCESS_VM_WRITE) {
Entry->GrantedAccessBits &= ~PROCESS_VM_WRITE;
DEBUG_VERBOSE("Stripped PROCESS_VM_WRITE");
}
2024-05-11 14:54:58 +02:00
report_size =
CryptRequestRequiredBufferLength(sizeof(OPEN_HANDLE_FAILURE_REPORT));
2024-04-13 10:23:14 +02:00
POPEN_HANDLE_FAILURE_REPORT report =
2024-05-11 14:54:58 +02:00
ImpExAllocatePool2(POOL_FLAG_NON_PAGED, report_size, REPORT_POOL_TAG);
2024-04-13 10:23:14 +02:00
if (!report)
goto end;
/*
* Using the same report structure as the ObRegisterCallbacks
* report since both of these reports are closely related by the
* fact they are triggered by a process either opening a handle
* to our protected process or have a valid open handle to it. I
* also don't think its worth creating another queue
* specifically for open handle reports since they will be rare.
*/
2024-05-11 14:54:58 +02:00
INIT_REPORT_PACKET(report, REPORT_ILLEGAL_HANDLE_OPERATION, 0);
2024-05-05 12:42:22 +02:00
report->is_kernel_handle = Entry->Attributes & OBJ_KERNEL_HANDLE;
2024-08-01 06:21:53 +02:00
report->process_id = ImpPsGetProcessId(process);
report->thread_id = 0;
report->access = handle_access_mask;
2024-04-13 10:23:14 +02:00
2024-08-01 06:21:53 +02:00
IntCopyMemory(
&report->process_name,
process_name,
HANDLE_REPORT_PROCESS_NAME_MAX_LENGTH);
2024-04-13 10:23:14 +02:00
2024-05-11 14:54:58 +02:00
status = CryptEncryptBuffer(report, report_size);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("CryptEncryptBuffer: %lx", status);
ImpExFreePoolWithTag(report, report_size);
2024-04-13 10:23:14 +02:00
goto end;
}
2023-08-22 10:51:52 +02:00
2024-05-11 17:27:18 +02:00
IrpQueueSchedulePacket(report, report_size);
2024-05-11 14:54:58 +02:00
2023-08-22 10:51:52 +02:00
end:
2024-04-13 10:23:14 +02:00
ExUnlockHandleTableEntry(HandleTable, Entry);
return FALSE;
2023-08-22 10:51:52 +02:00
}
2023-10-05 08:27:17 +02:00
NTSTATUS
EnumerateProcessHandles(_In_ PPROCESS_LIST_ENTRY Entry, _In_opt_ PVOID Context)
2023-08-22 10:51:52 +02:00
{
2024-04-13 10:23:14 +02:00
/* Handles are stored in pageable memory */
PAGED_CODE();
UNREFERENCED_PARAMETER(Context);
2024-08-04 08:30:31 +02:00
NT_ASSERT(Entry != NULL);
2023-10-10 19:49:17 +02:00
if (!Entry)
2024-04-13 10:23:14 +02:00
return STATUS_INVALID_PARAMETER;
2023-08-22 10:51:52 +02:00
if (Entry->process == PsInitialSystemProcess)
2024-04-13 10:23:14 +02:00
return STATUS_SUCCESS;
2023-08-22 10:51:52 +02:00
2024-04-13 10:23:14 +02:00
PHANDLE_TABLE handle_table =
*(PHANDLE_TABLE*)((uintptr_t)Entry->process +
2024-04-13 10:23:14 +02:00
EPROCESS_HANDLE_TABLE_OFFSET);
2023-08-22 10:51:52 +02:00
2024-04-13 10:23:14 +02:00
if (!handle_table)
return STATUS_INVALID_ADDRESS;
2023-08-22 10:51:52 +02:00
2024-04-13 10:23:14 +02:00
if (!ImpMmIsAddressValid(handle_table))
return STATUS_INVALID_ADDRESS;
2023-08-22 10:51:52 +02:00
#pragma warning(push)
#pragma warning(suppress : 6387)
2024-05-11 14:54:58 +02:00
ImpExEnumHandleTable(handle_table, EnumHandleCallback, NULL, NULL);
2023-08-22 10:51:52 +02:00
#pragma warning(pop)
2024-04-13 10:23:14 +02:00
return STATUS_SUCCESS;
2024-01-12 06:40:33 +01:00
}
#define REPEAT_TIME_10_SEC 10000
STATIC
VOID
2024-08-01 06:21:53 +02:00
TimerObjectValidateProcessModuleCallback(
_In_ PPROCESS_MAP_MODULE_ENTRY Entry, _In_opt_ PVOID Context)
{
2024-08-04 08:30:31 +02:00
NT_ASSERT(Entry != NULL);
2024-08-01 06:21:53 +02:00
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;
}
2024-07-22 12:43:09 +02:00
if (IntCompareMemory(hash, session->module.module_hash, sizeof(hash)) !=
sizeof(hash)) {
DEBUG_ERROR("User module hash not matching!! MODIFIED!");
return;
}
DEBUG_VERBOSE("User module hash valid.");
}
2024-05-11 14:54:58 +02:00
STATIC
2024-01-12 06:40:33 +01:00
VOID
2024-08-01 06:21:53 +02:00
TimerObjectWorkItemRoutine(
_In_ PDEVICE_OBJECT DeviceObject, _In_opt_ PVOID Context)
2024-01-12 06:40:33 +01:00
{
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
PTIMER_OBJECT timer = (PTIMER_OBJECT)Context;
PDRIVER_LIST_HEAD list = GetDriverList();
PACTIVE_SESSION session = GetActiveSession();
2024-01-14 01:48:31 +01:00
2024-05-11 14:54:58 +02:00
UNREFERENCED_PARAMETER(DeviceObject);
if (!ARGUMENT_PRESENT(Context))
return;
2024-04-13 10:23:14 +02:00
if (!list->active)
goto end;
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
DEBUG_VERBOSE("Integrity check timer callback invoked.");
2024-01-12 06:40:33 +01:00
2024-06-16 13:42:13 +02:00
RtlRbTreePrintCurrentStatistics(GetThreadTree());
2024-04-13 10:23:14 +02:00
if (!ValidateOurDriversDispatchRoutines()) {
DEBUG_VERBOSE("l");
}
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
status = ValidateOurDriverImage();
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status))
DEBUG_ERROR("ValidateOurDriverImage failed with status %x", status);
2024-01-12 06:40:33 +01:00
KeAcquireGuardedMutex(&session->lock);
if (!session->is_session_active) {
KeReleaseGuardedMutex(&session->lock);
goto end;
}
2024-08-01 06:21:53 +02:00
FindOurUserModeModuleEntry(
TimerObjectValidateProcessModuleCallback,
session);
KeReleaseGuardedMutex(&session->lock);
2024-01-14 05:31:19 +01:00
end:
2024-04-13 10:23:14 +02:00
InterlockedExchange(&timer->state, FALSE);
2024-01-12 06:40:33 +01:00
}
/*
* This routine is executed every x seconds, and is run at IRQL = DISPATCH_LEVEL
*/
2024-05-11 14:54:58 +02:00
STATIC
2024-01-12 06:40:33 +01:00
VOID
2024-08-01 06:21:53 +02:00
TimerObjectCallbackRoutine(
_In_ PKDPC Dpc,
_In_opt_ PVOID DeferredContext,
_In_opt_ PVOID SystemArgument1,
_In_opt_ PVOID SystemArgument2)
2024-01-12 06:40:33 +01:00
{
2024-05-11 14:54:58 +02:00
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
2024-08-04 08:30:31 +02:00
NT_ASSERT(DeferredContext != NULL);
2024-04-13 10:23:14 +02:00
2024-05-11 14:54:58 +02:00
if (!HasDriverLoaded() || !ARGUMENT_PRESENT(DeferredContext))
2024-04-13 10:23:14 +02:00
return;
2024-05-11 14:54:58 +02:00
PTIMER_OBJECT timer = (PTIMER_OBJECT)DeferredContext;
2024-04-13 10:23:14 +02:00
/* we dont want to queue our work item if it hasnt executed */
if (timer->state)
return;
/* we queue a work item because DPCs run at IRQL = DISPATCH_LEVEL and we
* need certain routines which cannot be run at an IRQL this high.*/
InterlockedExchange(&timer->state, TRUE);
2024-08-01 06:21:53 +02:00
IoQueueWorkItem(
timer->work_item,
TimerObjectWorkItemRoutine,
BackgroundWorkQueue,
timer);
2024-01-12 06:40:33 +01:00
}
NTSTATUS
InitialiseTimerObject(_Out_ PTIMER_OBJECT Timer)
{
2024-05-11 14:54:58 +02:00
LARGE_INTEGER due_time = {.QuadPart = -ABSOLUTE(SECONDS(5))};
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
Timer->work_item = IoAllocateWorkItem(GetDriverDeviceObject());
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
if (!Timer->work_item)
return STATUS_MEMORY_NOT_ALLOCATED;
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
KeInitializeDpc(&Timer->dpc, TimerObjectCallbackRoutine, Timer);
KeInitializeTimer(&Timer->timer);
KeSetTimerEx(&Timer->timer, due_time, REPEAT_TIME_10_SEC, &Timer->dpc);
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
DEBUG_VERBOSE("Successfully initialised global timer callback.");
return STATUS_SUCCESS;
2024-01-12 06:40:33 +01:00
}
VOID
2024-05-11 14:54:58 +02:00
CleanupDriverTimerObjects(_Inout_ PTIMER_OBJECT Timer)
2024-01-12 06:40:33 +01:00
{
2024-04-13 10:23:14 +02:00
/* this routine blocks until all queued DPCs on all processors have
* executed. */
KeFlushQueuedDpcs();
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
/* wait for our work item to complete */
while (Timer->state)
YieldProcessor();
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
/* now its safe to free and cancel our timers, pools etc. */
KeCancelTimer(&Timer->timer);
IoFreeWorkItem(Timer->work_item);
2024-01-12 06:40:33 +01:00
2024-04-13 10:23:14 +02:00
DEBUG_VERBOSE("Freed timer objects.");
2024-01-15 02:01:14 +01:00
}
VOID
UnregisterProcessObCallbacks()
{
2024-04-13 10:23:14 +02:00
PAGED_CODE();
PACTIVE_SESSION config = GetActiveSession();
AcquireDriverConfigLock();
if (config->callback_configuration.registration_handle) {
ImpObUnRegisterCallbacks(
config->callback_configuration.registration_handle);
config->callback_configuration.registration_handle = NULL;
}
2024-01-15 02:01:14 +01:00
2024-04-13 10:23:14 +02:00
ReleaseDriverConfigLock();
2024-01-15 02:01:14 +01:00
}
NTSTATUS
RegisterProcessObCallbacks()
{
2024-04-13 10:23:14 +02:00
PAGED_CODE();
2024-01-15 02:01:14 +01:00
2024-08-01 06:21:53 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
PACTIVE_SESSION config = GetActiveSession();
OB_CALLBACK_REGISTRATION callback_registration = {0};
2024-05-11 14:54:58 +02:00
OB_OPERATION_REGISTRATION operation_registration = {0};
2024-01-15 02:01:14 +01:00
2024-04-13 10:23:14 +02:00
DEBUG_VERBOSE("Enabling ObRegisterCallbacks.");
AcquireDriverConfigLock();
2024-01-15 02:01:14 +01:00
2024-04-13 10:23:14 +02:00
operation_registration.ObjectType = PsProcessType;
operation_registration.Operations |= OB_OPERATION_HANDLE_CREATE;
operation_registration.Operations |= OB_OPERATION_HANDLE_DUPLICATE;
2024-08-01 06:21:53 +02:00
operation_registration.PreOperation = ObPreOpCallbackRoutine;
2024-04-13 10:23:14 +02:00
operation_registration.PostOperation = ObPostOpCallbackRoutine;
2024-01-15 02:01:14 +01:00
2024-08-01 06:21:53 +02:00
callback_registration.Version = OB_FLT_REGISTRATION_VERSION;
2024-04-13 10:23:14 +02:00
callback_registration.OperationRegistration = &operation_registration;
callback_registration.OperationRegistrationCount = 1;
2024-08-01 06:21:53 +02:00
callback_registration.RegistrationContext = NULL;
2024-01-15 02:01:14 +01:00
2024-04-13 10:23:14 +02:00
status = ImpObRegisterCallbacks(
&callback_registration,
&config->callback_configuration.registration_handle);
2024-01-15 02:01:14 +01:00
2024-04-13 10:23:14 +02:00
if (!NT_SUCCESS(status))
DEBUG_ERROR("ObRegisterCallbacks failed with status %x", status);
2024-01-15 02:01:14 +01:00
2024-04-13 10:23:14 +02:00
ReleaseDriverConfigLock();
return status;
2024-01-15 02:01:14 +01:00
}
VOID
2024-01-31 08:32:13 +01:00
InitialiseObCallbacksConfiguration(_Out_ PACTIVE_SESSION ProcessConfig)
2024-01-15 02:01:14 +01:00
{
2024-04-13 10:23:14 +02:00
ImpKeInitializeGuardedMutex(&ProcessConfig->callback_configuration.lock);
2024-01-02 23:29:23 +01:00
}