线程创建过程分析NtCreateThread-PspCreateThread

类似于进程的创建过程:进程创建过程分析NtCreateProcess-NtCreateProcessEx-PspCreateProcess

线程的创建是从NtCreateThread函数开始的。NtCreateThread所做的事很简单,首先,对于非内核模式传递过来的调用,检查参数是否可写。处理InitialTeb参数,将它放到局部变量CapturedInitialTeb中。这些操作都是在try块中完成的。然后调用真正创建线程的函数PspCreateThread

NTSTATUS
NtCreateThread(
    __out PHANDLE ThreadHandle,
    __in ACCESS_MASK DesiredAccess,
    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
    __in HANDLE ProcessHandle,
    __out Pcreateprocess-analyseCLIENT_ID ClientId,
    __in PCONTEXT ThreadContext,
    __in PINITIAL_TEB InitialTeb,
    __in BOOLEAN CreateSuspended
    )

{
    NTSTATUS Status;
    INITIAL_TEB CapturedInitialTeb;

    PAGED_CODE();

    try {
        if (KeGetPreviousMode () != KernelMode) {
            ProbeForWriteHandle (ThreadHandle);

            if (ARGUMENT_PRESENT (ClientId)) {
                ProbeForWriteSmallStructure (ClientId, sizeof (CLIENT_ID), sizeof (ULONG));
            }

            if (ARGUMENT_PRESENT (ThreadContext) ) {
                ProbeForReadSmallStructure (ThreadContext, sizeof (CONTEXT), CONTEXT_ALIGN);
            } else {
                return STATUS_INVALID_PARAMETER;
            }
            ProbeForReadSmallStructure (InitialTeb, sizeof (InitialTeb->OldInitialTeb), sizeof (ULONG));
        }

        CapturedInitialTeb.OldInitialTeb = InitialTeb->OldInitialTeb;
        if (CapturedInitialTeb.OldInitialTeb.OldStackBase == NULL &&
            CapturedInitialTeb.OldInitialTeb.OldStackLimit == NULL) {
            CapturedInitialTeb = *InitialTeb;
        }
    } except (ExSystemExceptionFilter ()) {
        return GetExceptionCode ();
    }

    Status = PspCreateThread (ThreadHandle,
                              DesiredAccess,
                              ObjectAttributes,
                              ProcessHandle,
                              NULL,
                              ClientId,
                              ThreadContext,
                              &CapturedInitialTeb,
                              CreateSuspended,
                              NULL,
                              NULL);

    return Status;
}

下面进入PspCreateThread的流程分析。

1.得到当前线程,判断模式,得到进程对象。

CurrentThread = PsGetCurrentThread ();

   if (StartRoutine != NULL) {
       PreviousMode = KernelMode;
   } else {
       PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
   }

   Teb = NULL;

   Thread = NULL;
   Process = NULL;

   if (ProcessHandle != NULL) {

       Status = ObReferenceObjectByHandle (ProcessHandle,
                                           PROCESS_CREATE_THREAD,
                                           PsProcessType,
                                           PreviousMode,
                                           &Process,
                                           NULL);
   } else {
       if (StartRoutine != NULL) {
           ObReferenceObject (ProcessPointer);
           Process = ProcessPointer;
           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;
   }

2.调用ObCreateObject创建一个线程对象ETHREAD,并清零。

Status = ObCreateObject (PreviousMode,
                            PsThreadType,
                            ObjectAttributes,
                            PreviousMode,
                            NULL,
                            sizeof(ETHREAD),
                            0,
                            0,
                            &Thread);

   if (!NT_SUCCESS (Status)) {
       ObDereferenceObject (Process);
       return Status;
   }

   RtlZeroMemory (Thread, sizeof (ETHREAD));

3.初始化基本域。

//初始化rundown

ExInitializeRundownProtection (&Thread->RundownProtect);
  Thread->ThreadsProcess = Process;

  Thread->Cid.UniqueProcess = Process->UniqueProcessId;

  CidEntry.Object = Thread;
  CidEntry.GrantedAccess = 0;

//从CID句柄表中创建一个句柄表项
  Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);

  if (Thread->Cid.UniqueThread == NULL) {
      ObDereferenceObject (Thread);
      return (STATUS_INSUFFICIENT_RESOURCES);
  }

  Thread->ReadClusterSize = MmReadClusterSize;

  KeInitializeSemaphore (&Thread->LpcReplySemaphore, 0L, 1L);
  InitializeListHead (&Thread->LpcReplyChain);

  InitializeListHead (&Thread->IrpList);

  InitializeListHead (&Thread->PostBlockList);

  PspInitializeThreadLock (Thread);

  KeInitializeSpinLock (&Thread->ActiveTimerListLock);
  InitializeListHead (&Thread->ActiveTimerListHead);

4.获得RundownProtect锁,以避免在创建过程中该进程被停掉(rundown),直到该线程被插入到进程的线程链表中,锁才被释放。

if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
      ObDereferenceObject (Thread);
      return STATUS_PROCESS_IS_TERMINATING;
  }

5.判断是不是用户模式线程,并进行各种初始化。

if (ARGUMENT_PRESENT (ThreadContext)) {

//不为null,创建的是用户模式线程,创建TEB,并初始化

        Status = MmCreateTeb (Process, InitialTeb, &Thread->Cid, &Teb);
        if (!NT_SUCCESS (Status)) {
            ExReleaseRundownProtection (&Process->RundownProtect);
            ObDereferenceObject (Thread);
            return Status;
        }

        try {

//利用ThreadContext中的程序指针(Eip寄存器)来设置线程的启动地址
            Thread->StartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ThreadContext);

#if defined(_AMD64_)

            Thread->Win32StartAddress = (PVOID)ThreadContext->Rdx;

#elif defined(_X86_)

//将ThreadContext中的Eax寄存器设置到线程的Win32StartAddress

            Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;

#else

#error “no target architecture”

#endif

        } except (EXCEPTION_EXECUTE_HANDLER) {

            Status = GetExceptionCode();
        }

        if (NT_SUCCESS (Status)) {

//初始化一些线程属性
            Status = KeInitThread (&Thread->Tcb,
                                   NULL,
                                   PspUserThreadStartup,
                                   (PKSTART_ROUTINE)NULL,
                                   Thread->StartAddress,
                                   ThreadContext,
                                   Teb,
                                   &Process->Pcb);
       }

    } else {

//系统线程

        Teb = NULL;

//设置系统线程位
        PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SYSTEM);

        Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;
        Status = KeInitThread (&Thread->Tcb,
                               NULL,
                               PspSystemThreadStartup,
                               StartRoutine,
                               StartContext,
                               NULL,
                               NULL,
                               &Process->Pcb);
    }

    if (!NT_SUCCESS (Status)) {
        if (Teb != NULL) {
            MmDeleteTeb(Process, Teb);
        }
        ExReleaseRundownProtection (&Process->RundownProtect);
        ObDereferenceObject (Thread);
        return Status;
    }

6.锁住线程,确保此进程不是在退出或终止过程中。

PspLockProcessExclusive (Process, CurrentThread);

//进程正在结束

if ((Process->Flags&PS_PROCESS_FLAGS_PROCESS_DELETE) != 0 ||
       (((CurrentThread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) != 0) &&
       (ThreadContext != NULL) &&
       (THREAD_TO_PROCESS(CurrentThread) == Process))) {

       PspUnlockProcessExclusive (Process, CurrentThread);

       KeUninitThread (&Thread->Tcb);

       if (Teb != NULL) {
           MmDeleteTeb(Process, Teb);
       }
       ExReleaseRundownProtection (&Process->RundownProtect);
       ObDereferenceObject(Thread);

       return STATUS_PROCESS_IS_TERMINATING;
   }

7.进程的活动线程+1,加入线程链表。

OldActiveThreads = Process->ActiveThreads++;
   InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);

   KeStartThread (&Thread->Tcb);

   PspUnlockProcessExclusive (Process, CurrentThread);

   ExReleaseRundownProtection (&Process->RundownProtect);

8.若是进程的第一个线程,则触发该进程的创建通知。

if (OldActiveThreads == 0) {
        PERFINFO_PROCESS_CREATE (Process);

        if (PspCreateProcessNotifyRoutineCount != 0) {
            ULONG i;
            PEX_CALLBACK_ROUTINE_BLOCK CallBack;
            PCREATE_PROCESS_NOTIFY_ROUTINE Rtn;

            for (i=0; i<PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
                CallBack = ExReferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i]);
                if (CallBack != NULL) {
                    Rtn = (PCREATE_PROCESS_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
                    Rtn (Process->InheritedFromUniqueProcessId,
                         Process->UniqueProcessId,
                         TRUE);
                    ExDereferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i],
                                                CallBack);
                }
            }
        }
    }

9.如果新线程的进程在一个作业中,则需要做特定的处理。

Job = Process->Job;
    if (Job != NULL && Job->CompletionPort &&
        !(Process->JobStatus & (PS_JOB_STATUS_NOT_REALLY_ACTIVE|PS_JOB_STATUS_NEW_PROCESS_REPORTED))) {

        PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_NEW_PROCESS_REPORTED);

        KeEnterCriticalRegionThread (&CurrentThread->Tcb);
        ExAcquireResourceSharedLite (&Job->JobLock, TRUE);
        if (Job->CompletionPort != NULL) {
            IoSetIoCompletion (Job->CompletionPort,
                               Job->CompletionKey,
                               (PVOID)Process->UniqueProcessId,
                               STATUS_SUCCESS,
                               JOB_OBJECT_MSG_NEW_PROCESS,
                               FALSE);
        }
        ExReleaseResourceLite (&Job->JobLock);
        KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
    }

    PERFINFO_THREAD_CREATE(Thread, InitialTeb);

10.通知接受线程创建事件的出调例程。

if (PspCreateThreadNotifyRoutineCount != 0) {
        ULONG i;
        PEX_CALLBACK_ROUTINE_BLOCK CallBack;
        PCREATE_THREAD_NOTIFY_ROUTINE Rtn;

        for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
            CallBack = ExReferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i]);
            if (CallBack != NULL) {
                Rtn = (PCREATE_THREAD_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
                Rtn (Thread->Cid.UniqueProcess,
                     Thread->Cid.UniqueThread,
                     TRUE);
                ExDereferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i],
                                            CallBack);
            }
        }
    }

11.线程对象的引用计数加2,一个针对当前的创建操作,另一个针对要返回的线程句柄。

ObReferenceObjectEx (Thread, 2);

12.如果CreateSuspended指示新线程立即被挂起,则调用KeSuspendThread挂起线程。

if (CreateSuspended) {
        try {
            KeSuspendThread (&Thread->Tcb);
        } except ((GetExceptionCode () == STATUS_SUSPEND_COUNT_EXCEEDED)?
                     EXCEPTION_EXECUTE_HANDLER :
                     EXCEPTION_CONTINUE_SEARCH) {
        }
        if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) {
            KeForceResumeThread (&Thread->Tcb);
        }
    }

13.根据指定的期望访问权限,调用SeCreateAccessStateEx函数创建一个访问状态结构

AccessState = NULL;
    if (!PsUseImpersonationToken) {
        AccessState = &LocalAccessState;
        Status = SeCreateAccessStateEx (NULL,
                                        ARGUMENT_PRESENT (ThreadContext)?PsGetCurrentProcessByThread (CurrentThread) : Process,
                                        AccessState,
                                        &AuxData,
                                        DesiredAccess,
                                        &PsThreadType->TypeInfo.GenericMapping);

        if (!NT_SUCCESS (Status)) {
            PS_SET_BITS (&Thread->CrossThreadFlags,
                         PS_CROSS_THREAD_FLAGS_DEADTHREAD);

            if (CreateSuspended) {
                (VOID) KeResumeThread (&Thread->Tcb);
            }
            KeReadyThread (&Thread->Tcb);
            ObDereferenceObjectEx (Thread, 2);

            return Status;
        }
    }

14.调用ObInsertObject函数把线程对象插入到当前进程的句柄表中。

Status = ObInsertObject (Thread,
                            AccessState,
                            DesiredAccess,
                            0,
                            NULL,
                            &LocalThreadHandle);

   if (AccessState != NULL) {
       SeDeleteAccessState (AccessState);
   }

   if (!NT_SUCCESS (Status)) {

//调用失败,终止线程

       PS_SET_BITS (&Thread->CrossThreadFlags,
                    PS_CROSS_THREAD_FLAGS_DEADTHREAD);

       if (CreateSuspended) {
           KeResumeThread (&Thread->Tcb);
       }

   } else {

       try {

//设置ThreadHandle 、ClientId

           *ThreadHandle = LocalThreadHandle;
           if (ARGUMENT_PRESENT (ClientId)) {
               *ClientId = Thread->Cid;
           }
       } except(EXCEPTION_EXECUTE_HANDLER) {

           PS_SET_BITS (&Thread->CrossThreadFlags,
                        PS_CROSS_THREAD_FLAGS_DEADTHREAD);

           if (CreateSuspended) {
               (VOID) KeResumeThread (&Thread->Tcb);
           }
           KeReadyThread (&Thread->Tcb);
           ObDereferenceObject (Thread);
           ObCloseHandle (LocalThreadHandle, PreviousMode);
           return GetExceptionCode();
       }
   }

15.设置线程的创建时间。

KeQuerySystemTime(&CreateTime);

ASSERT ((CreateTime.HighPart & 0xf0000000) == 0);
    PS_SET_THREAD_CREATE_TIME(Thread, CreateTime);

16.设置线程的访问权限
if ((Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) == 0) {
    Status = ObGetObjectSecurity (Thread,
                                  &SecurityDescriptor,
                                  &MemoryAllocated);
    if (!NT_SUCCESS (Status)) {
        PS_SET_BITS (&Thread->CrossThreadFlags,
                     PS_CROSS_THREAD_FLAGS_DEADTHREAD);

        if (CreateSuspended) {
            KeResumeThread(&Thread->Tcb);
        }
        KeReadyThread (&Thread->Tcb);
        ObDereferenceObject (Thread);
        ObCloseHandle (LocalThreadHandle, PreviousMode);
        return Status;
    }

    SubjectContext.ProcessAuditId = Process;
    SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
    SubjectContext.ClientToken = NULL;

    AccessCheck = SeAccessCheck (SecurityDescriptor,
                                 &SubjectContext,
                                 FALSE,
                                 MAXIMUM_ALLOWED,
                                 0,
                                 NULL,
                                 &PsThreadType->TypeInfo.GenericMapping,
                                 PreviousMode,
                                 &Thread->GrantedAccess,
                                 &accesst);

    PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);

    ObReleaseObjectSecurity (SecurityDescriptor,
                             MemoryAllocated);

    if (!AccessCheck) {
        Thread->GrantedAccess = 0;
    }

    Thread->GrantedAccess |= (THREAD_TERMINATE | THREAD_SET_INFORMATION | THREAD_QUERY_INFORMATION);

} else {
    Thread->GrantedAccess = THREAD_ALL_ACCESS;
}

17.调用KeReadyThread,使线程进入“就绪”状态,准备马上执行。或者此时进程未在内存中,则新线程的状态为“转移”,以等待换入内存后再执行。引用计数减1.

KeReadyThread (&Thread->Tcb);
  ObDereferenceObject (Thread);

  return Status;

至此线程的创建过程就完成了。

本文链接:http://www.alonemonkey.com/createthread-analyse.html