欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【内核原理与实现 011】进程线程创建过程

程序员文章站 2022-07-13 10:52:30
...

一、进程创建过程

所有进程都通过 PspCreateProcess 函数创建,包括 System 进程。它被三个函数调用,分别是NtCreateProcessEx、PsCreateSystemProcess 和 PspInitPhase0 。

NtCreateProcessEx 是 CreateProcess 的内核服务;

PspInitPhase0 函数是系统初始化早期调用的,它创建了 System 进程,System 进程的句柄保存在全局变量 PspInitialSystemProcessHandle 中,EPROCESS 保存在 PsInitialSystemProcess 中;

PsCreateSystemProcess 是用来创建系统进程的,它创建的进程都是 PsInitialSystemProcess 的子进程。

PspCreateProcess 的大致流程在136-140页分析了。这里简单介绍一下,完整代码放在文末。

  • 创建进程对象
  • 初始化进程对象
  • 初始化内存区对象 SectionObject
  • 初始化调试端口
  • 初始化异常端口
  • 创建进程地址空间
  • 初始化进程基本优先级,CPU亲和性,页目录基址,超空间页帧号
  • 初始化进程安全属性(从父进程复制令牌)
  • 设置优先级类别
  • 初始化句柄表
  • 初始化进程地址空间
  • 创建进程ID
  • 审计此次进程创建行为
  • 作业相关操作
  • 创建或复制PEB
  • 新进程对象插入 PsActiveProcessHead 链表
  • 新进程对象插入当前进程句柄表
  • 计算新进程的基本优先级和时限重置值
  • 设置进程访问权限,当前进程句柄可访问,允许进程终止
  • 设置进程创建时间

PspCreateProcess 创建了进程,此时进程中的代码还没运行起来,进程还是死的,因为此时还没有线程,接下来介绍线程的创建过程。

二、线程创建过程

NtCreateThread 和 PsCreateSystemThread 函数会调用 PspCreateThread ,分别用于创建用户线程和系统线程。

下面简单概括 PspCreateThread 创建线程的工作,可能有遗漏或错误。

  • 获取当前CPU模式
  • 获取进程对象
  • 创建线程对象并初始化为0
  • 设置父进程
  • 创建CID
  • 初始化线程结构的部分属性
  • 初始化定时器链表
  • 如果是用户线程,创建并初始化TEB,用 ThreadConatext 初始化R0 R3的入口点
  • 如果是系统线程,用 StartRoutine 初始化R0入口点
  • 不管是用户线程还是内核线程,都调用 KeInitThread 初始化 Header, WaitBlock, ServiceTable, APC,定时器,内核栈等属性
  • 进程的活动线程计数加1
  • 新线程加入进程的线程链表
  • 调用 KeStartThread 初始化剩余的域,主要是和调度相关的优先级、时限、CPU亲和性等
  • 如果是该进程的第一个线程,则触发该进程的创建通知
  • 工作集相关的操作
  • 线程对象的引用计数加2,一个针对当前的创建操作,一个针对要返回的线程句柄
  • 如果 CreateSuspended 为真,指示新线程立即被挂起
  • 根据指定的期望访问权限,调用 SeCreateAccessStateEx 创建一个访问状态结构
  • 把新线程对象插入到当前进程的句柄表
  • 设置输出参数 ThreadHandle
  • 设置输出参数 ClientId
  • 设置线程创建时间
  • 设置线程访问权限
  • 新线程加入就绪链表,等待调度;或者此时进程不在内存中,设置新线程状态为转移
  • 引用计数减1

PspCreateThread 函数返回后,新线程随时可以被调度执行。

三、创建进程的全貌

进程创建后才创建线程,但是 PspCreateProcess 函数中根本没有创建线程的动作,也没有打开进程可执行映像文件的代码。在WRK中,我们看不到完整的进程创建过程,这是不行的!下面从 CreateProcess 函数调用开始,分析进程创建的全过程。

实际上,0环的东西已经分析过了,我们只需要分析3环 CreateProcessW 进0环之前干了啥就行。

CreateProcessW 本身没干啥,而是调用了 CreateProcessInternalW 函数,源码见文末。

CreateProcessInternalW 函数在 base\win32\client\process.c,总共 2582 行C代码,我看不懂,主要是不知道怎么把文件名转化成 SectionHandle 的,代码实在太多了,而且有很多看不懂的操作。

BOOL
WINAPI
CreateProcessInternalW(
    HANDLE hUserToken,
    LPCWSTR lpApplicationName,
    LPWSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCWSTR lpCurrentDirectory,
    LPSTARTUPINFOW lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation,
    PHANDLE hRestrictedUserToken
    )

CreateProcessInternalW 打开指定的可执行文件,并创建一个内存区对象,注意,内存区对象并没有被映射到内存中(由于目标进程尚未创建,不可能完成内存映射),但它确实是打开了。

接下来就是调用 ntdll 的 NtCreateProcessEx,通过系统调用,CPU模式变成内核模式,进入0环 KiSystemService / KiFastCallEntry 分发函数,然后调用执行体的 NtCreateProcessEx 函数。

接下来的工作我们先前已经分析过了,这里再次过一遍。NtCreateProcessEx 函数执行前面介绍的进程创建逻辑,包括创建并初始化 EPROCESS 对象,创建初始的进程地址空间,创建和初始化句柄表,设置 EPROCESS KPROCESS 的各种属性,如进程优先级,安全属性,创建时间等。到这里,执行体层的进程对象已经建立,进程地址空间已经初始化,PEB也已初始化。

接下来是创建线程,首先需要构造一个栈,和一个上下文环境。栈的大小通过映像文件获得,创建线程通过 ntdll 的 NtCreateThread 调用执行体的 NtCreateThread 完成,具体工作就是先前介绍过的,包括创建并初始化 ETHREAD,生成线程ID,建立TEB和设置线程安全性。

进程的第一个线程启动函数是 kernel32 的 BaseProcessStart ,这里创建的线程并不会立即执行,而是要等进程完全初始化后才执行。

到此为止,从内核角度来看,进程对象和第一个线程对象已经建立起来了,但是对子系统而言,进程创建才刚刚开始。kernel32 给windows子系统发送一个消息,消息中包括进程和线程的句柄、进程创建者的ID等必要信息。windows子系统 csrss.exe 接收到此消息,执行以下操作:

  • 保留一份句柄
  • 设定新进程的优先级类别
  • 在子系统中分配一个内部进程块
  • 设置新进程的异常端口,从而子系统可以接收到该进程中发生的异常
  • 对于被调试进程,设置它的调试端口,从而子系统可以接收到该进程的调试事件
  • 分配并初始化一个内部线程块,并插入到进程的线程列表中
  • 窗口会话中的进程计数加1
  • 设置进程的停机级别位默认级别
  • 将新进程插入到子系统的进程列表中
  • 分配并初始化一块内存供子系统的内核模式部分使用(W32PROCESS结构)
  • 显示应用程序启动光标

到此为止,进程环境已经建好,其线程将要使用的资源也分配好了,windows子系统已经知道并登记了此进程和线程。所以,初始线程被恢复执行,余下部分的初始化工作是在初始线程在新进程环境中完成的。在内核中,新线程启动的例程是 KiThreadStartup 函数,这是在 PspCreateThread 函数中调用 KeInitThread 时,KeInitThread 函数又调用 KiInitializeContextThread 函数来设置的。

cPublicProc _KiThreadStartup ,1
xor ebx,ebx ; clear registers
xor esi,esi ;
xor edi,edi ;
xor ebp,ebp ;
LowerIrql APC_LEVEL ; KeLowerIrql(APC_LEVEL)
pop eax ; (eax)->SystemRoutine
call eax ; SystemRoutine(StartRoutine, StartContext)
pop ecx ; (ecx) = UserContextFlag
or ecx, ecx
jz short kits10 ; No user context, go bugcheck
mov ebp,esp ; (bp) -> TrapFrame holding UserContext
jmp _KiServiceExit2
kits10: stdCall _KeBugCheck, <NO_USER_MODE_CONTEXT>
stdENDP _KiThreadStartup

KiThreadStartup 函数首先将 IRQL 降低到 APC_LEVEL,然后调用系统初始的线程函数 PspUserThreadStartup (PspCreateThread 函数在调用KeInitThread 时指定的,如果是创建系统线程,这里就是 PspSystemThreadStartup 函数)。线程启动函数被作为一个参数传递给 PspUserThreadStartup ,此处应是 kernel32 的 BaseProcessStart。

PspUserThreadStartup 函数设置异步函数调用APC机制,基本流程如下:

  • 获得当前线程和进程对象。

  • 是否由于创建过程中出错而需要终止本线程。

  • 如果需要,通知调试器。

  • 如果这是进程中的第一个线程,则判断系统是否支持应用程序预取的特性,如果
    是,则通知缓存管理器预取可执行映像文件中的页面(见2 106 行的CcPfBeginAppLaunch
    调用)。所谓应用程序预取,是指将该进程上一次启动的前10 s 内引用到的页面直接读
    入到内存中。

  • 然后,PspUserThreadStartup 把一个用户模式APC 插入到线程的用户APC 队列中,
    此APC 例程是在全局变量PspSystemDll 中指定的,指向ntdll.dll 的LdrInitializeThunk 函数。

  • 接下来填充系统范围的一个Cookie 值。

PspUserThreadStartup 返回后,KiThreadStartup 函数返回到用户模式,此时,PspUserThreadStartup 插入的APC 被交付,于是 LdrInitializeThunk 函数被调用,这是映像加载器(image loader)的初始化函数,完成加载器,堆管理器等初始化工作,然后加载必要的dll,并调用它们的入口函数。最后,当 LdrInitializeThunk 返回到用户模式 APC 分发器时,该线程开始在用户模式下执行,调用应用程序指定的线程启动函数,此启动函数的地址已经在APC交付时被压到用户栈中。

至此,进程创建完毕,开始执行用户空间中的代码。

本文涉及的函数源码

PspCreateProcess

NTSTATUS
PspCreateProcess(
    OUT PHANDLE ProcessHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ParentProcess OPTIONAL,
    IN ULONG Flags,
    IN HANDLE SectionHandle OPTIONAL,
    IN HANDLE DebugPort OPTIONAL,
    IN HANDLE ExceptionPort OPTIONAL,
    IN ULONG JobMemberLevel
    )

/*++

Routine Description:

    This routine creates and initializes a process object.  It implements the
    foundation for NtCreateProcess and for system initialization process
    creation.
    这个函数创建并初始化一个进程对象。NtCreateProcess 会调用它;系统进程初始化也会调用它。

Arguments:

    ProcessHandle - Returns the handle for the new process.
    输出参数,返回新进程句柄

    DesiredAccess - Supplies the desired access modes to the new process.
    期望对新进程的访问权限

    ObjectAttributes - Supplies the object attributes of the new process.
    新进程的对象属性

    ParentProcess - Supplies a handle to the process' parent process.  If this
                    parameter is not specified, then the process has no parent
                    and is created using the system address space.
    指定父进程句柄。如果未指定,说明没有父进程,那就是用系统地址空间创建进程。

    Flags         - Process creation flags
    进程创建标志

    SectionHandle - Supplies a handle to a section object to be used to create
                    the process' address space.  If this parameter is not
                    specified, then the address space is simply a clone of the
                    parent process' address space.
    提供一个内存区对象句柄用来创建进程地址空间。如果此参数未指定,则简单地复制父进程
    的地址空间。

    DebugPort - Supplies a handle to a port object that will be used as the
                process' debug port.
    调试端口句柄

    ExceptionPort - Supplies a handle to a port object that will be used as the
                    process' exception port.
    异常端口句柄

    JobMemberLevel - Level for a create process in a jobset
    工作集等级
--*/

{

    NTSTATUS Status;
    PEPROCESS Process;
    PEPROCESS CurrentProcess;
    PEPROCESS Parent;
    PETHREAD CurrentThread;
    KAFFINITY Affinity;
    KPRIORITY BasePriority;
    PVOID SectionObject;
    PVOID ExceptionPortObject;
    PVOID DebugPortObject;
    ULONG WorkingSetMinimum, WorkingSetMaximum;
    HANDLE LocalProcessHandle;
    KPROCESSOR_MODE PreviousMode;
    INITIAL_PEB InitialPeb;
    BOOLEAN CreatePeb;
    ULONG_PTR DirectoryTableBase[2];
    BOOLEAN AccessCheck;
    BOOLEAN MemoryAllocated;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    SECURITY_SUBJECT_CONTEXT SubjectContext;
    NTSTATUS accesst;
    NTSTATUS SavedStatus;
    ULONG ImageFileNameSize;
    HANDLE_TABLE_ENTRY CidEntry;
    PEJOB Job;
    PPEB Peb;
    AUX_ACCESS_DATA AuxData;
    PACCESS_STATE AccessState;
    ACCESS_STATE LocalAccessState;
    BOOLEAN UseLargePages;
    SCHAR QuantumReset;
#if defined(_WIN64)
    INITIAL_PEB32 InitialPeb32;
#endif

    PAGED_CODE();

    // 获取当前线程、CPU模式、当前进程
    CurrentThread = PsGetCurrentThread ();
    PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
    CurrentProcess = PsGetCurrentProcessByThread (CurrentThread);

    CreatePeb = FALSE;
    UseLargePages = FALSE;
    DirectoryTableBase[0] = 0;
    DirectoryTableBase[1] = 0;
    Peb = NULL;
    
    //
    // Reject bogus create parameters for future expansion
    // 如果 Flags 里的保留位被置1,就是非法参数
    if (Flags&~PROCESS_CREATE_FLAGS_LEGAL_MASK) {
        return STATUS_INVALID_PARAMETER;
    }

    //
    // Parent
    // 检查有无指定父进程
    // 

    if (ARGUMENT_PRESENT (ParentProcess)) {
        // 如果指定了父进程句柄,就获取它的EPROCESS
        Status = ObReferenceObjectByHandle (ParentProcess,
                                            PROCESS_CREATE_PROCESS,
                                            PsProcessType,
                                            PreviousMode,
                                            &Parent,
                                            NULL);
        if (!NT_SUCCESS (Status)) {
            return Status;
        }

        // 工作集相关
        if (JobMemberLevel != 0 && Parent->Job == NULL) {
            ObDereferenceObject (Parent);
            return STATUS_INVALID_PARAMETER;
        }

        // 继承父进程的CPU亲和性
        Affinity = Parent->Pcb.Affinity;
        // 用全局变量初始化工作集最大最小值
        WorkingSetMinimum = PsMinimumWorkingSet;
        WorkingSetMaximum = PsMaximumWorkingSet;


    } else {
        // 没有父进程
        Parent = NULL;
        Affinity = KeActiveProcessors;
        WorkingSetMinimum = PsMinimumWorkingSet;
        WorkingSetMaximum = PsMaximumWorkingSet;
    }

    //
    // Create the process object
    // 创建进程对象 EPROCESS
    //
    Status = ObCreateObject (PreviousMode,
                             PsProcessType,
                             ObjectAttributes,
                             PreviousMode,
                             NULL,
                             sizeof (EPROCESS),
                             0,
                             0,
                             &Process);

    if (!NT_SUCCESS (Status)) {
        goto exit_and_deref_parent;
    }

    //
    // The process object is created set to NULL. Errors
    // That occur after this step cause the process delete
    // routine to be entered.
    // EPROCESS 数据清零。此后发生的错误会导致调用进程删除函数
    //
    // Teardown actions that occur in the process delete routine
    // do not need to be performed inline.
    //

    RtlZeroMemory (Process, sizeof(EPROCESS));
    ExInitializeRundownProtection (&Process->RundownProtect);
    PspInitializeProcessLock (Process);
    InitializeListHead (&Process->ThreadListHead);

#if defined(_WIN64)

    if (Flags & PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE) {
        PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_OVERRIDE_ADDRESS_SPACE);
    }

#endif

    PspInheritQuota (Process, Parent);
    ObInheritDeviceMap (Process, Parent);
    if (Parent != NULL) {
        Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing;
        Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;

    } else {
        Process->DefaultHardErrorProcessing = PROCESS_HARDERROR_DEFAULT;
        Process->InheritedFromUniqueProcessId = NULL;
    }

    //
    // Section
    //

    if (ARGUMENT_PRESENT (SectionHandle)) {
        // 如果指定了内存区对象句柄参数 SectionHandle,就获取内存区对象
        Status = ObReferenceObjectByHandle (SectionHandle,
                                            SECTION_MAP_EXECUTE,
                                            MmSectionObjectType,
                                            PreviousMode,
                                            &SectionObject,
                                            NULL);
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }

    } else {
        // SectionHandle 参数为NULL,要看父进程是不是 System 进程

        SectionObject = NULL;

        
        if (Parent != PsInitialSystemProcess) {
            // 如果父进程不是 System 进程 ,那么内存区对象继承自父进程
            //
            // Fetch the section pointer from the parent process
            // as we will be cloning. Since the section pointer
            // is removed at last thread exit we need to protect against
            // process exit here to be safe.
            //

            if (ExAcquireRundownProtection (&Parent->RundownProtect)) {
                SectionObject = Parent->SectionObject;
                if (SectionObject != NULL) {
                    ObReferenceObject (SectionObject);
                }

                ExReleaseRundownProtection (&Parent->RundownProtect);
            }

            if (SectionObject == NULL) {
                Status = STATUS_PROCESS_IS_TERMINATING;
                goto exit_and_deref;
            }
        }

        // 如果父进程是 System 进程,那么 SectionObject 就是 NULL
    }

    // 内存区对象 SectionObject 初始化完成(如果是NULL则表示父进程是System进程)
    Process->SectionObject = SectionObject;

    //
    // DebugPort
    // 调试端口初始化

    if (ARGUMENT_PRESENT (DebugPort)) {
        Status = ObReferenceObjectByHandle (DebugPort,
                                            DEBUG_PROCESS_ASSIGN,
                                            DbgkDebugObjectType,
                                            PreviousMode,
                                            &DebugPortObject,
                                            NULL);

        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }

        Process->DebugPort = DebugPortObject;
        if (Flags&PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT) {
            PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT);
        }

    } else {
        if (Parent != NULL) {
            DbgkCopyProcessDebugPort (Process, Parent);
        }
    }

    //
    // ExceptionPort
    // 异常端口初始化

    if (ARGUMENT_PRESENT (ExceptionPort)) {
        Status = ObReferenceObjectByHandle (ExceptionPort,
                                            0,
                                            LpcPortObjectType,
                                            PreviousMode,
                                            &ExceptionPortObject,
                                            NULL);

        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }

        Process->ExceptionPort = ExceptionPortObject;
    }

    Process->ExitStatus = STATUS_PENDING;

    //
    // Clone parent's object table.
    // If no parent (booting) then use the current object table created in
    // ObInitSystem.
    //

    // 创建进程地址空间

    if (Parent != NULL) {
        // 如果有父进程
        //
        // Calculate address space
        //
        //      If Parent == PspInitialSystem
        //

        // 创建一个全新的地址空间,这个函数有三个版本,wrk选 procx86.c 的
        if (!MmCreateProcessAddressSpace (WorkingSetMinimum,
                                          Process,
                                          &DirectoryTableBase[0])) {

            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto exit_and_deref;
        }

    } else {
        // 如果没有父进程

        // 复制当前进程的句柄表
        Process->ObjectTable = CurrentProcess->ObjectTable;

        //
        // Initialize the Working Set Mutex and address creation mutex
        // for this "hand built" process.
        // Normally, the call to MmInitializeAddressSpace initializes the
        // working set mutex, however, in this case, we have already initialized
        // the address space and we are now creating a second process using
        // the address space of the idle thread.
        //

        // 使用空闲线程的地址空间
        Status = MmInitializeHandBuiltProcess (Process, &DirectoryTableBase[0]);
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }
    }

    // 进程地址空间初始化完成
    PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_HAS_ADDRESS_SPACE);

    Process->Vm.MaximumWorkingSetSize = WorkingSetMaximum;

    // 初始化进程基础优先级,CPU亲和性,页目录基址,超空间的页帧号
    KeInitializeProcess (&Process->Pcb,
                         NORMAL_BASE_PRIORITY,
                         Affinity,
                         &DirectoryTableBase[0],
                         (BOOLEAN)(Process->DefaultHardErrorProcessing & PROCESS_HARDERROR_ALIGNMENT_BIT));

    //
    //  Initialize the security fields of the process
    //  The parent may be null exactly once (during system init).
    //  Thereafter, a parent is always required so that we have a
    //  security context to duplicate for the new process.
    //

    // 函数初始化新进程的安全属性,主要是从父进程复制一个令牌
    Status = PspInitializeProcessSecurity (Parent, Process);
    if (!NT_SUCCESS (Status)) {
        goto exit_and_deref;
    }

    // 设置新进程优先级类别
    Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;

    if (Parent != NULL) {
        // 拷贝父进程的优先级类别
        if (Parent->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE ||
            Parent->PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL) {
            Process->PriorityClass = Parent->PriorityClass;
        }

        //
        // if address space creation worked, then when going through
        // delete, we will attach. Of course, attaching means that the kprocess
        // must be initialized, so we delay the object stuff till here.
        // 如果地址空间已创建,

        // 初始化进程句柄表。如果指定父进程,则拷贝所有设置了继承属性的句柄,句柄计数加一
        Status = ObInitProcess ((Flags&PROCESS_CREATE_FLAGS_INHERIT_HANDLES) ? Parent : NULL,
                                Process);

        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }

    } else {
        Status = MmInitializeHandBuiltProcess2 (Process);
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }
    }

    Status = STATUS_SUCCESS;
    SavedStatus = STATUS_SUCCESS;

    //
    // Initialize the process address space
    // The address space has four possibilities
    // 初始化进程地址空间,有4种可能性
    //
    //      1 - Boot Process. Address space is initialized during
    //          MmInit. Parent is not specified.
    //          引导进程,这种情况不在这里初始化地址空间,而是在 MmInitSystem 函数初始化
    //
    //      2 - System Process. Address space is a virgin address
    //          space that only maps system space. Process is same
    //          as PspInitialSystemProcess.
    //          System 进程。地址空间未使用,映射到系统空间。
    //
    //      3 - User Process (Cloned Address Space). Address space
    //          is cloned from the specified process.
    //          用户进程(克隆父进程地址空间)
    //
    //      4 - User Process (New Image Address Space). Address space
    //          is initialized so that it maps the specified section.
    //          用户进程(新地址空间镜像)
    //

    if (SectionHandle != NULL) {

        //
        // User Process (New Image Address Space). Don't specify Process to
        // clone, just SectionObject.
        //
        // Passing in the 4th parameter as below lets the EPROCESS struct contain its image file name, provided that
        // appropriate audit settings are enabled.  Memory is allocated inside of MmInitializeProcessAddressSpace
        // and pointed to by ImageFileName, so that must be freed in the process deletion routine (PspDeleteProcess())
        //
        // 新进程指定了内存区对象,调用 MmInitializeProcessAddressSpace 函数初始化进程地址空间
        //

        Status = MmInitializeProcessAddressSpace (Process,
                                                  NULL,
                                                  SectionObject,
                                                  &Flags,
                                                  &(Process->SeAuditProcessCreationInfo.ImageFileName));

        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }

        //
        // In order to support relocating executables, the proper status
        // (STATUS_IMAGE_NOT_AT_BASE) must be returned, so save it here.
        //

        SavedStatus = Status;
        CreatePeb = TRUE;
        UseLargePages = ((Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) != 0 ? TRUE : FALSE);

    } else if (Parent != NULL) {
        if (Parent != PsInitialSystemProcess) {
            Process->SectionBaseAddress = Parent->SectionBaseAddress;

            //
            // User Process ( Cloned Address Space ).  Don't specify section to
            // map, just Process to clone.
            //
            // 指定了父进程,父进程不是 System 进程,调用 MmInitializeProcessAddressSpace 
            // 根据父进程初始化地址空间
            //

            Status = MmInitializeProcessAddressSpace (Process,
                                                      Parent,
                                                      NULL,
                                                      &Flags,
                                                      NULL);

            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }

            CreatePeb = TRUE;
            UseLargePages = ((Flags & PROCESS_CREATE_FLAGS_LARGE_PAGES) != 0 ? TRUE : FALSE);
            
            //
            // A cloned process isn't started from an image file, so we give it the name
            // of the process of which it is a clone, provided the original has a name.
            //

            if (Parent->SeAuditProcessCreationInfo.ImageFileName != NULL) {
                ImageFileNameSize = sizeof(OBJECT_NAME_INFORMATION) +
                                    Parent->SeAuditProcessCreationInfo.ImageFileName->Name.MaximumLength;

                Process->SeAuditProcessCreationInfo.ImageFileName =
                    ExAllocatePoolWithTag (PagedPool,
                                           ImageFileNameSize,
                                           'aPeS');

                if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {
                    RtlCopyMemory (Process->SeAuditProcessCreationInfo.ImageFileName,
                                   Parent->SeAuditProcessCreationInfo.ImageFileName,
                                   ImageFileNameSize);

                    //
                    // The UNICODE_STRING in the process is self contained, so calculate the
                    // offset for the buffer.
                    //

                    Process->SeAuditProcessCreationInfo.ImageFileName->Name.Buffer =
                        (PUSHORT)(((PUCHAR) Process->SeAuditProcessCreationInfo.ImageFileName) +
                        sizeof(UNICODE_STRING));

                } else {
                    Status = STATUS_INSUFFICIENT_RESOURCES;
                    goto exit_and_deref;
                }
            }

        } else {

            //
            // System Process.  Don't specify Process to clone or section to map
            //
            // 没有指定内存区对象,但父进程是System进程
            //

            Flags &= ~PROCESS_CREATE_FLAGS_ALL_LARGE_PAGE_FLAGS;
            Status = MmInitializeProcessAddressSpace (Process,
                                                      NULL,
                                                      NULL,
                                                      &Flags,
                                                      NULL);

            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }

            //
            // In case the image file name of this system process is ever queried, we give
            // a zero length UNICODE_STRING.
            //

            Process->SeAuditProcessCreationInfo.ImageFileName =
                ExAllocatePoolWithTag (PagedPool,
                                       sizeof(OBJECT_NAME_INFORMATION),
                                       'aPeS');

            if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {
                RtlZeroMemory (Process->SeAuditProcessCreationInfo.ImageFileName,
                               sizeof(OBJECT_NAME_INFORMATION));
            } else {
                Status = STATUS_INSUFFICIENT_RESOURCES;
                goto exit_and_deref;
            }
        }
    }

    //
    // Create the process ID
    //
    // 创建进程ID,方法是调用 ExCreateHandle 在System 进程句柄表中存一个句柄
    // 句柄值就是PID
    //

    CidEntry.Object = Process;
    CidEntry.GrantedAccess = 0;
    Process->UniqueProcessId = ExCreateHandle (PspCidTable, &CidEntry);
    if (Process->UniqueProcessId == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto exit_and_deref;
    }

    ExSetHandleTableOwner (Process->ObjectTable, Process->UniqueProcessId);

    //
    // Audit the process creation.
    // 审计此次进程创建行为

    if (SeDetailedAuditingWithToken (NULL)) {
        SeAuditProcessCreation (Process);
    }

    //
    // See if the parent has a job. If so reference the job
    // and add the process in.
    //

    // 作业相关,本书不分析
    if (Parent) {
        Job = Parent->Job;
        if (Job != NULL && !(Job->LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)) {
            if (Flags&PROCESS_CREATE_FLAGS_BREAKAWAY) {
                if (!(Job->LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {
                    Status = STATUS_ACCESS_DENIED;

                } else {
                    Status = STATUS_SUCCESS;
                }

            } else {
                Status = PspGetJobFromSet (Job, JobMemberLevel, &Process->Job);
                if (NT_SUCCESS (Status)) {
                    PACCESS_TOKEN Token, NewToken;
                    Job = Process->Job;
                    Status = PspAddProcessToJob (Job, Process);

                    //
                    // Duplicate a new process token if one is specified for the job
                    //

                    Token = Job->Token;
                    if (Token != NULL) {
                        Status = SeSubProcessToken (Token,
                                                    &NewToken,
                                                    FALSE,
                                                    Job->SessionId);

                        if (!NT_SUCCESS (Status)) {
                            goto exit_and_deref;
                        }

                        SeAssignPrimaryToken (Process, NewToken);    
                        ObDereferenceObject (NewToken);                    
                    }
                }
            }

            if (!NT_SUCCESS (Status)) {
                goto exit_and_deref;
            }
        }
    }

    // 对于通过映像内存区对象创建的进程,创建一个PEB
    // 对于进程拷贝(fork)的情景,则使用继承的PEB
    if (Parent && CreatePeb) {

        //
        // For processes created w/ a section,
        // a new "virgin" PEB is created. Otherwise,
        // for forked processes, uses inherited PEB
        // with an updated mutant.
        //

        RtlZeroMemory (&InitialPeb, FIELD_OFFSET(INITIAL_PEB, Mutant));

        InitialPeb.Mutant = (HANDLE)(-1);
        InitialPeb.ImageUsesLargePages = (BOOLEAN) UseLargePages;
            
        if (SectionHandle != NULL) {
            Status = MmCreatePeb (Process, &InitialPeb, &Process->Peb);
            if (!NT_SUCCESS (Status)) {
                Process->Peb = NULL;
                goto exit_and_deref;
            }

            Peb =  Process->Peb;

        } else {
            SIZE_T BytesCopied;

            InitialPeb.InheritedAddressSpace = TRUE;
            Process->Peb = Parent->Peb;
            MmCopyVirtualMemory (CurrentProcess,
                                 &InitialPeb,
                                 Process,
                                 Process->Peb,
                                 sizeof (INITIAL_PEB),
                                 KernelMode,
                                 &BytesCopied);

#if defined(_WIN64)
            if (Process->Wow64Process != NULL) {
                
                RtlZeroMemory (&InitialPeb32, FIELD_OFFSET(INITIAL_PEB32, Mutant));
                InitialPeb32.Mutant = -1;
                InitialPeb32.InheritedAddressSpace = TRUE;
                InitialPeb32.ImageUsesLargePages = (BOOLEAN) UseLargePages;

                MmCopyVirtualMemory (CurrentProcess,
                                     &InitialPeb32,
                                     Process,
                                     Process->Wow64Process->Wow64,
                                     sizeof (INITIAL_PEB32),
                                     KernelMode,
                                     &BytesCopied);
            }
#endif

        }
    }

    Peb = Process->Peb;

    //
    // Add the process to the global list of processes.
    // 新进程对象插入到全局活动进程链表 PsActiveProcessHead

    PspLockProcessList (CurrentThread);
    InsertTailList (&PsActiveProcessHead, &Process->ActiveProcessLinks);
    PspUnlockProcessList (CurrentThread);

    AccessState = NULL;
    if (!PsUseImpersonationToken) {
        AccessState = &LocalAccessState;
        Status = SeCreateAccessStateEx (NULL,
                                        (Parent == NULL || Parent != PsInitialSystemProcess)?
                                           PsGetCurrentProcessByThread (CurrentThread) :
                                           PsInitialSystemProcess,
                                        AccessState,
                                        &AuxData,
                                        DesiredAccess,
                                        &PsProcessType->TypeInfo.GenericMapping);
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }
    }

    //
    // Insert the object. Once we do this is reachable from the outside world via
    // open by name. Open by ID is still disabled. Since its reachable
    // somebody might create a thread in the process and cause
    // rundown.
    //

    // 新进程对象插入到当前进程句柄表中
    Status = ObInsertObject (Process,
                             AccessState,
                             DesiredAccess,
                             1,     // bias the refcnt by one for future process manipulations
                             NULL,
                             &LocalProcessHandle);

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

    if (!NT_SUCCESS (Status)) {
        goto exit_and_deref_parent;
    }

    //
    // Compute the base priority and quantum reset values for the process and
    // set the memory priority.
    //

    ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE);

    // 计算新进程的基本优先级和时限重置值
    BasePriority = PspComputeQuantumAndPriority(Process,
                                                PsProcessPriorityBackground,
                                                &QuantumReset);

    Process->Pcb.BasePriority = (SCHAR)BasePriority;
    Process->Pcb.QuantumReset = QuantumReset;

    //
    // As soon as a handle to the process is accessible, allow the process to
    // be deleted.
    //

    // 设置进程访问权限,当前进程句柄可访问,允许进程终止
    Process->GrantedAccess = PROCESS_TERMINATE;
    if (Parent && Parent != PsInitialSystemProcess) {
        Status = ObGetObjectSecurity (Process,
                                      &SecurityDescriptor,
                                      &MemoryAllocated);

        if (!NT_SUCCESS (Status)) {
            ObCloseHandle (LocalProcessHandle, PreviousMode);
            goto exit_and_deref;
        }

        //
        // Compute the subject security context
        //

        SubjectContext.ProcessAuditId = Process;
        SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
        SubjectContext.ClientToken = NULL;
        AccessCheck = SeAccessCheck (SecurityDescriptor,
                                     &SubjectContext,
                                     FALSE,
                                     MAXIMUM_ALLOWED,
                                     0,
                                     NULL,
                                     &PsProcessType->TypeInfo.GenericMapping,
                                     PreviousMode,
                                     &Process->GrantedAccess,
                                     &accesst);

        PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);
        ObReleaseObjectSecurity (SecurityDescriptor,
                                 MemoryAllocated);

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

        //
        // It does not make any sense to create a process that can not
        // do anything to itself.
        // Note: Changes to this set of bits should be reflected in psquery.c
        // code, in PspSetPrimaryToken.
        //

        Process->GrantedAccess |= (PROCESS_VM_OPERATION |
                                   PROCESS_VM_READ |
                                   PROCESS_VM_WRITE |
                                   PROCESS_QUERY_INFORMATION |
                                   PROCESS_TERMINATE |
                                   PROCESS_CREATE_THREAD |
                                   PROCESS_DUP_HANDLE |
                                   PROCESS_CREATE_PROCESS |
                                   PROCESS_SET_INFORMATION |
                                   STANDARD_RIGHTS_ALL |
                                   PROCESS_SET_QUOTA);

    } else {
        Process->GrantedAccess = PROCESS_ALL_ACCESS;
    }

    // 设置进程创建时间
    KeQuerySystemTime (&Process->CreateTime);
    try {
        if (Peb != NULL && CurrentThread->Tcb.Teb != NULL) {
            ((PTEB)(CurrentThread->Tcb.Teb))->NtTib.ArbitraryUserPointer = Peb;
        }

        *ProcessHandle = LocalProcessHandle;

    } except (EXCEPTION_EXECUTE_HANDLER) {
        NOTHING;
    }

    if (SavedStatus != STATUS_SUCCESS) {
        Status = SavedStatus;
    }

exit_and_deref:
    ObDereferenceObject (Process);

exit_and_deref_parent:
    if (Parent != NULL) {
        ObDereferenceObject (Parent);
    }

    return Status;
}

PspCreateThread

NTSTATUS
PspCreateThread(
    OUT PHANDLE ThreadHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ProcessHandle,
    IN PEPROCESS ProcessPointer,
    OUT PCLIENT_ID ClientId OPTIONAL,
    IN PCONTEXT ThreadContext OPTIONAL,
    IN PINITIAL_TEB InitialTeb OPTIONAL,
    IN BOOLEAN CreateSuspended,
    IN PKSTART_ROUTINE StartRoutine OPTIONAL,
    IN PVOID StartContext
    )

/*++

Routine Description:

    This routine creates and initializes a thread object. It implements the
    foundation for NtCreateThread and for PsCreateSystemThread.

Arguments:

    ThreadHandle - Returns the handle for the new thread.
    输出参数,返回新线程句柄

    DesiredAccess - Supplies the desired access modes to the new thread.
    期望的新线程访问权限

    ObjectAttributes - Supplies the object attributes of the new thread.
    指定新线程对象的属性

    ProcessHandle - Supplies a handle to the process that the thread is being
                    created within.
    新线程将运行在此进程的环境中

    ProcessPointer
    仅当创建系统线程时,此参数指向 System进程 PsInitialSystemProcess
    其他情况下都是NULL

    ClientId - Returns the CLIENT_ID of the new thread.
    返回新线程的CID

    ThreadContext - Supplies a pointer to a context frame that represents the
                initial user-mode context for a user-mode thread. The absence
                of this parameter indicates that a system thread is being
                created.
    用户线程执行环境;如果是NULL,则表示创建系统线程

    InitialTeb - Supplies the contents of certain fields for the new threads
                 TEB. This parameter is only examined if both a trap and
                 exception frame were specified.
    用户线程初始化TEB结构

    CreateSuspended - Supplies a value that controls whether or not a user-mode
                      thread is created in a suspended state.
    是否挂起这个用户线程

    StartRoutine - Supplies the address of the system thread start routine.
    系统线程启动函数

    StartContext - Supplies context for a system thread start routine.
    系统线程启动函数执行环境

--*/

{

    HANDLE_TABLE_ENTRY CidEntry;
    NTSTATUS Status;
    PETHREAD Thread;
    PETHREAD CurrentThread;
    PEPROCESS Process;
    PTEB Teb;
    KPROCESSOR_MODE PreviousMode;
    HANDLE LocalThreadHandle;
    BOOLEAN AccessCheck;
    BOOLEAN MemoryAllocated;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    SECURITY_SUBJECT_CONTEXT SubjectContext;
    NTSTATUS accesst;
    LARGE_INTEGER CreateTime;
    ULONG OldActiveThreads;
    PEJOB Job;
    AUX_ACCESS_DATA AuxData;
    PACCESS_STATE AccessState;
    ACCESS_STATE LocalAccessState;

    PAGED_CODE();

    // 当前线程
    CurrentThread = PsGetCurrentThread ();

    // 当前CPU模式
    if (StartRoutine != NULL) {
        // 如果指定了 StartRoutine ,就是创建系统线程
        PreviousMode = KernelMode;
    } else {
        // 如果未指定 StartRoutine,就通过当前线程判断
        PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
    }

    Teb = NULL;

    Thread = NULL;
    Process = NULL;

    
    // 获取进程对象,存储到局部变量 Process

    if (ProcessHandle != NULL) {
        // 如果指定了 ProcessHandle,就通过 ProcessHandle 获取进程对象

        //
        // Process object reference count is biased by one for each thread.
        // This accounts for the pointer given to the kernel that remains
        // in effect until the thread terminates (and becomes signaled)
        //

        Status = ObReferenceObjectByHandle (ProcessHandle,
                                            PROCESS_CREATE_THREAD,
                                            PsProcessType,
                                            PreviousMode,
                                            &Process,
                                            NULL);
    } else {
        if (StartRoutine != NULL) {
            // 如果 ProcessHandle 是 NULL,且指定了 StartRoutine ,说明是System进程要创建系统线程
            ObReferenceObject (ProcessPointer);
            Process = ProcessPointer;
            Status = STATUS_SUCCESS;
        } else {
            // 否则,返回错误
            Status = STATUS_INVALID_HANDLE;
        }
    }

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

    //
    // If the previous mode is user and the target process is the system
    // process, then the operation cannot be performed.
    //

    // 如果是用户模式,父进程却是System进程,就返回错误
    if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) {
        ObDereferenceObject (Process);
        return STATUS_INVALID_HANDLE;
    }

    // 创建 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));

    //
    // Initialize rundown protection for cross thread TEB refs etc.
    //

    // 初始化 RundownProtect
    ExInitializeRundownProtection (&Thread->RundownProtect);

    //
    // Assign this thread to the process so that from now on
    // we don't have to dereference in error paths.
    //

    // 设置新线程的父进程
    Thread->ThreadsProcess = Process;

    // 创建CID
    Thread->Cid.UniqueProcess = Process->UniqueProcessId;    
    CidEntry.Object = Thread;
    CidEntry.GrantedAccess = 0;
    Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);

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

    //
    // Initialize Mm
    //

    Thread->ReadClusterSize = MmReadClusterSize;

    //
    // Initialize LPC
    //

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

    //
    // Initialize Io
    //

    InitializeListHead (&Thread->IrpList);

    //
    // Initialize Registry
    //

    InitializeListHead (&Thread->PostBlockList);

    //
    // Initialize the thread lock
    //

    PspInitializeThreadLock (Thread);

    // 初始化定时器链表
    KeInitializeSpinLock (&Thread->ActiveTimerListLock);
    InitializeListHead (&Thread->ActiveTimerListHead);

    // 获得进程的 RundownProtect 锁,防止创建过程中进程被停掉(rundown)
    // 直到线程被插入到进程的线程链表中,才能解锁
    if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
        ObDereferenceObject (Thread);
        return STATUS_PROCESS_IS_TERMINATING;
    }

    if (ARGUMENT_PRESENT (ThreadContext)) {

        //
        // User-mode thread. Create TEB etc
        // 如果 ThreadContext 不空,说明是创建用户线程
        // 于是创建TEB,并用 InitialTeb 初始化

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


        try {
            //
            // Initialize kernel thread object for user mode thread.
            //

            // 用 ThreadContext 的 Eip 初始化 StartAddress
            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();
        }

        // 根据进程对象的信息初始化线程的一些属性
        // 包括 Header, WaitBlock, ServiceTable, APC,定时器,内核栈等
        if (NT_SUCCESS (Status)) {
            Status = KeInitThread (&Thread->Tcb,
                                   NULL,
                                   PspUserThreadStartup,
                                   (PKSTART_ROUTINE)NULL,
                                   Thread->StartAddress,
                                   ThreadContext,
                                   Teb,
                                   &Process->Pcb);
       }


    } else {

        Teb = NULL;
        //
        // Set the system thread bit thats kept for all time
        // 设置系统线程标志位
        //
        PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SYSTEM);

        //
        // Initialize kernel thread object for kernel mode thread.
        //

        // 设置系统线程启动地址 StartRoutine
        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;
    }

    // 锁住进程,确保不是在退出或终止过程中
    PspLockProcessExclusive (Process, CurrentThread);
    //
    // Process is exiting or has had delete process called
    // We check the calling threads termination status so we
    // abort any thread creates while ExitProcess is being called --
    // but the call is blocked only if the new thread would be created
    // in the terminating thread's process.
    //
    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;
    }

    // 进程的活动线程计数加一
    OldActiveThreads = Process->ActiveThreads++;
    // 新线程加入进程的线程链表
    InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);
    // 初始化剩余的域,尤其是和调度相关的,比如优先级、时限设置、CPU亲和性等
    KeStartThread (&Thread->Tcb);

    // 此时线程可以被调度执行了

    PspUnlockProcessExclusive (Process, CurrentThread);

    ExReleaseRundownProtection (&Process->RundownProtect);

    //
    // Failures that occur after this point cause the thread to
    // go through PspExitThread
    //

    // 如果是该进程的第一个线程,触发该进程的创建通知
    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);
                }
            }
        }
    }

    //
    // If the process has a job with a completion port,
    // AND if the process is really considered to be in the Job, AND
    // the process has not reported, report in
    //
    // This should really be done in add process to job, but can't
    // in this path because the process's ID isn't assigned until this point
    // in time
    //
    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);

    //
    // Notify registered callout routines of thread creation.
    //

    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);
            }
        }
    }


    //
    // Reference count of thread is biased once for itself and once for the handle if we create it.
    //

    // 线程对象的引用计数加2,一个针对当前的创建操作,一个针对要返回的线程句柄
    ObReferenceObjectEx (Thread, 2);

    // 如果 CreateSuspended ,指示新线程立即被挂起
    if (CreateSuspended) {
        try {
            KeSuspendThread (&Thread->Tcb);
        } except ((GetExceptionCode () == STATUS_SUSPEND_COUNT_EXCEEDED)?
                     EXCEPTION_EXECUTE_HANDLER :
                     EXCEPTION_CONTINUE_SEARCH) {
        }
        //
        // If deletion was started after we suspended then wake up the thread
        //
        if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) {
            KeForceResumeThread (&Thread->Tcb);
        }
    }

    // 根据指定的期望访问权限,调用 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;
        }
    }

    // 把新线程对象插入到当前进程的句柄表
    Status = ObInsertObject (Thread,
                             AccessState,
                             DesiredAccess,
                             0,
                             NULL,
                             &LocalThreadHandle);

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

    if (!NT_SUCCESS (Status)) {

        //
        // The insert failed. Terminate the thread.
        //

        //
        // This trick is used so that Dbgk doesn't report
        // events for dead threads
        //

        PS_SET_BITS (&Thread->CrossThreadFlags,
                     PS_CROSS_THREAD_FLAGS_DEADTHREAD);

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

    } else {
        
        try {
            // 设置输出参数 ThreadHandle
            *ThreadHandle = LocalThreadHandle;

            // 设置输出参数 ClientId 
            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();
        }
    }

    // 设置线程创建时间
    KeQuerySystemTime(&CreateTime);
    ASSERT ((CreateTime.HighPart & 0xf0000000) == 0);
    PS_SET_THREAD_CREATE_TIME(Thread, CreateTime);

    // 设置线程访问权限
    if ((Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) == 0) {
        Status = ObGetObjectSecurity (Thread,
                                      &SecurityDescriptor,
                                      &MemoryAllocated);
        if (!NT_SUCCESS (Status)) {
            //
            // This trick us used so that Dbgk doesn't report
            // events for dead threads
            //
            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;
        }

        //
        // Compute the subject security context
        //

        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;
    }

    // 新线程加入就绪链表,等待调度;或者此时进程不在内存中,设置新线程状态为转移
    KeReadyThread (&Thread->Tcb);

    // 引用计数减一
    ObDereferenceObject (Thread);

    return Status;
}

CreateProcessW

BOOL
WINAPI
CreateProcessW(
    LPCWSTR lpApplicationName,
    LPWSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCWSTR lpCurrentDirectory,
    LPSTARTUPINFOW lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
    )
{
    return CreateProcessInternalW(
               NULL, // Create new process with the token on the creator process
               lpApplicationName,
               lpCommandLine,
               lpProcessAttributes,
               lpThreadAttributes,
               bInheritHandles,
               dwCreationFlags,
               lpEnvironment,
               lpCurrentDirectory,
               lpStartupInfo,
               lpProcessInformation,
               NULL  // Do not return the restricted token
               );
}

结束