到底一个线程是怎么样创建的呢?又是怎么样放到就绪队列呢?
#001 NTSTATUS
#002 NTAPI
#003 PspCreateThread(OUT PHANDLE ThreadHandle,
#004 IN ACCESS_MASK DesiredAccess,
#005 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
#006 IN HANDLE ProcessHandle,
#007 IN PEPROCESS TargetProcess,
#008 OUT PCLIENT_ID ClientId,
#009 IN PCONTEXT ThreadContext,
#010 IN PINITIAL_TEB InitialTeb,
#011 IN BOOLEAN CreateSuspended,
#012 IN PKSTART_ROUTINE StartRoutine OPTIONAL,
#013 IN PVOID StartContext OPTIONAL)
#014 {
#015 HANDLE hThread;
#016 PEPROCESS Process;
#017 PETHREAD Thread;
#018 PTEB TebBase = NULL;
获取当前处理器的模式,比如内核模式、用户模式、最大模式。
#019 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
#020 NTSTATUS Status, AccessStatus;
#021 HANDLE_TABLE_ENTRY CidEntry;
#022 ACCESS_STATE LocalAccessState;
#023 PACCESS_STATE AccessState = &LocalAccessState;
#024 AUX_ACCESS_DATA AuxData;
#025 BOOLEAN Result, SdAllocated;
#026 PSECURITY_DESCRIPTOR SecurityDescriptor;
#027 SECURITY_SUBJECT_CONTEXT SubjectContext;
判断代码是否可以执行。
#028 PAGED_CODE();
#029 PSTRACE(PS_THREAD_DEBUG,
#030 "ThreadContext: %p TargetProcess: %p ProcessHandle: %p/n",
#031 ThreadContext, TargetProcess, ProcessHandle);
#032
当从函数PsCreateSystemThread里调用时,当前肯定是运行在内核模式,也就是通过是否有回调函数StartRoutine来判断的。
#033 /* If we were called from PsCreateSystemThread, then we're kernel mode */
#034 if (StartRoutine) PreviousMode = KernelMode;
#035
获取线程所属的进程结构。
#036 /* Reference the Process by handle or pointer, depending on what we got */
#037 if (ProcessHandle)
#038 {
通过进程句柄到对象
#039 /* Normal thread or System Thread */
#040 Status = ObReferenceObjectByHandle(ProcessHandle,
#041 PROCESS_CREATE_THREAD,
#042 PsProcessType,
#043 PreviousMode,
#044 (PVOID*)&Process,
#045 NULL);
#046 PSREFTRACE(Process);
#047 }
#048 else
#049 {
获取系统线程的进程对象,或者普通线程的进程有问题。
#050 /* System thread inside System Process, or Normal Thread with a bug */
#051 if (StartRoutine)
#052 {
#053 /* Reference the Process by Pointer */
#054 ObReferenceObject(TargetProcess);
#055 Process = TargetProcess;
#056 Status = STATUS_SUCCESS;
#057 }
#058 else
#059 {
#060 /* Fake ObReference returning this */
#061 Status = STATUS_INVALID_HANDLE;
#062 }
#063 }
#064
#065 /* Check for success */
#066 if (!NT_SUCCESS(Status)) return Status;
#067
如果不是内核模式,不让创建线程。
#068 /* Also make sure that User-Mode isn't trying to create a system thread */
#069 if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
#070 {
#071 /* Fail */
#072 ObDereferenceObject(Process);
#073 return STATUS_INVALID_HANDLE;
#074 }
#075
创建一个线程对象。
#076 /* Create Thread Object */
#077 Status = ObCreateObject(PreviousMode,
#078 PsThreadType,
#079 ObjectAttributes,
#080 PreviousMode,
#081 NULL,
#082 sizeof(ETHREAD),
#083 0,
#084 0,
#085 (PVOID*)&Thread);
#086 if (!NT_SUCCESS(Status))
#087 {
#088 /* We failed; dereference the process and exit */
#089 ObDereferenceObject(Process);
#090 return Status;
#091 }
#092
初始化线程对象。
#093 /* Zero the Object entirely */
#094 RtlZeroMemory(Thread, sizeof(ETHREAD));
#095
#096 /* Initialize rundown protection */
#097 ExInitializeRundownProtection(&Thread->RundownProtect);
#098
设置线程退出码。
#099 /* Initialize exit code */
#100 Thread->ExitStatus = STATUS_PENDING;
#101
设置线程的进程ID。
#102 /* Set the Process CID */
#103 Thread->ThreadsProcess = Process;
#104 Thread->Cid.UniqueProcess = Process->UniqueProcessId;
#105
创建线程的ID。
#106 /* Create Cid Handle */
#107 CidEntry.Object = Thread;
#108 CidEntry.GrantedAccess = 0;
#109 Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry);
#110 if (!Thread->Cid.UniqueThread)
#111 {
#112 /* We couldn't create the CID, dereference the thread and fail */
#113 ObDereferenceObject(Thread);
#114 return STATUS_INSUFFICIENT_RESOURCES;
#115 }
保存读取的族大小。
#116
#117 /* Save the read cluster size */
#118 Thread->ReadClusterSize = MmReadClusterSize;
#119
初始化LPC信号量。
#120 /* Initialize the LPC Reply Semaphore */
#121 KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1);
#122
初始化线程的列表和锁。
#123 /* Initialize the list heads and locks */
#124 InitializeListHead(&Thread->LpcReplyChain);
#125 InitializeListHead(&Thread->IrpList);
#126 InitializeListHead(&Thread->PostBlockList);
#127 InitializeListHead(&Thread->ActiveTimerListHead);
#128 KeInitializeSpinLock(&Thread->ActiveTimerListLock);
#129
#130 /* Acquire rundown protection */
#131 if (!ExAcquireRundownProtection (&Process->RundownProtect))
#132 {
#133 /* Fail */
#134 ObDereferenceObject(Thread);
#135 return STATUS_PROCESS_IS_TERMINATING;
#136 }
#137
初始化线程的TEB环境块。
#138 /* Now let the kernel initialize the context */
#139 if (ThreadContext)
#140 {
#141 /* User-mode Thread, create Teb */
#142 TebBase = MmCreateTeb(Process, &Thread->Cid, InitialTeb);
#143 if (!TebBase)
#144 {
#145 /* Failed to create the TEB. Release rundown and dereference */
#146 ExReleaseRundownProtection(&Process->RundownProtect);
#147 ObDereferenceObject(Thread);
#148 return STATUS_INSUFFICIENT_RESOURCES;
#149 }
#150
#151 /* Set the Start Addresses */
#152 #if defined(_M_IX86)
#153 Thread->StartAddress = (PVOID)ThreadContext->Eip;
#154 Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
#155 #elif defined(_M_PPC)
#156 Thread->StartAddress = (PVOID)ThreadContext->Dr0;
#157 Thread->Win32StartAddress = (PVOID)ThreadContext->Gpr3;
#158 #elif defined(_M_MIPS)
#159 Thread->StartAddress = (PVOID)ThreadContext->Psr;
#160 Thread->Win32StartAddress = (PVOID)ThreadContext->IntA0;
#161 #elif defined(_M_ARM)
#162 Thread->StartAddress = (PVOID)ThreadContext->Pc;
#163 Thread->Win32StartAddress = (PVOID)ThreadContext->R0;
#164 #elif defined(_M_AMD64)
#165 Thread->StartAddress = (PVOID)ThreadContext->Rip;
#166 Thread->Win32StartAddress = (PVOID)ThreadContext->Rax;
#167 #else
#168 #error Unknown architecture
#169 #endif
#170
#171 /* Let the kernel intialize the Thread */
#172 Status = KeInitThread(&Thread->Tcb,
#173 NULL,
#174 PspUserThreadStartup,
#175 NULL,
#176 Thread->StartAddress,
#177 ThreadContext,
#178 TebBase,
#179 &Process->Pcb);
#180 }
#181 else
#182 {
创建系统线程。
#183 /* System Thread */
#184 Thread->StartAddress = StartRoutine;
#185 PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT);
#186
#187 /* Let the kernel intialize the Thread */
#188 Status = KeInitThread(&Thread->Tcb,
#189 NULL,
#190 PspSystemThreadStartup,
#191 StartRoutine,
#192 StartContext,
#193 NULL,
#194 NULL,
#195 &Process->Pcb);
#196 }
#197
初始化线程失败,就清除分配的资源。
#198 /* Check if we failed */
#199 if (!NT_SUCCESS(Status))
#200 {
#201 /* Delete the TEB if we had done */
#202 if (TebBase) MmDeleteTeb(Process, TebBase);
#203
#204 /* Release rundown and dereference */
#205 ExReleaseRundownProtection(&Process->RundownProtect);
#206 ObDereferenceObject(Thread);
#207 return Status;
#208 }
#209
检查进程是否已经删除。
#210 /* Lock the process */
#211 KeEnterCriticalRegion();
#212 ExAcquirePushLockExclusive(&Process->ProcessLock);
#213
#214 /* Make sure the proces didn't just die on us */
#215 if (Process->ProcessDelete) goto Quickie;
#216
#217 /* Check if the thread was ours, terminated and it was user mode */
#218 if ((Thread->Terminated) &&
#219 (ThreadContext) &&
#220 (Thread->ThreadsProcess == Process))
#221 {
#222 /* Cleanup, we don't want to start it up and context switch */
#223 goto Quickie;
#224 }
#225
把新创建的线程放到进程的线程列表里。
#226 /*
#227 * Insert the Thread into the Process's Thread List
#228 * Note, this is the ETHREAD Thread List. It is removed in
#229 * ps/kill.c!PspExitThread.
#230 */
#231 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
#232 Process->ActiveThreads++;
#233
设置启动线程。
#234 /* Start the thread */
#235 KeStartThread(&Thread->Tcb);
#236
#237 /* Release the process lock */
#238 ExReleasePushLockExclusive(&Process->ProcessLock);
#239 KeLeaveCriticalRegion();
#240
#241 /* Release rundown */
#242 ExReleaseRundownProtection(&Process->RundownProtect);
#243
#244 /* Notify WMI */
#245 //WmiTraceProcess(Process, TRUE);
#246 //WmiTraceThread(Thread, InitialTeb, TRUE);
#247
通知线程创建。
#248 /* Notify Thread Creation */
#249 PspRunCreateThreadNotifyRoutines(Thread, TRUE);
#250
#251 /* Reference ourselves as a keep-alive */
#252 ObReferenceObjectEx(Thread, 2);
#253
检查是否需要挂起线程执行。
#254 /* Suspend the Thread if we have to */
#255 if (CreateSuspended) KeSuspendThread(&Thread->Tcb);
#256
终止线程的执行。
#257 /* Check if we were already terminated */
#258 if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb);
#259
#260 /* Create an access state */
#261 Status = SeCreateAccessStateEx(NULL,
#262 ThreadContext ?
#263 PsGetCurrentProcess() : Process,
#264 &LocalAccessState,
#265 &AuxData,
#266 DesiredAccess,
#267 &PsThreadType->TypeInfo.GenericMapping);
#268 if (!NT_SUCCESS(Status))
#269 {
#270 /* Access state failed, thread is dead */
#271 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
#272
#273 /* If we were suspended, wake it up */
#274 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
#275
#276 /* Dispatch thread */
#277 KeReadyThread(&Thread->Tcb);
#278
#279 /* Dereference completely to kill it */
#280 ObDereferenceObjectEx(Thread, 2);
#281 return Status;
#282 }
#283
把线程放到对象管理器。
#284 /* Insert the Thread into the Object Manager */
#285 Status = ObInsertObject(Thread,
#286 AccessState,
#287 DesiredAccess,
#288 0,
#289 NULL,
#290 &hThread);
#291
#292 /* Delete the access state if we had one */
#293 if (AccessState) SeDeleteAccessState(AccessState);
#294
通过SEH机制保存线程ID和线程句柄给用户空间的变量。
#295 /* Check for success */
#296 if (NT_SUCCESS(Status))
#297 {
#298 /* Wrap in SEH to protect against bad user-mode pointers */
#299 _SEH2_TRY
#300 {
#301 /* Return Cid and Handle */
#302 if (ClientId) *ClientId = Thread->Cid;
#303 *ThreadHandle = hThread;
#304 }
#305 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
#306 {
#307 /* Get the exception code */
#308 Status = _SEH2_GetExceptionCode();
#309
#310 /* Thread insertion failed, thread is dead */
#311 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
#312
#313 /* If we were suspended, wake it up */
#314 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
#315
#316 /* Dispatch thread */
#317 KeReadyThread(&Thread->Tcb);
#318
#319 /* Dereference it, leaving only the keep-alive */
#320 ObDereferenceObject(Thread);
#321
#322 /* Close its handle, killing it */
#323 ObCloseHandle(ThreadHandle, PreviousMode);
#324 }
#325 _SEH2_END;
#326 if (!NT_SUCCESS(Status)) return Status;
#327 }
#328 else
#329 {
#330 /* Thread insertion failed, thread is dead */
#331 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
#332
#333 /* If we were suspended, wake it up */
#334 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
#335 }
#336
获取线程创建时间。
#337 /* Get the create time */
#338 KeQuerySystemTime(&Thread->CreateTime);
#339 ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
#340
#341 /* Make sure the thread isn't dead */
#342 if (!Thread->DeadThread)
#343 {
#344 /* Get the thread's SD */
#345 Status = ObGetObjectSecurity(Thread,
#346 &SecurityDescriptor,
#347 &SdAllocated);
#348 if (!NT_SUCCESS(Status))
#349 {
#350 /* Thread insertion failed, thread is dead */
#351 PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT);
#352
#353 /* If we were suspended, wake it up */
#354 if (CreateSuspended) KeResumeThread(&Thread->Tcb);
#355
#356 /* Dispatch thread */
#357 KeReadyThread(&Thread->Tcb);
#358
#359 /* Dereference it, leaving only the keep-alive */
#360 ObDereferenceObject(Thread);
#361
#362 /* Close its handle, killing it */
#363 ObCloseHandle(ThreadHandle, PreviousMode);
#364 return Status;
#365 }
#366
设置线程安全环境变量。
#367 /* Create the subject context */
#368 SubjectContext.ProcessAuditId = Process;
#369 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
#370 SubjectContext.ClientToken = NULL;
#371
#372 /* Do the access check */
#373 Result = SeAccessCheck(SecurityDescriptor,
#374 &SubjectContext,
#375 FALSE,
#376 MAXIMUM_ALLOWED,
#377 0,
#378 NULL,
#379 &PsThreadType->TypeInfo.GenericMapping,
#380 PreviousMode,
#381 &Thread->GrantedAccess,
#382 &AccessStatus);
#383
#384 /* Dereference the token and let go the SD */
#385 ObFastDereferenceObject(&Process->Token,
#386 SubjectContext.PrimaryToken);
#387 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
#388
#389 /* Remove access if it failed */
#390 if (!Result) Process->GrantedAccess = 0;
#391
#392 /* Set least some minimum access */
#393 Thread->GrantedAccess |= (THREAD_TERMINATE |
#394 THREAD_SET_INFORMATION |
#395 THREAD_QUERY_INFORMATION);
#396 }
#397 else
#398 {
#399 /* Set the thread access mask to maximum */
#400 Thread->GrantedAccess = THREAD_ALL_ACCESS;
#401 }
#402
标记线程已经可以运行,把线程放到准备就绪队列。
#403 /* Dispatch thread */
#404 KeReadyThread(&Thread->Tcb);
#405
#406 /* Dereference it, leaving only the keep-alive */
#407 ObDereferenceObject(Thread);
#408
#409 /* Return */
#410 return Status;
#411
出错处理。
#412 /* Most annoying failure case ever, where we undo almost all manually */
#413 Quickie:
#414 /* When we get here, the process is locked, unlock it */
#415 ExReleasePushLockExclusive(&Process->ProcessLock);
#416 KeLeaveCriticalRegion();
#417
#418 /* Uninitailize it */
#419 KeUninitThread(&Thread->Tcb);
#420
#421 /* If we had a TEB, delete it */
#422 if (TebBase) MmDeleteTeb(Process, TebBase);
#423
#424 /* Release rundown protection, which we also hold */
#425 ExReleaseRundownProtection(&Process->RundownProtect);
#426
#427 /* Dereference the thread and return failure */
#428 ObDereferenceObject(Thread);
#429 return STATUS_PROCESS_IS_TERMINATING;
#430 }
通上面函数分析,已经了解一个线程创建,不但可以创建系统线程,还可以创建用户线程。当初始化线程后,就可以把线程放到调度就绪队列,准备给下一轮调试使用。