Last active
December 17, 2023 17:08
-
-
Save kuh4it/b1dfccd4332891b50eae03e7850a58d3 to your computer and use it in GitHub Desktop.
Create legit kernel system thread
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// InterDKOM - Making magic happen | |
// -> Thread.c | |
// | |
NTSTATUS | |
InterDkom::Core::PsCreateLegitSystemThread | |
(OUT PHANDLE ThreadHandle, | |
IN ACCESS_MASK DesiredAccess, | |
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, | |
IN HANDLE ProcessHandle, | |
IN PEPROCESS TargetProcess, | |
OUT PCLIENT_ID ClientId, | |
IN PCONTEXT ThreadContext, | |
IN PINITIAL_TEB InitialTeb, | |
IN BOOLEAN CreateSuspended, | |
IN PKSTART_ROUTINE StartRoutine OPTIONAL, | |
IN PVOID StartContext OPTIONAL) | |
{ | |
HANDLE hThread; | |
PEPROCESS Process; | |
PETHREAD Thread; | |
PTEB TebBase = NULL; | |
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); | |
NTSTATUS Status, AccessStatus; | |
HANDLE_TABLE_ENTRY CidEntry; | |
ACCESS_STATE LocalAccessState; | |
PACCESS_STATE AccessState = &LocalAccessState; | |
AUX_ACCESS_DATA AuxData; | |
BOOLEAN Result, SdAllocated; | |
PSECURITY_DESCRIPTOR SecurityDescriptor; | |
SECURITY_SUBJECT_CONTEXT SubjectContext; | |
PAGED_CODE(); | |
if (StartRoutine) PreviousMode = KernelMode; | |
if (ProcessHandle) | |
{ | |
Status = ObReferenceObjectByHandle(ProcessHandle, | |
PROCESS_CREATE_THREAD, | |
PsProcessType, | |
PreviousMode, | |
(PVOID*)&Process, | |
NULL); | |
PSREFTRACE(Process); | |
} | |
else | |
{ | |
if (StartRoutine) | |
{ | |
ObReferenceObject(TargetProcess); | |
Process = TargetProcess; | |
Status = STATUS_SUCCESS; | |
} | |
else | |
{ | |
Status = STATUS_INVALID_HANDLE; | |
} | |
} | |
if (!NT_SUCCESS(Status)) return Status; | |
if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) | |
{ | |
ObDereferenceObject(Process); | |
return STATUS_INVALID_HANDLE; | |
} | |
Status = ObCreateObject(PreviousMode, | |
PsThreadType, | |
ObjectAttributes, | |
PreviousMode, | |
NULL, | |
sizeof(ETHREAD), | |
0, | |
0, | |
(PVOID*)&Thread); | |
if (!NT_SUCCESS(Status)) | |
{ | |
ObDereferenceObject(Process); | |
return Status; | |
} | |
RtlZeroMemory(Thread, sizeof(ETHREAD)); | |
ExInitializeRundownProtection(&Thread->RundownProtect); | |
Thread->ExitStatus = STATUS_PENDING; | |
Thread->ThreadsProcess = Process; | |
Thread->Cid.UniqueProcess = Process->UniqueProcessId; | |
CidEntry.Object = Thread; | |
CidEntry.GrantedAccess = 0; | |
Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry); | |
if (!Thread->Cid.UniqueThread) | |
{ | |
ObDereferenceObject(Thread); | |
return STATUS_INSUFFICIENT_RESOURCES; | |
} | |
Thread->ReadClusterSize = MmReadClusterSize; | |
KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1); | |
InitializeListHead(&Thread->LpcReplyChain); | |
InitializeListHead(&Thread->IrpList); | |
InitializeListHead(&Thread->PostBlockList); | |
InitializeListHead(&Thread->ActiveTimerListHead); | |
KeInitializeSpinLock(&Thread->ActiveTimerListLock); | |
if (!ExAcquireRundownProtection(&Process->RundownProtect)) | |
{ | |
ObDereferenceObject(Thread); | |
return STATUS_PROCESS_IS_TERMINATING; | |
} | |
if (ThreadContext) | |
{ | |
Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase); | |
if (!NT_SUCCESS(Status)) | |
{ | |
ExReleaseRundownProtection(&Process->RundownProtect); | |
ObDereferenceObject(Thread); | |
return Status; | |
} | |
_SEH2_TRY | |
{ | |
// | |
// Meme it ;) | |
// | |
Thread->StartAddress = Ctx->SafeMemoryRegion.Thread(3)->StartAddress; | |
Thread->Win32StartAddress = Ctx->SafeMemoryRegion.Thread(3)->Win32StartAddress; | |
} | |
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) | |
{ | |
Status = _SEH2_GetExceptionCode(); | |
} | |
_SEH2_END; | |
if (NT_SUCCESS(Status)) | |
{ | |
Status = KeInitThread(&Thread->Tcb, | |
NULL, | |
PspUserThreadStartup, | |
NULL, | |
Thread->StartAddress, | |
ThreadContext, | |
TebBase, | |
&Process->Pcb); | |
} | |
} | |
else | |
{ | |
Thread->StartAddress = StartRoutine; | |
PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT); | |
Status = KeInitThread(&Thread->Tcb, | |
NULL, | |
PspSystemThreadStartup, | |
StartRoutine, | |
StartContext, | |
NULL, | |
NULL, | |
&Process->Pcb); | |
} | |
if (!NT_SUCCESS(Status)) | |
{ | |
if (TebBase) MmDeleteTeb(Process, TebBase); | |
ExReleaseRundownProtection(&Process->RundownProtect); | |
ObDereferenceObject(Thread); | |
return Status; | |
} | |
KeEnterCriticalRegion(); | |
ExAcquirePushLockExclusive(&Process->ProcessLock); | |
if (Process->ProcessDelete) goto Quickie; | |
if ((Thread->Terminated) && | |
(ThreadContext) && | |
(Thread->ThreadsProcess == Process)) | |
{ | |
goto Quickie; | |
} | |
// | |
// Insertion to ETHREAD list | |
// | |
InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); | |
Process->ActiveThreads++; | |
KeStartThread(&Thread->Tcb); | |
ExReleasePushLockExclusive(&Process->ProcessLock); | |
KeLeaveCriticalRegion(); | |
ExReleaseRundownProtection(&Process->RundownProtect); | |
PspRunCreateThreadNotifyRoutines(Thread, TRUE); | |
ObReferenceObjectEx(Thread, 2); | |
if (CreateSuspended) KeSuspendThread(&Thread->Tcb); | |
if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb); | |
Status = SeCreateAccessStateEx(NULL, | |
ThreadContext ? | |
PsGetCurrentProcess() : Process, | |
&LocalAccessState, | |
&AuxData, | |
DesiredAccess, | |
&PsThreadType->TypeInfo.GenericMapping); | |
if (!NT_SUCCESS(Status)) | |
{ | |
PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); | |
if (CreateSuspended) KeResumeThread(&Thread->Tcb); | |
KeReadyThread(&Thread->Tcb); | |
ObDereferenceObjectEx(Thread, 2); | |
return Status; | |
} | |
Status = ObInsertObject(Thread, | |
AccessState, | |
DesiredAccess, | |
0, | |
NULL, | |
&hThread); | |
if (AccessState) SeDeleteAccessState(AccessState); | |
if (NT_SUCCESS(Status)) | |
{ | |
// | |
// Wrap custom legit memory in SEH | |
// (Meme it ;) | |
// | |
_SEH2_TRY | |
{ | |
Mislocate(Thread->Cid, Ctx->SafeMemoryRegion, Ctx->Cid); | |
if (Ctx->Cid) Thread->Cid = Ctx->Cid; | |
if (ClientId) *ClientId = Thread->Cid; | |
*ThreadHandle = hThread; | |
} | |
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) | |
{ | |
PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); | |
if (CreateSuspended) KeResumeThread(&Thread->Tcb); | |
KeReadyThread(&Thread->Tcb); | |
ObDereferenceObject(Thread); | |
ObCloseHandle(hThread, PreviousMode); | |
_SEH2_YIELD(return _SEH2_GetExceptionCode()); | |
} | |
_SEH2_END; | |
} | |
else | |
{ | |
PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); | |
if (CreateSuspended) KeResumeThread(&Thread->Tcb); | |
} | |
// | |
// Meme it ;) | |
// | |
&Thread->CreateTime = Ctx->SafeMemoryRegion.Thread(3)->CreateTime; | |
ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000)); | |
if (!Thread->DeadThread) | |
{ | |
Status = ObGetObjectSecurity(Thread, | |
&SecurityDescriptor, | |
&SdAllocated); | |
if (!NT_SUCCESS(Status)) | |
{ | |
PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); | |
if (CreateSuspended) KeResumeThread(&Thread->Tcb); | |
KeReadyThread(&Thread->Tcb); | |
ObDereferenceObject(Thread); | |
ObCloseHandle(hThread, PreviousMode); | |
return Status; | |
} | |
SubjectContext.ProcessAuditId = Process; | |
SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process); | |
SubjectContext.ClientToken = NULL; | |
Result = SeAccessCheck(SecurityDescriptor, | |
&SubjectContext, | |
FALSE, | |
MAXIMUM_ALLOWED, | |
0, | |
NULL, | |
&PsThreadType->TypeInfo.GenericMapping, | |
PreviousMode, | |
&Thread->GrantedAccess, | |
&AccessStatus); | |
ObFastDereferenceObject(&Process->Token, | |
SubjectContext.PrimaryToken); | |
ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated); | |
if (!Result) Process->GrantedAccess = 0; | |
Thread->GrantedAccess |= (THREAD_TERMINATE | | |
THREAD_SET_INFORMATION | | |
THREAD_QUERY_INFORMATION); | |
} | |
else | |
{ | |
Thread->GrantedAccess = THREAD_ALL_ACCESS; | |
} | |
KeReadyThread(&Thread->Tcb); | |
ObDereferenceObject(Thread); | |
return Status; | |
Quickie: | |
ExReleasePushLockExclusive(&Process->ProcessLock); | |
KeLeaveCriticalRegion(); | |
KeUninitThread(&Thread->Tcb); | |
if (TebBase) MmDeleteTeb(Process, TebBase); | |
ExReleaseRundownProtection(&Process->RundownProtect); | |
ObDereferenceObject(Thread); | |
return STATUS_PROCESS_IS_TERMINATING; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment