mirror-ac/driver/thread.c

123 lines
4.6 KiB
C
Raw Normal View History

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"
#include "imports.h"
2023-08-29 19:36:58 +02:00
2023-10-09 09:34:30 +02:00
#ifdef ALLOC_PRAGMA
2023-12-13 05:06:27 +01:00
# pragma alloc_text(PAGE, DetectThreadsAttachedToProtectedProcess)
# pragma alloc_text(PAGE, ValidateThreadsPspCidTableEntry)
2023-10-09 09:34:30 +02:00
#endif
BOOLEAN
ValidateThreadsPspCidTableEntry(_In_ PETHREAD Thread)
2023-08-29 19:36:58 +02:00
{
2023-12-13 05:06:27 +01:00
PAGED_CODE();
2023-10-09 20:19:51 +02:00
NTSTATUS status = STATUS_UNSUCCESSFUL;
HANDLE thread_id = NULL;
PETHREAD thread = NULL;
/*
* PsGetThreadId simply returns ETHREAD->Cid.UniqueThread
*/
thread_id = ImpPsGetThreadId(Thread);
/*
* For each core on the processor, the first x threads equal to x cores will be assigned a
* cid equal to its equivalent core. These threads are generally executing the HLT
* instruction or some other boring stuff while the processor is not busy. The reason this
* is important is because passing in a handle value of 0 which, even though is a valid cid,
* returns a non success status meaning we mark it an invalid cid entry even though it is.
* To combat this we simply add a little check here. The problem is this can be easily
2023-12-31 15:06:24 +01:00
* bypassed by simply modifying the ETHREAD->Cid.UniqueThread identifier.. So while it isnt
* a perfect detection method for now it's good enough.
*/
if ((UINT64)thread_id < (UINT64)ImpKeQueryActiveProcessorCount(NULL))
return TRUE;
/*
* PsLookupThreadByThreadId will use a threads id to find its cid entry, and return
* the pointer contained in the HANDLE_TABLE entry pointing to the thread object.
* Meaning if we pass a valid thread id which we retrieved above and dont receive a
* STATUS_SUCCESS the cid entry could potentially be removed or disrupted..
*/
status = ImpPsLookupThreadByThreadId(thread_id, &thread);
if (!NT_SUCCESS(status))
2023-12-13 05:06:27 +01:00
{
DEBUG_WARNING(
"Failed to lookup thread by id. PspCidTable entry potentially removed.");
return FALSE;
2023-12-13 05:06:27 +01:00
}
return TRUE;
2023-08-31 18:42:38 +02:00
}
2023-12-31 15:06:24 +01: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 find:
2023-12-31 15:06:24 +01:00
*
* https://github.com/KANKOSHEV/Detect-KeAttachProcess/tree/main
* https://doxygen.reactos.org/d0/dc9/procobj_8c.html#adec6dc539d4a5c0ee7d0f48e24ef0933
*
* 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 queued.
*/
2024-01-08 04:57:07 +01:00
STATIC VOID
DetectAttachedThreadsProcessCallback(_In_ PTHREAD_LIST_ENTRY ThreadListEntry,
_Inout_opt_ PVOID Context)
2023-09-02 10:54:04 +02:00
{
2023-12-13 05:06:27 +01:00
UNREFERENCED_PARAMETER(Context);
2023-09-13 12:06:25 +02:00
2023-12-13 05:06:27 +01:00
PKAPC_STATE apc_state = NULL;
PEPROCESS protected_process = NULL;
2023-09-02 10:54:04 +02:00
2023-12-13 05:06:27 +01:00
GetProtectedProcessEProcess(&protected_process);
2023-09-02 15:47:15 +02:00
2023-12-31 15:06:24 +01:00
if (!protected_process)
2023-12-13 05:06:27 +01:00
return;
2023-09-02 10:54:04 +02:00
2023-12-13 05:06:27 +01:00
apc_state = (PKAPC_STATE)((UINT64)ThreadListEntry->thread + KTHREAD_APC_STATE_OFFSET);
2023-09-02 10:54:04 +02:00
2023-12-31 15:06:24 +01:00
/*
2024-01-14 05:31:19 +01:00
* We don't care if a thread owned by our protected process is attached
*
* todo: this is filterless and will just report anything, need to have a look into what
* processes actually attach to real games
2023-12-31 15:06:24 +01:00
*/
2024-01-14 05:31:19 +01:00
if (apc_state->Process == protected_process &&
ThreadListEntry->owning_process != protected_process)
2023-12-13 05:06:27 +01:00
{
2023-12-23 19:52:55 +01:00
DEBUG_WARNING("Thread is attached to our protected process: %llx",
(UINT64)ThreadListEntry->thread);
2023-09-02 15:47:15 +02:00
PATTACH_PROCESS_REPORT report = ImpExAllocatePool2(
2023-12-13 05:06:27 +01:00
POOL_FLAG_NON_PAGED, sizeof(ATTACH_PROCESS_REPORT), REPORT_POOL_TAG);
2023-09-02 15:47:15 +02:00
2023-12-13 05:06:27 +01:00
if (!report)
return;
2023-09-02 15:47:15 +02:00
2023-12-13 05:06:27 +01:00
report->report_code = REPORT_ILLEGAL_ATTACH_PROCESS;
report->thread_id = ImpPsGetThreadId(ThreadListEntry->thread);
2023-12-13 05:06:27 +01:00
report->thread_address = ThreadListEntry->thread;
2023-09-02 10:54:04 +02:00
2023-12-13 05:06:27 +01:00
InsertReportToQueue(report);
}
2023-09-02 10:54:04 +02:00
}
2023-12-13 05:06:27 +01:00
VOID
DetectThreadsAttachedToProtectedProcess()
2023-09-02 10:54:04 +02:00
{
2023-12-13 05:06:27 +01:00
PAGED_CODE();
2024-01-14 05:31:19 +01:00
DEBUG_VERBOSE("Detecting threads attached to our process...");
2023-12-13 05:06:27 +01:00
EnumerateThreadListWithCallbackRoutine(DetectAttachedThreadsProcessCallback, NULL);
2023-09-02 10:54:04 +02:00
}