首页 > WinDriver > WD-进程的创建流程(WRK)
2015四月7

WD-进程的创建流程(WRK)

[隐藏]

1.进程的创建

1.1.NtCreateProcessEx

理论上,启动顺序如下:

2k ->NtCreateProcess
server2003,xp ->NtCreateProcessEx
vista/win7/2008 ->NtCreateUserProcess

使用calc启动,发现直接调到了NtCreateProcessEx

1
2
3
4
5
6
7
8
9
10
11
12
NTSTATUS  
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  
);
__out PHANDLE ProcessHandle, //如果创建成功,则它包含了所创建的进程的句柄
__in ACCESS_MASK DesiredAccess, //包含了对新进程的访问权限
_in_opt POBJECT_ATTRIBUTES ObjectAttributes, //一个可选的指针参数(意指可以为NULL),它指定了进程对象的属性
__in HANDLE ParentProcess

ParentProcess 指向父进程的句柄,这是一个必需的参数,不能为NULL,并且调用者必须对该进程具有PROCESS_CREATE_PROCESS 访问权限。

__in ULONG Flags

Flags 是创建标志,其中有一个标志PROCESS_CREATE_FLAGS_INHERIT_HANDLES 特别值得一提:NtCreateProcess专门有一个布尔参数指定是否该标志为TRUE,表明新进程的对象句柄表是否要复制父进程的句柄表,或者初始设置为空.如下为NtCreateProcess此处代码:

1
2
3
 if (InheritObjectTable) {
        Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
    }
__in_opt HANDLE SectionHandle

SectionHandle 是一个可选的句柄,指向一个内存区对象,代表了该进程的映像文件,调用者对于此内存区对象必须具有SECTION_MAP_EXECUTE 访问权限,对于系统进程,此参数为NULL(下面提到的system和其子进程),非系统进程,可为NULL(继承父进程),可不为NULL

__in_opt HANDLE DebugPort

DebugPort 是一个可选的句柄,指向一个端口对象,如果此句柄参数不为NULL,则此端口被赋为新进程的调试端口,如为NULL,如果父窗口有,就复制父窗口的,否则新进程没有调试端口。而且,调用者对于调试端口对象必须具有PORT_WRITE 和PORT_READ 访问权限。

__in_opt HANDLE ExceptionPort

ExceptionPort 也是一个可选的句柄,指向一个端口对象,如果此句柄参数不为NULL,则此端口被赋为新进程的异常端口,否则,新进程没有异常端口。调用者对于异常端口对象必须具有PORT_WRITE 和PORT_READ 访问权限。

__in ULONG JobMemberLevel  

JobMemberLevel 指定了要创建的进程在一个Job 集中的级别

NtCreateProcessEx仅做了两点判断

1.如果是用户模式传入的,判断ProcessHandle是可写的

2.确认ParentProcess不可为NULL,所以很明显,system是第一个进程,它的父进程肯定是NULL,所以它不是通过NtCreateProcessEx创建的

之后,直接调用PspCreateProcess。

   

1.2.PspCreateProcess

1
2
3
4
5
6
7
8
9
10
11
12
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
    );

其参数和NtCreateProcessEx一模一样.

PspCreateProcess被三个函数调用,它们是NtCreateProcessEx、PsCreateSystemProcess 和PspInitPhase0.

PspInitPhase0 是在系统初始化的早期被调用的,它创建的进程(即System 进程)的句柄保存在全局变量PspInitialSystemProcessHandle 中, 进程对象存放于全局变量PsInitialSystemProcess 中,PspInitPhase0的调用代码如下:(可以看到,ParentProcess地址传的是NULL,PsCreateSystemProcess同样后五个参数为NULL)

    if (!NT_SUCCESS (PspCreateProcess (&PspInitialSystemProcessHandle,
                                       PROCESS_ALL_ACCESS,
                                       &ObjectAttributes,
                                       NULL,
                                       0,
                                       NULL,
                                       NULL,
                                       NULL,
                                       0)))

全局变量如下:

kd> x nt!PspInitialSystemProcessHandle
809d3344          nt!PspInitialSystemProcessHandle = 0x00000004
kd> x nt!PsInitialSystemProcess
808a5e8c          nt!PsInitialSystemProcess = 0x84fe7648   //system的EPROCESS
kd> !process 0 0 system
PROCESS 84fe7648  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 17c01000  ObjectTable: e1001de0  HandleCount: 429.
    Image: System

PsCreateSystemProcess 可用于创建系统进程对象,它创建的进程都是PsInitialSystemProcess 的子进程。所以,PspCreateProcess函数负责创建系统中的所有进程,包括System 进程。

它的流程如下:

1.如果ParentProcess不为NULL,则通过ObReferenceObjectByHandle 获得父进程对象的EPROCESS 指针,放在Parent 局部变量中,同时也获得父进程的Affinity 设置。新进程的工作集最大/ 最小值被初始化为全局变量PsMinimumWorkingSet 和PsMaximumWorkingSet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   if (ARGUMENT_PRESENT (ParentProcess)) {
        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 = Parent->Pcb.Affinity;
        WorkingSetMinimum = PsMinimumWorkingSet;
        WorkingSetMaximum = PsMaximumWorkingSet;
    }

2.如果ParentProcess为NULL,则Affinity 设置为全局变量KeActiveProcessors,即系统中当前的可用处理器。

1
2
3
4
5
6
7
    } else {
 
        Parent = NULL;
        Affinity = KeActiveProcessors;
        WorkingSetMinimum = PsMinimumWorkingSet;
        WorkingSetMaximum = PsMaximumWorkingSet;
    }
kd> x nt!KeActiveProcessors
8089b280          nt!KeActiveProcessors = 1

3.调用ObCreateObject 函数,创建一个类型为PsProcessType 的内核对象,置于局部变量Process 中,其对象体为EPROCESS 数据结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
    Status = ObCreateObject (PreviousMode,
                             PsProcessType,
                             ObjectAttributes,
                             PreviousMode,
                             NULL,
                             sizeof (EPROCESS),
                             0,
                             0,
                             &Process);
 
    if (!NT_SUCCESS (Status)) {
        goto exit_and_deref_parent;
    }

4.把Process 对象中的所有域置为0,然后初始化其中部分成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    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;
    }

检查内存区句柄参数SectionHandle(对于系统进程如system及其子进程,此参数为NULL)

4.如SectionHandle不为NULL,则利用此句柄参数调用ObReferenceObjectByHandle 获得内存区对象的指针。所以,新进程对象的内存区对象已经完成初始化。

1
2
3
4
5
6
7
8
9
10
11
12
  if (ARGUMENT_PRESENT (SectionHandle)) {
        Status = ObReferenceObjectByHandle (SectionHandle,
                                            SECTION_MAP_EXECUTE,
                                            MmSectionObjectType,
                                            PreviousMode,
                                            &SectionObject,
                                            NULL);
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }
 
    } else {

5.如SectionHandle为NULL,这部分代码有点诡异:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
} else {
        SectionObject = NULL;
        if (Parent != PsInitialSystemProcess) {
            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;
            }
        }
    }

参看PspCreateProcess的三个调用处,可以知道这里会存在三种状态:

(1).如果NtCreateProcessEx调用,但Parent不为NULL且SectionHandle为NULL,此时,内存区对象直接继承自父进程,走入上面的条件句

(2).如果NtCreateProcessEx调用,但Parent不为NULL且SectionHandle不为NULL,此时,走上面的条件4

(3).PsCreateSystemProcess 和PspInitPhase0的调用是传了NULL,所以Parent应该为NULL,那这句

ExAcquireRundownProtection (&Parent->RundownProtect)//Parent为NULL是必崩

是不是有可能崩溃,所以windbg跟了下,在system初始化时,PsInitialSystemProcess是为NULL的,Parent==PsInitialSystemProcess都为NULL,所以没有问题.

1
2
3
4
5
6
7
kd> r esi
esi=00000000
kd> p
nt!PspCreateProcess+0x230:
809302fc 3b358c5e8a80    cmp     esi,dword ptr [nt!PsInitialSystemProcess (808a5e8c)]
kd> x nt!PsInitialSystemProcess
808a5e8c          nt!PsInitialSystemProcess = 0x00000000

这也说明一个问题,如果你想再使用PspInitPhase0创建新的system,那这句必崩!

6.根据DebugPort 参数来初始化新进程对象的DebugPort 成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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);
        }
    }

如DebugPort不为NULL,则通过ObReferenceObjectByHandle 获得,如为NULL,且存在父进程,则尝试通过DbgkCopyProcessDebugPort复制父进程的

7.根据ExceptionPort 参数来初始化新进程对象的ExceptionPort 成员。如ExceptionPort不为NULL,则通过ObReferenceObjectByHandle 获得

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  if (ARGUMENT_PRESENT (ExceptionPort)) {
        Status = ObReferenceObjectByHandle (ExceptionPort,
                                            0,
                                            LpcPortObjectType,
                                            PreviousMode,
                                            &ExceptionPortObject,
                                            NULL);
 
        if (!NT_SUCCESS (Status)) {
            goto exit_and_deref;
        }
 
        Process->ExceptionPort = ExceptionPortObject;
    }

8.如果指定的父进程不为NULL,则利用MmCreateProcessAddressSpace创建一个全新的地址空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 if (Parent != NULL) {
 
        //
        // Calculate address space
        //
        //      If Parent == PspInitialSystem
        //
 
        if (!MmCreateProcessAddressSpace (WorkingSetMinimum,
                                          Process,
                                          &DirectoryTableBase[0])) {
 
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto exit_and_deref;
        }
 
    } else {

否则(对于系统进程),让新进程的句柄表指向当前进程的句柄表,并且利用空闲线程的地址空间来初始化新进程的地址空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    } 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;
        }
    }

9.调用KeInitializeProcess 函数来初始化新进程对象的基本优先级、Affinity、进程页表目录和超空间的页帧号。

1
2
3
4
5
6
7
  PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_HAS_ADDRESS_SPACE);
    Process->Vm.MaximumWorkingSetSize = WorkingSetMaximum;
    KeInitializeProcess (&Process->Pcb,
                         NORMAL_BASE_PRIORITY,
                         Affinity,
                         &DirectoryTableBase[0],
                         (BOOLEAN)(Process->DefaultHardErrorProcessing & PROCESS_HARDERROR_ALIGNMENT_BIT));

10.通过PspInitializeProcessSecurity 函数初始化新进程的安全属性,主要是从父进程复制一个令牌。

1
2
3
4
5
6
7
8
9
10
11
    //
    //  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;
    }

11.接下来设置新进程的优先级类别。如果父进程不为NULL,则拷贝父进程的优先级类别,并且初始化新进程的句柄表,若Flags 参数中包含了句柄继承标志,则把父进程句柄表中凡是有继承属性的对象拷贝到新进程句柄表中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    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;
        }
    }

12.初始化新进程的进程地址空间。有四种可能性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
    // Initialize the process address space
    // The address space has four possibilities
    //
    //      1 - Boot Process. Address space is initialized during
    //          MmInit. Parent is not specified.
    //
    //      2 - System Process. Address space is a virgin address
    //          space that only maps system space. Process is same
    //          as PspInitialSystemProcess.
    //
    //      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.
    //

(1).新进程有新的可执行映像内存区对象。调用MmInitializeProcessAddressSpace 函数,根据指定的内存区对象来初始化进程地址空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    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())
        //
 
        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) {

(2).没有指定映像内存区对象,但指定了父进程,而父进程并非PsInitialSystemProcess。调用MmInitializeProcessAddressSpace 函数,并根据父进程来初始化进程地址空间。并且把父进程的映像名称字符串拷贝到新进程对象的数据结构中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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.
            //
 
            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 {

(3).没有指定映像内存区对象,但指定了PsInitialSystemProcess 作为父进程。这对应于系统进程的情形。调用MmInitializeProcessAddressSpace,不指定内存区和父进程,直接初始化。同样地,把父进程的映像名称字符串拷贝到新进程对象的数据结构中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 } else {
 
            //
            // System Process.  Don't specify Process to clone or section to map
            //
 
            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;
            }
        }

可以看到(2)和(3)区别的关键代码:

  Process->SectionBaseAddress = Parent->SectionBaseAddress;
  MmInitializeProcessAddressSpace(..,Parent..)
  CreatePeb = TRUE;

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
  //
    // Create the process 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);

14.对这次进程创建行为进行审计。

1
2
3
4
5
6
7
  //
    // Audit the process creation.
    //
 
    if (SeDetailedAuditingWithToken (NULL)) {
        SeAuditProcessCreation (Process);
    }

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   //
    // 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;
            }
        }
    }

16.对于通过映像内存区对象来创建进程的情形,创建一个PEB;对于进程拷贝(fork)的情形,则使用继承的PEB。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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;

17.把新进程加入到全局的进程链表PsActiveProcessHead中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   //
    // Add the process to the global list of processes.
    //
 
    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;
        }
    }
kd> x nt!PsActiveProcessHead
808a5ec0          nt!PsActiveProcessHead = struct _LIST_ENTRY [ 0x84fe76e0 - 0x8456e2b8 ]

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 //
    // 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;
    }

19.通过PspComputeQuantumAndPriority计算新进程的基本优先级和时限重置值,并且设置进程的内存优先级。

1
2
3
4
5
6
7
8
9
10
11
12
13
//
    // 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;

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 //
    // 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;
    }

21.设置进程的创建时间。并把新进程的句柄赋到输出参数ProcessHandle 中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    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);
    }

以上是创建并初始化一个进程对象的过程。然而,经过PspCreateProcess 函数以后,新建的进程中并没有任何线程对象,所以,它现在还只是一个死的进程空间,也就是说,其中的代码并没有被真正运行起来

文章作者:hgy413
本文地址:http://hgy413.com/2924.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!

16 Responses to “WD-进程的创建流程(WRK)”

  1. #1 minecraft 回复 | 引用 Post:2018-10-05 16:35

    I’m not sure why but this site is loading very slow for me.

    Is anyone else having this issue or is it a problem on my end?
    I’ll check back later and see if the problem
    still exists.

  2. #2 minecraft 回复 | 引用 Post:2018-10-06 10:18

    I all the time used to study article in news papers but now
    as I am a user of internet so from now I am using
    net for articles, thanks to web.

  3. #3 minecraft 回复 | 引用 Post:2018-10-06 10:52

    I love looking through an article that can make men and women think.
    Also, thank you for permitting me to comment!

  4. I was curious if you ever considered changing the layout
    of your blog? Its very well written; I love what youve got to say.
    But maybe you could a little more in the way of content so people could connect with it
    better. Youve got an awful lot of text for only having 1 or 2 pictures.
    Maybe you could space it out better?

  5. Somebody necessarily help to make seriously posts I might state.
    This is the very first time I frequented your web page and so far?
    I amazed with the research you made to make this particular publish incredible.
    Magnificent job!

  6. Hi there, I found your blog via Google at the same
    time as searching for a similar subject, your web site got here up, it looks great.
    I’ve bookmarked it in my google bookmarks.
    Hello there, just turned into alert to your blog via Google, and found that it is truly informative.
    I am going to be careful for brussels. I will
    appreciate when you continue this in future. A lot of folks will probably be benefited out of your writing.
    Cheers!

  7. This paragraph is in fact a good one it helps new net users,
    who are wishing in favor of blogging.

  8. #8 Benefits of Coconut Oil 回复 | 引用 Post:2018-10-21 05:27

    It’s amazing to pay a quick visit this website and reading the views of
    all mates regarding this article, while I am also eager of getting knowledge.

  9. #9 quest bars 回复 | 引用 Post:2018-11-06 03:07

    Its not my first time to visit this web page, i am browsing this web page dailly and take nice
    information from here daily.

  10. #10 Quest Protein Bars 回复 | 引用 Post:2018-11-06 04:17

    I used to be recommended this web site via my cousin. I am
    now not certain whether this post is written by him as no one else know such exact about my difficulty.
    You’re amazing! Thanks!

  11. #11 Quest Bars Cheap 回复 | 引用 Post:2018-11-06 19:32

    Heya i’m for the primary time here. I found this board and
    I to find It truly helpful & it helped me out a lot.
    I hope to offer something again and help others such as you helped me.

  12. #12 Sling TV 回复 | 引用 Post:2018-11-11 20:25

    Oh my goodness! Impressive article dude! Thank you so
    much, However I am having issues with your RSS.
    I don’t understand why I cannot subscribe to it. Is there anybody having the same RSS issues?
    Anyone who knows the answer can you kindly respond? Thanx!!

  13. Hey! This post couldn’t be written any better! Reading through
    this post reminds me of my good old room mate!
    He always kept chatting about this. I will forward this
    write-up to him. Pretty sure he will have a good read.
    Thanks for sharing!

  14. Sling tv coupons and promo codes for november 2018
    Currently it looks like Movable Type is the best blogging platform available right now.

    (from what I’ve read) Is that what you’re using on your blog?
    Sling tv coupons and promo codes for november 2018

  15. Sling tv coupons and promo codes for november 2018
    We’re a group of volunteers and opening a new scheme
    in our community. Your site provided us with valuable info to work on. You have done
    a formidable job and our entire community will be grateful
    to you. Sling tv coupons and promo codes for november 2018

  16. I’m not that much of a internet reader to be honest but your
    blogs really nice, keep it up! I’ll go ahead and bookmark your website to come back later
    on. All the best

发表评论