进程创建过程分析NtCreateProcess-NtCreateProcessEx-PspCreateProcess

在内核中,windows创建一个进程的过程是从NtCreateProcess函数开始的。找到这个函数,发现它只是简单地对参数稍作处理,然后把创建进程的任务交给NtCreateProcessEx函数。

NTSTATUS
NtCreateProcess(
    __out PHANDLE ProcessHandle,
    __in ACCESS_MASK DesiredAccess,
    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
    __in HANDLE ParentProcess,
    __in BOOLEAN InheritObjectTable,
    __in_opt HANDLE SectionHandle,
    __in_opt HANDLE DebugPort,
    __in_opt HANDLE ExceptionPort
    )
{
    ULONG Flags = 0;

    if ((ULONG_PTR)SectionHandle & 1) {
        Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
    }

    if ((ULONG_PTR) DebugPort & 1) {
        Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
    }

    if (InheritObjectTable) {
        Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
    }

    return NtCreateProcessEx (ProcessHandle,
                              DesiredAccess,
                              ObjectAttributes OPTIONAL,
                              ParentProcess,
                              Flags,
                              SectionHandle,
                              DebugPort,
                              ExceptionPort,
                              0);
}

所以我们来看NtCreateProcessEx函数的流程。它也只是简单地检查ProcessHandle参数代表的句柄是否可写,ParentProcess是否不为空,这是个必需的参数,不能为NULL,并且调用者必须对该进程具有PROCESS_CREATE_PROCESS访问权限。真正的创建工作交给PspCreateProcess函数。

NtCreateProcessEx(
    __out PHANDLE ProcessHandle,
    __in ACCESS_MASK DesiredAccess,
    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
    __in HANDLE ParentProcess,
    __in ULONG Flags,
    __in_opt HANDLE SectionHandle,
    __in_opt HANDLE DebugPort,
    __in_opt HANDLE ExceptionPort,
    __in ULONG JobMemberLevel
    )

{
    NTSTATUS Status;

    PAGED_CODE();

    if (KeGetPreviousMode() != KernelMode) {

        try {
            ProbeForWriteHandle (ProcessHandle);
        } except (EXCEPTION_EXECUTE_HANDLER) {
            return GetExceptionCode ();
        }
    }

    if (ARGUMENT_PRESENT (ParentProcess)) {
        Status = PspCreateProcess (ProcessHandle,
                                   DesiredAccess,
                                   ObjectAttributes,
                                   ParentProcess,
                                   Flags,
                                   SectionHandle,
                                   DebugPort,
                                   ExceptionPort,
                                   JobMemberLevel);
    } else {
        Status = STATUS_INVALID_PARAMETER;
    }

    return Status;
}

下面来看看PspCreateProcess 的执行流程。

1.   if (ARGUMENT_PRESENT (ParentProcess)) {

       //如果ParentProcess不为空,则通过ObReferenceObjectByHandle 获得父进程对象的EPROCESS指针,放在局部变量Parent。
       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;
       }

        //获得父进程Affinity设置。

       Affinity = Parent->Pcb.Affinity;

       新进程的工作集最大/最小值被初始化为全局变量。
       WorkingSetMinimum = PsMinimumWorkingSet;
       WorkingSetMaximum = PsMaximumWorkingSet;

   } else {

       Parent = NULL;

       //Affinity设置为全局变量KeActiveProcessors,系统中当前的可用处理器。
       Affinity = KeActiveProcessors;
       WorkingSetMinimum = PsMinimumWorkingSet;
       WorkingSetMaximum = PsMaximumWorkingSet;
   }

2.调用ObCreateObject 创建一个类型为PsProcessType的内核对象,置于局部变量Process中,对象体为EPROCESS

Status = ObCreateObject (PreviousMode,
                            PsProcessType,
                            ObjectAttributes,
                            PreviousMode,
                            NULL,
                            sizeof (EPROCESS),
                            0,
                            0,
                            &Process);

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

3.把Process置0,并初始化部分成员。

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;

//保存父进程PID
        Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;

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

4.判断SectionHandle是否为空

if (ARGUMENT_PRESENT (SectionHandle)) {

   //不为空,ObReferenceObjectByHandle 获取内存区对象的指针
    Status = ObReferenceObjectByHandle (SectionHandle,
                                        SECTION_MAP_EXECUTE,
                                        MmSectionObjectType,
                                        PreviousMode,
                                        &SectionObject,
                                        NULL);
    if (!NT_SUCCESS (Status)) {
        goto exit_and_deref;
    }

} else {
    SectionObject = NULL;

//父进程不为系统进程
    if (Parent != PsInitialSystemProcess) {

//acquire run-down protection on a shared object so the caller can safely access the object

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

Process->SectionObject = SectionObject;

新进程对象的内存区对象已经完成初始化。

5.初始化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);
        }
    }

6.初始化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;

7.创建地址空间。

if (Parent != NULL) {
    //创建一个全新的地址空间

    if (!MmCreateProcessAddressSpace (WorkingSetMinimum,
                                      Process,
                                      &DirectoryTableBase[0])) {

        Status = STATUS_INSUFFICIENT_RESOURCES;
        goto exit_and_deref;
    }

} else {

//否则新进程句柄表指向当前进程句柄表
    Process->ObjectTable = CurrentProcess->ObjectTable;
    //利用空闲线程的地址空间来初始化新进程的地址空间

    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;

8.初始化新进程对象的基本优先级、Affinity、进程页表目录和超空间的页帧号。

KeInitializeProcess (&Process->Pcb,
                        NORMAL_BASE_PRIORITY,
                        Affinity,
                        &DirectoryTableBase[0],
                        (BOOLEAN)(Process->DefaultHardErrorProcessing & PROCESS_HARDERROR_ALIGNMENT_BIT));

9.初始化新进程的安全属性。

Status = PspInitializeProcessSecurity (Parent, Process);
   if (!NT_SUCCESS (Status)) {
       goto exit_and_deref;
   }

10.设置新进程优先级。

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;
       }
       //如果参数中包含了句柄继承标志,则把父进程句柄表中凡是具有继承属性的对象拷贝到新进程句柄表中。

       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;

11.初始化新进程的地址空间

if (SectionHandle != NULL) {

//新进程有新的可执行映像内存区对象,根据指定的内存区对象来初始化进程地址空间。

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

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

       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;

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

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

 

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

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

       } else {

          //系统进程,不指定内存区和父进程,直接初始化,同样拷贝父进程的映像名称到新进程对象的数据结构中。

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

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

 

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

还有第四种可能性,即没有指定映像内存区对象,也没有指定父进程。这对应于系统的引导进程(后蜕化成空闲进程),它的地址空间是在MmInitSystem执行过程中初始化的,由MiInitMachineDependent函数调用MmInitializeProcessAddressSpace来完成。

12.创建进程ID。利用ExCreateHandle函数在CID句柄表中创建一个进程ID项。

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

13.审计创建行为

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

14.如果父进程属于一个作业对象,则也加入到父进程所在的作业中。

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

 

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

15.对于通过映像内存区来创建进程的情形,创建一个PEB,对于进程拷贝的情况,则使用继承的PEB。

if (Parent && CreatePeb) {

        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;

16.把新进程加入全局的进程链表中。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;
       }
   }

17.把新进程对象插入到当前进程的句柄表中。

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

18.计算新进程的优先级和时限重置值,设置内存优先级。

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

   BasePriority = PspComputeQuantumAndPriority(Process,
                                               PsProcessPriorityBackground,
                                               &QuantumReset);

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

19。设置进程的访问权限,GrantedAccess。由于新进程已经被加入到句柄表中,所以它现在能够被终止了(PROCESS_TERMINATE)。有父进程,但不是PsInitialialSystemProcess,首先执行访问检查,然后计算进程的访问权限。如果是PsInitialialSystemProcess的子进程,则授予所有的访问权限。

Process->GrantedAccess = PROCESS_TERMINATE;
   if (Parent && Parent != PsInitialSystemProcess) {
       Status = ObGetObjectSecurity (Process,
                                     &SecurityDescriptor,
                                     &MemoryAllocated);

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

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

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

20.设置进程的创建时间,把新进程的句柄赋到ProcessHandle中。

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;

新建的进程中,没有任何线程对象,所有还是一个死的进程空间,其中的代码没有真正的运行起来。直到第一个线程被创建!

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