Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/ps/thread.c * PURPOSE: Process Manager: Thread Management * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Thomas Weidenmueller (w3seek@reactos.org) */
/* INCLUDES ****************************************************************/
#include <ntoskrnl.h>#define NDEBUG#include <debug.h>
/* GLOBALS ******************************************************************/
extern BOOLEAN CcPfEnablePrefetcher;extern ULONG MmReadClusterSize;POBJECT_TYPE PsThreadType = NULL;
/* PRIVATE FUNCTIONS *********************************************************/
VOIDNTAPIPspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext){ PETHREAD Thread; PTEB Teb; BOOLEAN DeadThread = FALSE; KIRQL OldIrql; PAGED_CODE(); PSTRACE(PS_THREAD_DEBUG, "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
/* Go to Passive Level */ KeLowerIrql(PASSIVE_LEVEL); Thread = PsGetCurrentThread();
/* Check if the thread is dead */ if (Thread->DeadThread) { /* Remember that we're dead */ DeadThread = TRUE; } else { /* Get the Locale ID and save Preferred Proc */ Teb = NtCurrentTeb(); Teb->CurrentLocale = MmGetSessionLocaleId(); Teb->IdealProcessor = Thread->Tcb.IdealProcessor; }
/* Check if this is a dead thread, or if we're hiding */ if (!(Thread->DeadThread) && !(Thread->HideFromDebugger)) { /* We're not, so notify the debugger */ DbgkCreateThread(Thread, StartContext); }
/* Make sure we're not already dead */ if (!DeadThread) { /* Check if the Prefetcher is enabled */ if (CcPfEnablePrefetcher) { /* FIXME: Prepare to prefetch this process */ }
/* Raise to APC */ KeRaiseIrql(APC_LEVEL, &OldIrql);
/* Queue the User APC */ KiInitializeUserApc(KeGetExceptionFrame(&Thread->Tcb), KeGetTrapFrame(&Thread->Tcb), PspSystemDllEntryPoint, NULL, PspSystemDllBase, NULL);
/* Lower it back to passive */ KeLowerIrql(PASSIVE_LEVEL); } else { /* We're dead, kill us now */ PspTerminateThreadByPointer(Thread, STATUS_THREAD_IS_TERMINATING, TRUE); }
/* Do we have a cookie set yet? */ while (!SharedUserData->Cookie) { LARGE_INTEGER SystemTime; ULONG NewCookie; PKPRCB Prcb;
/* Generate a new cookie */ KeQuerySystemTime(&SystemTime); Prcb = KeGetCurrentPrcb(); NewCookie = (Prcb->MmPageFaultCount ^ Prcb->InterruptTime ^ SystemTime.u.LowPart ^ SystemTime.u.HighPart ^ (ULONG)(ULONG_PTR)&SystemTime);
/* Set the new cookie*/ InterlockedCompareExchange((LONG*)&SharedUserData->Cookie, NewCookie, 0); }}
LONGPspUnhandledExceptionInSystemThread(PEXCEPTION_POINTERS ExceptionPointers){ /* Print debugging information */ DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n", ExceptionPointers); DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n", ExceptionPointers->ExceptionRecord->ExceptionCode, ExceptionPointers->ExceptionRecord->ExceptionAddress, ExceptionPointers->ExceptionRecord->ExceptionInformation[0], ExceptionPointers->ExceptionRecord->ExceptionInformation[1], ExceptionPointers->ExceptionRecord->ExceptionInformation[2], ExceptionPointers->ExceptionRecord->ExceptionInformation[3]);
/* Bugcheck the system */ KeBugCheckEx(SYSTEM_THREAD_EXCEPTION_NOT_HANDLED, ExceptionPointers->ExceptionRecord->ExceptionCode, (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress, (ULONG_PTR)ExceptionPointers->ExceptionRecord, (ULONG_PTR)ExceptionPointers->ContextRecord); return 0;}
VOIDNTAPIPspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext){ PETHREAD Thread; PSTRACE(PS_THREAD_DEBUG, "StartRoutine: %p StartContext: %p\n", StartRoutine, StartContext);
/* Unlock the dispatcher Database */ KeLowerIrql(PASSIVE_LEVEL); Thread = PsGetCurrentThread();
/* Make sure the thread isn't gone */ _SEH2_TRY { if (!(Thread->Terminated) && !(Thread->DeadThread)) { /* Call the Start Routine */ StartRoutine(StartContext); } } _SEH2_EXCEPT(PspUnhandledExceptionInSystemThread(_SEH2_GetExceptionInformation())) { /* Bugcheck if we got here */ KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED); } _SEH2_END;
/* Exit the thread */ PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE);}
NTSTATUSNTAPIPspCreateThread(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(); PSTRACE(PS_THREAD_DEBUG, "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n", ThreadContext, TargetProcess, ProcessHandle);
/* If we were called from PsCreateSystemThread, then we're kernel mode */ if (StartRoutine) PreviousMode = KernelMode;
/* Reference the Process by handle or pointer, depending on what we got */ if (ProcessHandle) { /* Normal thread or System Thread */ Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_CREATE_THREAD, PsProcessType, PreviousMode, (PVOID*)&Process, NULL); PSREFTRACE(Process); } else { /* System thread inside System Process, or Normal Thread with a bug */ if (StartRoutine) { /* Reference the Process by Pointer */ ObReferenceObject(TargetProcess); Process = TargetProcess; Status = STATUS_SUCCESS; } else { /* Fake ObReference returning this */ Status = STATUS_INVALID_HANDLE; } }
/* Check for success */ if (!NT_SUCCESS(Status)) return Status;
/* Also make sure that User-Mode isn't trying to create a system thread */ if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) { /* Fail */ ObDereferenceObject(Process); return STATUS_INVALID_HANDLE; }
/* Create Thread Object */ Status = ObCreateObject(PreviousMode, PsThreadType, ObjectAttributes, PreviousMode, NULL, sizeof(ETHREAD), 0, 0, (PVOID*)&Thread); if (!NT_SUCCESS(Status)) { /* We failed; dereference the process and exit */ ObDereferenceObject(Process); return Status; }
/* Zero the Object entirely */ RtlZeroMemory(Thread, sizeof(ETHREAD));
/* Initialize rundown protection */ ExInitializeRundownProtection(&Thread->RundownProtect);
/* Initialize exit code */ Thread->ExitStatus = STATUS_PENDING;
/* Set the Process CID */ Thread->ThreadsProcess = Process; Thread->Cid.UniqueProcess = Process->UniqueProcessId;
/* Create Cid Handle */ CidEntry.Object = Thread; CidEntry.GrantedAccess = 0; Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry); if (!Thread->Cid.UniqueThread) { /* We couldn't create the CID, dereference the thread and fail */ ObDereferenceObject(Thread); return STATUS_INSUFFICIENT_RESOURCES; }
/* Save the read cluster size */ Thread->ReadClusterSize = MmReadClusterSize;
/* Initialize the LPC Reply Semaphore */ KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);
/* Initialize the list heads and locks */ InitializeListHead(&Thread->LpcReplyChain); InitializeListHead(&Thread->IrpList); InitializeListHead(&Thread->PostBlockList); InitializeListHead(&Thread->ActiveTimerListHead); KeInitializeSpinLock(&Thread->ActiveTimerListLock);
/* Acquire rundown protection */ if (!ExAcquireRundownProtection (&Process->RundownProtect)) { /* Fail */ ObDereferenceObject(Thread); return STATUS_PROCESS_IS_TERMINATING; }
/* Now let the kernel initialize the context */ if (ThreadContext) { /* User-mode Thread, create Teb */ Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase); if (!NT_SUCCESS(Status)) { /* Failed to create the TEB. Release rundown and dereference */ ExReleaseRundownProtection(&Process->RundownProtect); ObDereferenceObject(Thread); return Status; }
/* Set the Start Addresses from the untrusted ThreadContext */ _SEH2_TRY { Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext); Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END;
/* Let the kernel intialize the Thread */ if (NT_SUCCESS(Status)) { Status = KeInitThread(&Thread->Tcb, NULL, PspUserThreadStartup, NULL, Thread->StartAddress, ThreadContext, TebBase, &Process->Pcb); } } else { /* System Thread */ Thread->StartAddress = StartRoutine; PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
/* Let the kernel intialize the Thread */ Status = KeInitThread(&Thread->Tcb, NULL, PspSystemThreadStartup, StartRoutine, StartContext, NULL, NULL, &Process->Pcb); }
/* Check if we failed */ if (!NT_SUCCESS(Status)) { /* Delete the TEB if we had done */ if (TebBase) MmDeleteTeb(Process, TebBase);
/* Release rundown and dereference */ ExReleaseRundownProtection(&Process->RundownProtect); ObDereferenceObject(Thread); return Status; }
/* Lock the process */ KeEnterCriticalRegion(); ExAcquirePushLockExclusive(&Process->ProcessLock);
/* Make sure the process didn't just die on us */ if (Process->ProcessDelete) goto Quickie;
/* Check if the thread was ours, terminated and it was user mode */ if ((Thread->Terminated) && (ThreadContext) && (Thread->ThreadsProcess == Process)) { /* Cleanup, we don't want to start it up and context switch */ goto Quickie; }
/* * Insert the Thread into the Process's Thread List * Note, this is the ETHREAD Thread List. It is removed in * ps/kill.c!PspExitThread. */ InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); Process->ActiveThreads++;
/* Start the thread */ KeStartThread(&Thread->Tcb);
/* Release the process lock */ ExReleasePushLockExclusive(&Process->ProcessLock); KeLeaveCriticalRegion();
/* Release rundown */ ExReleaseRundownProtection(&Process->RundownProtect);
/* Notify WMI */ //WmiTraceProcess(Process, TRUE); //WmiTraceThread(Thread, InitialTeb, TRUE);
/* Notify Thread Creation */ PspRunCreateThreadNotifyRoutines(Thread, TRUE);
/* Reference ourselves as a keep-alive */ ObReferenceObjectEx(Thread, 2);
/* Suspend the Thread if we have to */ if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
/* Check if we were already terminated */ if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
/* Create an access state */ Status = SeCreateAccessStateEx(NULL, ThreadContext ? PsGetCurrentProcess() : Process, &LocalAccessState, &AuxData, DesiredAccess, &PsThreadType->TypeInfo.GenericMapping); if (!NT_SUCCESS(Status)) { /* Access state failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
/* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb);
/* Dispatch thread */ KeReadyThread(&Thread->Tcb);
/* Dereference completely to kill it */ ObDereferenceObjectEx(Thread, 2); return Status; }
/* Insert the Thread into the Object Manager */ Status = ObInsertObject(Thread, AccessState, DesiredAccess, 0, NULL, &hThread);
/* Delete the access state if we had one */ if (AccessState) SeDeleteAccessState(AccessState);
/* Check for success */ if (NT_SUCCESS(Status)) { /* Wrap in SEH to protect against bad user-mode pointers */ _SEH2_TRY { /* Return Cid and Handle */ if (ClientId) *ClientId = Thread->Cid; *ThreadHandle = hThread; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Thread insertion failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
/* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb);
/* Dispatch thread */ KeReadyThread(&Thread->Tcb);
/* Dereference it, leaving only the keep-alive */ ObDereferenceObject(Thread);
/* Close its handle, killing it */ ObCloseHandle(hThread, PreviousMode);
/* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* Thread insertion failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
/* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb); }
/* Get the create time */ KeQuerySystemTime(&Thread->CreateTime); ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
/* Make sure the thread isn't dead */ if (!Thread->DeadThread) { /* Get the thread's SD */ Status = ObGetObjectSecurity(Thread, &SecurityDescriptor, &SdAllocated); if (!NT_SUCCESS(Status)) { /* Thread insertion failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
/* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb);
/* Dispatch thread */ KeReadyThread(&Thread->Tcb);
/* Dereference it, leaving only the keep-alive */ ObDereferenceObject(Thread);
/* Close its handle, killing it */ ObCloseHandle(hThread, PreviousMode); return Status; }
/* Create the subject context */ SubjectContext.ProcessAuditId = Process; SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process); SubjectContext.ClientToken = NULL;
/* Do the access check */ Result = SeAccessCheck(SecurityDescriptor, &SubjectContext, FALSE, MAXIMUM_ALLOWED, 0, NULL, &PsThreadType->TypeInfo.GenericMapping, PreviousMode, &Thread->GrantedAccess, &AccessStatus);
/* Dereference the token and let go the SD */ ObFastDereferenceObject(&Process->Token, SubjectContext.PrimaryToken); ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
/* Remove access if it failed */ if (!Result) Process->GrantedAccess = 0;
/* Set least some minimum access */ Thread->GrantedAccess |= (THREAD_TERMINATE | THREAD_SET_INFORMATION | THREAD_QUERY_INFORMATION); } else { /* Set the thread access mask to maximum */ Thread->GrantedAccess = THREAD_ALL_ACCESS; }
/* Dispatch thread */ KeReadyThread(&Thread->Tcb);
/* Dereference it, leaving only the keep-alive */ ObDereferenceObject(Thread);
/* Return */ return Status;
/* Most annoying failure case ever, where we undo almost all manually */Quickie: /* When we get here, the process is locked, unlock it */ ExReleasePushLockExclusive(&Process->ProcessLock); KeLeaveCriticalRegion();
/* Uninitailize it */ KeUninitThread(&Thread->Tcb);
/* If we had a TEB, delete it */ if (TebBase) MmDeleteTeb(Process, TebBase);
/* Release rundown protection, which we also hold */ ExReleaseRundownProtection(&Process->RundownProtect);
/* Dereference the thread and return failure */ ObDereferenceObject(Thread); return STATUS_PROCESS_IS_TERMINATING;}
/* PUBLIC FUNCTIONS **********************************************************/
/* * @implemented */NTSTATUSNTAPIPsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext){ PEPROCESS TargetProcess = NULL; HANDLE Handle = ProcessHandle; PAGED_CODE(); PSTRACE(PS_THREAD_DEBUG, "ProcessHandle: %p StartRoutine: %p StartContext: %p\n", ProcessHandle, StartRoutine, StartContext);
/* Check if we have a handle. If not, use the System Process */ if (!ProcessHandle) { Handle = NULL; TargetProcess = PsInitialSystemProcess; }
/* Call the shared function */ return PspCreateThread(ThreadHandle, DesiredAccess, ObjectAttributes, Handle, TargetProcess, ClientId, NULL, NULL, FALSE, StartRoutine, StartContext);}
/* * @implemented */NTSTATUSNTAPIPsLookupThreadByThreadId(IN HANDLE ThreadId, OUT PETHREAD *Thread){ PHANDLE_TABLE_ENTRY CidEntry; PETHREAD FoundThread; NTSTATUS Status = STATUS_INVALID_PARAMETER; PAGED_CODE(); PSTRACE(PS_THREAD_DEBUG, "ThreadId: %p\n", ThreadId); KeEnterCriticalRegion();
/* Get the CID Handle Entry */ CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId); if (CidEntry) { /* Get the Thread */ FoundThread = CidEntry->Object;
/* Make sure it's really a thread */ if (FoundThread->Tcb.Header.Type == ThreadObject) { /* Safe Reference and return it */ if (ObReferenceObjectSafe(FoundThread)) { *Thread = FoundThread; Status = STATUS_SUCCESS; } }
/* Unlock the Entry */ ExUnlockHandleTableEntry(PspCidTable, CidEntry); }
/* Return to caller */ KeLeaveCriticalRegion(); return Status;}
/* * @implemented */ULONGNTAPIPsGetThreadFreezeCount(IN PETHREAD Thread){ return Thread->Tcb.FreezeCount;}
/* * @implemented */BOOLEANNTAPIPsGetThreadHardErrorsAreDisabled(IN PETHREAD Thread){ return Thread->HardErrorsAreDisabled ? TRUE : FALSE;}
/* * @implemented */HANDLENTAPIPsGetThreadId(IN PETHREAD Thread){ return Thread->Cid.UniqueThread;}
/* * @implemented */HANDLENTAPIPsGetCurrentThreadId(VOID){ return PsGetCurrentThread()->Cid.UniqueThread;}
/* * @implemented */PEPROCESSNTAPIPsGetThreadProcess(IN PETHREAD Thread){ return Thread->ThreadsProcess;}
/* * @implemented */PEPROCESSNTAPIPsGetCurrentThreadProcess(VOID){ return PsGetCurrentThread()->ThreadsProcess;}
/* * @implemented */HANDLENTAPIPsGetThreadProcessId(IN PETHREAD Thread){ return Thread->Cid.UniqueProcess;}
/* * @implemented */HANDLENTAPIPsGetCurrentThreadProcessId(VOID){ return PsGetCurrentThread()->Cid.UniqueProcess;}
/* * @implemented */ULONGNTAPIPsGetThreadSessionId(IN PETHREAD Thread){ return MmGetSessionId(Thread->ThreadsProcess);}
/* * @implemented */PTEBNTAPIPsGetThreadTeb(IN PETHREAD Thread){ return Thread->Tcb.Teb;}
/* * @implemented */PVOIDNTAPIPsGetCurrentThreadTeb(VOID){ return PsGetCurrentThread()->Tcb.Teb;}
/* * @implemented */PVOIDNTAPIPsGetThreadWin32Thread(IN PETHREAD Thread){ return Thread->Tcb.Win32Thread;}
/* * @implemented */PVOIDNTAPIPsGetCurrentThreadWin32Thread(VOID){ return PsGetCurrentThread()->Tcb.Win32Thread;}
/* * @implemented */PVOIDNTAPIPsGetCurrentThreadWin32ThreadAndEnterCriticalRegion( _Out_ HANDLE* OutProcessId){ PETHREAD CurrentThread;
/* Get the current thread */ CurrentThread = PsGetCurrentThread();
/* Return the process id */ *OutProcessId = CurrentThread->Cid.UniqueProcess;
/* Enter critical region */ KeEnterCriticalRegion();
/* Return the win32 thread */ return CurrentThread->Tcb.Win32Thread;}
/* * @implemented */KPROCESSOR_MODENTAPIPsGetCurrentThreadPreviousMode(VOID){ return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;}
/* * @implemented */PVOIDNTAPIPsGetCurrentThreadStackBase(VOID){ return PsGetCurrentThread()->Tcb.StackBase;}
/* * @implemented */PVOIDNTAPIPsGetCurrentThreadStackLimit(VOID){ return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;}
/* * @implemented */BOOLEANNTAPIPsIsThreadTerminating(IN PETHREAD Thread){ return Thread->Terminated ? TRUE : FALSE;}
/* * @implemented */BOOLEANNTAPIPsIsSystemThread(IN PETHREAD Thread){ return Thread->SystemThread ? TRUE: FALSE;}
/* * @implemented */BOOLEANNTAPIPsIsThreadImpersonating(IN PETHREAD Thread){ return Thread->ActiveImpersonationInfo ? TRUE : FALSE;}
/* * @implemented */VOIDNTAPIPsSetThreadHardErrorsAreDisabled(IN PETHREAD Thread, IN BOOLEAN HardErrorsAreDisabled){ Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;}
/* * @implemented */PVOIDNTAPIPsSetThreadWin32Thread( _Inout_ PETHREAD Thread, _In_ PVOID Win32Thread, _In_ PVOID OldWin32Thread){ /* Are we setting the win32 process? */ if (Win32Thread != NULL) { /* Just exchange it */ return InterlockedExchangePointer(&Thread->Tcb.Win32Thread, Win32Thread); } else { /* We are resetting, only exchange when the old win32 thread matches */ return InterlockedCompareExchangePointer(&Thread->Tcb.Win32Thread, Win32Thread, OldWin32Thread); }}
NTSTATUSNTAPIPsWrapApcWow64Thread(IN OUT PVOID *ApcContext, IN OUT PVOID *ApcRoutine){ UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED;}
NTSTATUSNTAPINtCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb, IN BOOLEAN CreateSuspended){ INITIAL_TEB SafeInitialTeb; PAGED_CODE(); PSTRACE(PS_THREAD_DEBUG, "ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
/* Check if this was from user-mode */ if (KeGetPreviousMode() != KernelMode) { /* Make sure that we got a context */ if (!ThreadContext) return STATUS_INVALID_PARAMETER;
/* Protect checks */ _SEH2_TRY { /* Make sure the handle pointer we got is valid */ ProbeForWriteHandle(ThreadHandle);
/* Check if the caller wants a client id */ if (ClientId) { /* Make sure we can write to it */ ProbeForWrite(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); }
/* Make sure that the entire context is readable */ ProbeForRead(ThreadContext, sizeof(CONTEXT), sizeof(ULONG));
/* Check the Initial TEB */ ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG)); SafeInitialTeb = *InitialTeb; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* Use the Initial TEB as is */ SafeInitialTeb = *InitialTeb; }
/* Call the shared function */ return PspCreateThread(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, NULL, ClientId, ThreadContext, &SafeInitialTeb, CreateSuspended, NULL, NULL);}
/* * @implemented */NTSTATUSNTAPINtOpenThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId OPTIONAL){ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); CLIENT_ID SafeClientId; ULONG Attributes = 0; HANDLE hThread = NULL; NTSTATUS Status; PETHREAD Thread; BOOLEAN HasObjectName = FALSE; ACCESS_STATE AccessState; AUX_ACCESS_DATA AuxData; PAGED_CODE(); PSTRACE(PS_THREAD_DEBUG, "ClientId: %p ObjectAttributes: %p\n", ClientId, ObjectAttributes);
/* Check if we were called from user mode */ if (PreviousMode != KernelMode) { /* Enter SEH for probing */ _SEH2_TRY { /* Probe the thread handle */ ProbeForWriteHandle(ThreadHandle);
/* Check for a CID structure */ if (ClientId) { /* Probe and capture it */ ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG)); SafeClientId = *ClientId; ClientId = &SafeClientId; }
/* * Just probe the object attributes structure, don't capture it * completely. This is done later if necessary */ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); HasObjectName = (ObjectAttributes->ObjectName != NULL);
/* Validate user attributes */ Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else { /* Otherwise just get the data directly */ HasObjectName = (ObjectAttributes->ObjectName != NULL);
/* Still have to sanitize attributes */ Attributes = ObpValidateAttributes(ObjectAttributes->Attributes, PreviousMode); }
/* Can't pass both, fail */ if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
/* Create an access state */ Status = SeCreateAccessState(&AccessState, &AuxData, DesiredAccess, &PsThreadType->TypeInfo.GenericMapping); if (!NT_SUCCESS(Status)) return Status;
/* Check if this is a debugger */ if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode)) { /* Did he want full access? */ if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) { /* Give it to him */ AccessState.PreviouslyGrantedAccess |= THREAD_ALL_ACCESS; } else { /* Otherwise just give every other access he could want */ AccessState.PreviouslyGrantedAccess |= AccessState.RemainingDesiredAccess; }
/* The caller desires nothing else now */ AccessState.RemainingDesiredAccess = 0; }
/* Open by name if one was given */ if (HasObjectName) { /* Open it */ Status = ObOpenObjectByName(ObjectAttributes, PsThreadType, PreviousMode, &AccessState, 0, NULL, &hThread);
/* Get rid of the access state */ SeDeleteAccessState(&AccessState); } else if (ClientId) { /* Open by Thread ID */ if (ClientId->UniqueProcess) { /* Get the Process */ Status = PsLookupProcessThreadByCid(ClientId, NULL, &Thread); } else { /* Get the Process */ Status = PsLookupThreadByThreadId(ClientId->UniqueThread, &Thread); }
/* Check if we didn't find anything */ if (!NT_SUCCESS(Status)) { /* Get rid of the access state and return */ SeDeleteAccessState(&AccessState); return Status; }
/* Open the Thread Object */ Status = ObOpenObjectByPointer(Thread, Attributes, &AccessState, 0, PsThreadType, PreviousMode, &hThread);
/* Delete the access state and dereference the thread */ SeDeleteAccessState(&AccessState); ObDereferenceObject(Thread); } else { /* Neither an object name nor a client id was passed */ return STATUS_INVALID_PARAMETER_MIX; }
/* Check for success */ if (NT_SUCCESS(Status)) { /* Protect against bad user-mode pointers */ _SEH2_TRY { /* Write back the handle */ *ThreadHandle = hThread; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Get the exception code */ Status = _SEH2_GetExceptionCode(); } _SEH2_END; }
/* Return status */ return Status;}
/* EOF */