2023-08-29 19:36:58 +02:00
|
|
|
#include "thread.h"
|
|
|
|
|
2023-09-27 15:10:12 +02:00
|
|
|
#include <intrin.h>
|
|
|
|
|
2023-08-29 19:36:58 +02:00
|
|
|
#include "pool.h"
|
|
|
|
#include "callbacks.h"
|
2023-09-02 15:47:15 +02:00
|
|
|
#include "driver.h"
|
|
|
|
#include "queue.h"
|
2023-08-29 19:36:58 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGE, ValidateKPCRBThreads)
|
|
|
|
#pragma alloc_text(PAGE, DetectThreadsAttachedToProtectedProcess)
|
|
|
|
#endif
|
|
|
|
|
2023-09-13 12:06:25 +02:00
|
|
|
typedef struct _KPRCB_THREAD_VALIDATION_CTX
|
|
|
|
{
|
|
|
|
UINT64 current_kpcrb_thread;
|
|
|
|
UINT8 thread_found_in_pspcidtable;
|
|
|
|
UINT8 thread_found_in_kthreadlist;
|
|
|
|
BOOLEAN finished;
|
2023-08-29 19:36:58 +02:00
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
}KPRCB_THREAD_VALIDATION_CTX, * PKPRCB_THREAD_VALIDATION_CTX;
|
2023-08-29 19:36:58 +02:00
|
|
|
|
2023-10-09 20:19:51 +02:00
|
|
|
_IRQL_always_function_min_(DISPATCH_LEVEL)
|
2023-09-27 06:22:14 +02:00
|
|
|
STATIC
|
2023-10-05 08:27:17 +02:00
|
|
|
VOID
|
2023-09-27 06:22:14 +02:00
|
|
|
KPRCBThreadValidationProcessCallback(
|
2023-10-09 09:34:30 +02:00
|
|
|
_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
2023-10-07 17:37:47 +02:00
|
|
|
_Inout_opt_ PVOID Context
|
2023-08-29 19:36:58 +02:00
|
|
|
)
|
|
|
|
{
|
2023-08-30 11:19:41 +02:00
|
|
|
UINT32 thread_id;
|
2023-10-05 08:27:17 +02:00
|
|
|
PKPRCB_THREAD_VALIDATION_CTX context = (PKPRCB_THREAD_VALIDATION_CTX)Context;
|
2023-08-30 11:19:41 +02:00
|
|
|
|
2023-10-07 17:37:47 +02:00
|
|
|
if (!Context || context->finished == TRUE)
|
2023-08-30 11:19:41 +02:00
|
|
|
return;
|
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
if (ThreadListEntry->thread == context->current_kpcrb_thread)
|
2023-08-30 11:19:41 +02:00
|
|
|
{
|
2023-10-09 09:34:30 +02:00
|
|
|
context->thread_found_in_kthreadlist = TRUE;
|
2023-08-30 11:19:41 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
thread_id = PsGetThreadId(ThreadListEntry->thread);
|
2023-08-30 11:19:41 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
if (thread_id != NULL)
|
|
|
|
{
|
|
|
|
context->thread_found_in_pspcidtable = TRUE;
|
|
|
|
context->finished = TRUE;
|
2023-08-30 11:19:41 +02:00
|
|
|
}
|
|
|
|
}
|
2023-08-29 19:36:58 +02:00
|
|
|
}
|
|
|
|
|
2023-08-30 13:15:57 +02:00
|
|
|
/*
|
|
|
|
* How this will work:
|
|
|
|
*
|
|
|
|
* 1. The KPCRB (processor control block) contains 3 pointers to 3 threads:
|
|
|
|
*
|
|
|
|
* +0x008 CurrentThread : Ptr64 _KTHREAD
|
|
|
|
* +0x010 NextThread : Ptr64 _KTHREAD
|
|
|
|
* +0x018 IdleThread : Ptr64 _KTHREAD
|
|
|
|
*
|
|
|
|
* 2. These threads are stored in a list that is seperate to the KTHREADs linked list.
|
|
|
|
* We know this because if you unlink a process, the threads are still scheduled by
|
|
|
|
* the OS, meaning the OS has a seperate list that it uses to schedule these threads.
|
|
|
|
*
|
|
|
|
* 3. From here we can firstly check if the KTHREAD is within the KTHREAD linked list,
|
|
|
|
* if it is we can then use this to check if its in the PspCidTable by passing it
|
|
|
|
* to PsGetThreadId which returns the thread id by enumerating the PspCidTable and
|
|
|
|
* finding the corresponding object pointer. If the thread id is not found, we know
|
|
|
|
* that it's been removed from the PspCidTable, and if the thread is not in any
|
|
|
|
* process' thread list , we know it's been removed from the KTHREAD linked list.
|
|
|
|
*
|
|
|
|
*/
|
2023-10-05 08:27:17 +02:00
|
|
|
VOID
|
2023-09-27 06:22:14 +02:00
|
|
|
ValidateKPCRBThreads(
|
2023-10-07 17:37:47 +02:00
|
|
|
_Inout_ PIRP Irp
|
2023-08-29 19:36:58 +02:00
|
|
|
)
|
|
|
|
{
|
2023-10-09 20:19:51 +02:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2023-08-30 11:19:41 +02:00
|
|
|
UINT64 kpcr;
|
|
|
|
UINT64 kprcb;
|
|
|
|
KAFFINITY old_affinity = { 0 };
|
2023-09-13 12:06:25 +02:00
|
|
|
KPRCB_THREAD_VALIDATION_CTX context = { 0 };
|
2023-08-30 11:19:41 +02:00
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
for (LONG processor_index = 0; processor_index < KeQueryActiveProcessorCount(0); processor_index++)
|
2023-08-30 11:19:41 +02:00
|
|
|
{
|
2023-10-06 07:47:01 +02:00
|
|
|
old_affinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1ull << processor_index));
|
2023-08-30 11:19:41 +02:00
|
|
|
|
2023-10-06 09:02:10 +02:00
|
|
|
while (KeGetCurrentProcessorNumber() != processor_index)
|
|
|
|
YieldProcessor();
|
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
kpcr = __readmsr(IA32_GS_BASE);
|
2023-08-30 11:19:41 +02:00
|
|
|
kprcb = kpcr + KPRCB_OFFSET_FROM_GS_BASE;
|
2023-10-07 17:37:47 +02:00
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (!MmIsAddressValid(kprcb + KPCRB_CURRENT_THREAD))
|
|
|
|
continue;
|
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
context.current_kpcrb_thread = *(UINT64*)(kprcb + KPCRB_CURRENT_THREAD);
|
2023-09-13 12:06:25 +02:00
|
|
|
|
2023-10-06 09:02:10 +02:00
|
|
|
DEBUG_LOG("Proc number: %lx, Current thread: %llx", processor_index, context.current_kpcrb_thread);
|
2023-10-06 07:47:01 +02:00
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
if (!context.current_kpcrb_thread)
|
2023-09-13 12:06:25 +02:00
|
|
|
continue;
|
2023-08-30 11:19:41 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
EnumerateThreadListWithCallbackRoutine(
|
2023-09-13 12:06:25 +02:00
|
|
|
KPRCBThreadValidationProcessCallback,
|
|
|
|
&context
|
2023-08-30 11:19:41 +02:00
|
|
|
);
|
|
|
|
|
2023-10-06 09:02:10 +02:00
|
|
|
DEBUG_LOG("Found in kthread: %lx, found in pspcid: %lx", (UINT32)context.thread_found_in_kthreadlist, (UINT32)context.thread_found_in_pspcidtable);
|
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
if (context.current_kpcrb_thread == FALSE || context.thread_found_in_pspcidtable == FALSE)
|
2023-08-30 11:19:41 +02:00
|
|
|
{
|
2023-10-06 07:47:01 +02:00
|
|
|
PHIDDEN_SYSTEM_THREAD_REPORT report =
|
|
|
|
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(HIDDEN_SYSTEM_THREAD_REPORT), REPORT_POOL_TAG);
|
|
|
|
|
|
|
|
if (!report)
|
|
|
|
goto increment;
|
2023-08-30 13:15:57 +02:00
|
|
|
|
2023-10-06 07:47:01 +02:00
|
|
|
report->report_code = REPORT_HIDDEN_SYSTEM_THREAD;
|
|
|
|
report->found_in_kthreadlist = context.thread_found_in_kthreadlist;
|
|
|
|
report->found_in_pspcidtable = context.thread_found_in_pspcidtable;
|
|
|
|
report->thread_id = PsGetThreadId(context.current_kpcrb_thread);
|
|
|
|
report->thread_address = context.current_kpcrb_thread;
|
2023-08-30 13:15:57 +02:00
|
|
|
|
|
|
|
RtlCopyMemory(
|
2023-10-06 07:47:01 +02:00
|
|
|
report->thread,
|
2023-09-13 12:06:25 +02:00
|
|
|
context.current_kpcrb_thread,
|
2023-10-06 07:47:01 +02:00
|
|
|
sizeof(report->thread));
|
2023-08-30 13:15:57 +02:00
|
|
|
|
2023-10-06 07:47:01 +02:00
|
|
|
InsertReportToQueue(report);
|
2023-08-30 11:19:41 +02:00
|
|
|
}
|
|
|
|
|
2023-10-06 07:47:01 +02:00
|
|
|
increment:
|
2023-10-05 08:27:17 +02:00
|
|
|
KeRevertToUserAffinityThreadEx(old_affinity);
|
2023-08-30 11:19:41 +02:00
|
|
|
}
|
2023-08-31 18:42:38 +02:00
|
|
|
}
|
|
|
|
|
2023-10-09 20:19:51 +02:00
|
|
|
_IRQL_always_function_min_(DISPATCH_LEVEL)
|
2023-09-27 06:22:14 +02:00
|
|
|
STATIC
|
2023-10-05 08:27:17 +02:00
|
|
|
VOID
|
2023-09-27 06:22:14 +02:00
|
|
|
DetectAttachedThreadsProcessCallback(
|
2023-10-09 09:34:30 +02:00
|
|
|
_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
|
2023-10-07 17:37:47 +02:00
|
|
|
_Inout_opt_ PVOID Context
|
2023-09-02 10:54:04 +02:00
|
|
|
)
|
|
|
|
{
|
2023-10-05 08:27:17 +02:00
|
|
|
UNREFERENCED_PARAMETER(Context);
|
2023-09-13 12:06:25 +02:00
|
|
|
|
2023-09-02 15:47:15 +02:00
|
|
|
PKAPC_STATE apc_state;
|
|
|
|
PEPROCESS protected_process = NULL;
|
2023-09-02 10:54:04 +02:00
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
GetProtectedProcessEProcess(&protected_process);
|
2023-09-02 15:47:15 +02:00
|
|
|
|
2023-10-05 08:27:17 +02:00
|
|
|
if (protected_process == NULL)
|
2023-09-02 10:54:04 +02:00
|
|
|
return;
|
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
apc_state = (PKAPC_STATE)((UINT64)ThreadListEntry->thread + KTHREAD_APC_STATE_OFFSET);
|
2023-09-02 10:54:04 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
if (apc_state->Process == protected_process)
|
2023-09-02 10:54:04 +02:00
|
|
|
{
|
2023-10-09 09:34:30 +02:00
|
|
|
DEBUG_LOG("Program attached to notepad: %llx", (UINT64)ThreadListEntry->thread);
|
2023-09-02 15:47:15 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
PATTACH_PROCESS_REPORT report =
|
|
|
|
ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(ATTACH_PROCESS_REPORT), REPORT_POOL_TAG);
|
2023-09-02 15:47:15 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
if (!report)
|
|
|
|
return;
|
2023-09-02 15:47:15 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
report->report_code = REPORT_ILLEGAL_ATTACH_PROCESS;
|
|
|
|
report->thread_id = PsGetThreadId(ThreadListEntry->thread);
|
|
|
|
report->thread_address = ThreadListEntry->thread;
|
2023-09-02 10:54:04 +02:00
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
InsertReportToQueue(report);
|
2023-09-02 10:54:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* I did not reverse this myself and previously had no idea how you would go about
|
|
|
|
* detecting KiAttachProcess so credits to KANKOSHEV for the explanation:
|
2023-10-05 08:27:17 +02:00
|
|
|
*
|
2023-09-02 10:54:04 +02:00
|
|
|
* https://github.com/KANKOSHEV/Detect-KeAttachProcess/tree/main
|
|
|
|
* https://doxygen.reactos.org/d0/dc9/procobj_8c.html#adec6dc539d4a5c0ee7d0f48e24ef0933
|
2023-10-05 08:27:17 +02:00
|
|
|
*
|
2023-09-02 15:47:15 +02:00
|
|
|
* To expand on his writeup a little, the offset that he provides is equivalent to PKAPC_STATE->Process.
|
|
|
|
* This is where KiAttachProcess writes the process that thread is attaching to when it's called.
|
|
|
|
* The APC_STATE structure holds relevant information about the thread's APC state and is quite
|
|
|
|
* important during context switch scenarios as it's how the thread determines if it has any APC's
|
2023-10-05 08:27:17 +02:00
|
|
|
* queued.
|
2023-09-02 10:54:04 +02:00
|
|
|
*/
|
2023-09-02 15:47:15 +02:00
|
|
|
VOID DetectThreadsAttachedToProtectedProcess()
|
2023-09-02 10:54:04 +02:00
|
|
|
{
|
2023-10-09 20:19:51 +02:00
|
|
|
PAGED_CODE();
|
|
|
|
|
2023-10-09 09:34:30 +02:00
|
|
|
EnumerateThreadListWithCallbackRoutine(
|
2023-09-13 12:06:25 +02:00
|
|
|
DetectAttachedThreadsProcessCallback,
|
|
|
|
NULL
|
2023-09-02 10:54:04 +02:00
|
|
|
);
|
|
|
|
}
|