zoukankan      html  css  js  c++  java
  • 64位CreateProcess逆向:(二)0环下参数的整合即创建进程的整体流程

    转载:https://bbs.pediy.com/thread-207683.htm

    点击下面进入总目录:
    64位Windows创建64位进程逆向分析(总目录)

    在上一篇文章中,我们介绍了CreateProcess在3环的整个流程。在其中特别提到,当操作系统由3环切换到0环,是由NtCreateUserProcess完成所有关键工作的。
        在这篇文章中,我们将会介绍0环函数NtCreateUserProcess的整体流程。

    准备工作
        我们分析64位的Windows 7发现,其3环切换0环所用的特权指令是syscall(而不是sysenter),不过,他们两者的区别主要只在兼容模式是否有效上,与我们分析CreateProcess关系不大。不过,0环3环的切换,是既重要又基础的概念,对于还没概念的朋友,可以先查阅下Intel手册或者相关书籍。


        NtCreateUserProcess是一个复杂的函数,如果想在成千上万行的汇编代码中不迷失自己的目标,就要把握好它的核心,在此,我们提前强调三个结构体:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    struct _PPROCESS_CREATE_INFO
    {
      QWORD cb;//结构体大小
      QWORD UnKown;
      DWORD Flags2;
      BYTE  UnKown;
      WORD ImageCharacteristics;
      DWORD DesiredAccess; //3环下会赋值,0环下赋值给CREATEPROCESSCONTEXT的成员DesiredAccess
      QWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      DWORD UnKown;
      BYTE UnKown;
      DWORD Flags;
      PVOID* CurrentPeb;
      PVOID* ParentProcessPeb;
      QWORD UnKown;
      DWORD UnKown;
      BYTE UnKown;
    };

    _PPROCESS_CREATE_INFO是NtCreateUserProcess的带出参数,进程创建完成(或失败)后,它其中的内容就会填充相关信息,因此关注它,可以得到回溯到进程创建后的关键信息。
    //CREATEPROCESSCONTEXT注释版
    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    struct CREATEPROCESSCONTEXT
    {
      /*
      标志位  主要在PspAllocateProcess中使用
      */
      DWORD Flags;
      /*
      标志位:
      */
      BYTE Flags2;
      BYTE UnKown;
      /*
      镜像特征,由SECTION_IMAGE_INFORMATION结构ImageCharacteristics成员而来
      */
      WORD ImageCharacteristics;
      /*
      指向CLIENT_ID结构体的指针,CLIENT_ID定义如下:
      typedef struct _CLIENT_ID
      {
         HANDLE PID;
         HANDLE TID;
      } CLIENT_ID, *PCLIENT_ID;
      */
      CLIENT_ID* pClient_ID;
      /*
      指向TEB结构体的指针
      */
      TEB* pTeb;
      /*
      指向_SECTION_IMAGE_INFORMATION结构体的指针,该成员由最后一个参数传入,其属性值为6.
      */
      SECTION_IMAGE_INFORMATION *pSectionImageInfo;
      /*
      指向CREATEINFO结构体的指针,该结构体由PspCaptureCreateInfo函数负责初始化.
      */
      CREATEINFO *pCreateInfo;
      /*
      SECTION_IMAGE_INFORMATION结构体,这是即将创建进程的可执行文件映射到内存后的内存对象.
      */
      SECTION_IMAGE_INFORMATION SectionImageInfo;
      /*
      父进程句柄,由最后一个参数传入,其属性值为0x60000.
      */
      HANDLE hParentProcess;
      /*
      新进程的EPROCESS指针.
      */
      EPROCESS* pEprocess;
      /*
      调试对象的句柄,如果调用CreateProcess时创建选项中带有调试标志,则由最后一个参数会传入调试对象的句柄,将会保持到这个成员里面来.
      */
      HANDLE DebugObjectHandle;
      /*
      令牌对象句柄,由最后一个参数会传入,属性值0x60002.
      */
      HANDLE hSeTokenObject;
      DWORD DesiredAccess;
      /*
      文件句柄,新进程可执行文件的文件句柄.
      */
      HANDLE FileHandle;
      /*
      文件对象,新进程可执行文件的文件对象
      */
      FILE_OBJECT* pFileObject;
      /*
      新进程加载到内存后的内存对象.
      */
      HANDLE SectionHandle;
      HANDLE KeyHandle;
      SECTION_OBJECT* pSectionObject;
      /*
      _RTL_USER_PROCESS_PARAMETERS结构体指针.
      */
      PVOID pRtlUserProcessParameter;
      PVOID pBackupRtlUserProcessParameter;
      DWORD UnKown;
      /*
      PspWow64SetupUserProcessAddressSpace函数内赋值,具体含义不太清楚
      */
      DWORD UnKown;
      /*
      新进程可执行文件全路径
      */
      UNICODE_STRING FileName;
      /*
      优先级
      */
      BYTE PriorityClass;
      /*
      该成员会负责给新进程EPROCESS.Pcb.Flags.
      */
      BYTE EprocessFlags;
      /*
      作为查询全局表KeNodeBlock的下标
      */
      WORD KnodeIndex;
      /*
      全局表KiProcessorNumberToIndexMappingTable的表项
      */
      DWORD Mapping;
      QWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      DWORD UnKown;
      DWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      DWORD UnKown;
      /*
      由最后一个参数传入,其属性值为0x20009.
      */
      DWORD DefaultHardErrorProcessing;
      QWORD UnKown;
      /*
      和全局变量KiActiveGroups作比较
      */
      WORD ActiveGroupCount;
      WORD UnKown;
      WORD UnKown;
      WORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
    };

    //CREATEPROCESSCONTEXT无注释版
    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
    struct CREATEPROCESSCONTEXT
    {
      DWORD Flags;
      BYTE Flags2;
      BYTE UnKown;
      WORD ImageCharacteristics;
      CLIENT_ID* pClient_ID;
      TEB* pTeb;
      SECTION_IMAGE_INFORMATION *pSectionImageInfo;
      CREATEINFO *pCreateInfo;
      SECTION_IMAGE_INFORMATION SectionImageInfo;
      HANDLE hParentProcess;
      EPROCESS* pEprocess;
      HANDLE DebugObjectHandle;
      HANDLE hSeTokenObject;
      DWORD DesiredAccess;
      HANDLE FileHandle;
      FILE_OBJECT* pFileObject;
      HANDLE SectionHandle;
      HANDLE KeyHandle;
      SECTION_OBJECT* pSectionObject;
      PVOID pRtlUserProcessParameter;
      PVOID pBackupRtlUserProcessParameter;
      DWORD UnKown;
      DWORD UnKown;
      UNICODE_STRING FileName;
      BYTE PriorityClass;
      BYTE EprocessFlags;
      WORD KnodeIndex;
      DWORD Mapping;
      QWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      DWORD UnKown;
      DWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      DWORD UnKown;
      DWORD DefaultHardErrorProcessing;
      QWORD UnKown;
      WORD ActiveGroupCount;
      WORD UnKown;
      WORD UnKown;
      WORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
      QWORD UnKown;
    };

    简单说,这个结构体代表了整个新进程,因此与进程有关的几乎所有信息,都在其中,如文件映像信息、线程信息等。夸张一点讲,这个结构体贯穿了整个创建进程的过程,弄明白它,就弄明白了操作系统如何创建进程。
    1
    2
    3
    4
    5
    6
    7
    8
    struct ALL_ACCESS_STATE  //为结构体ACCESS_STATE的扩展版本
    {
      ACCESS_STATE AssedAccessState;//具体可查看MSDN
      BYTE AuxData[216];
      DWORD HandleAttributes;
      DWORD AcessMode;
      QWORD hProcess;
    };

    接下来,我们正式来看NtCreateUserProcess所做的工作。
    NtCreateUserProcess
    NtCreateUserProcess的函数原型如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    void NtCreateUserProcess(
              //传出新进程句柄
    OUT PHANDLE ProcessHandle,
    //传出新进程主线程句柄
    OUT PHANDLE ThreadHandle,
    //当前进程对新进程操作权限描述, 一般是MAXIMUM_ALLOWED, 无限制
    IN ACCESS_MASK ProcessDesiredAccess,
    //当前进程对新线程的操作权限描述, 一般是 MAXIMUM_ALLOWED
    IN ACCESS_MASK ThreadDesiredAccess, //
    //进程对象属性, 可空
    IN POBJECT_ATTRIBUTES ProcessObjectAttributes OPTIONAL, //线程对象属性, 可为空  
    IN POBJECT_ATTRIBUTES ThreadObjectAttributes OPTIONAL, //新进程创建标志
    IN ULONG CreateProcessFlags,
    //新线程创建标志
    IN ULONG CreateThreadFlags, 
    //进程创建的相关参数信息,包括待启动进程的映像路径,命令参数,环境
    //行变量串等信息
    IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters, 
    //传出一些基本信息, 比如新进程的PEB
    OUT  PPROCESS_CREATE_INFO CreateInfo,
    //传入参数, 保存了一些信息. 比如程序路径 父进程PID等
    IN PNT_PROC_THREAD_ATTRIBUTE_LIST AttributeList);

    从文末附上的整体流程图可以看出,NtCreateUserProcess内部的模块化是做的挺好的,由多个函数完成各自的任务。因此,我们除了梳理NtCreateUserProcess的流程外,就是逐个解剖NtCreateUserProcess所调用的函数。在这篇文章中,我们将详细介绍PspBuildCreateProcessContext、PspCaptureCreateInfo、PspCaptureProcessParameters三个功能函数。

    NtCreateUserProcess流程
    初始化

    在一开始,NtCreateUserProcess会做一些初始化的工作,具体是:
      将参数ThreadDesiredAccess、ProcessDesiredAccess、ThreadHandle、ProcessHandle、ProcessObjectAttributes、ThreadObjectAttributes、ProcessParameters保存到局部变量中。
      将句柄变量var_Context(新线程环境)初始化为0.
      检查参数ThreadHandle、ProcessHandle地址是否小于MmUserProbeAddress(是否小于系统地址),不是则将其设置为MmUserProbeAddress。
      检查参数ProcessObjectAttributes地址是否对齐,不对齐则调用ExRaiseDatatypeMisalignment触发STATUS_DATATYPE_MISALIGNMENT异常。
      检查参数ProcessObjectAttributes地址是否小于MmUserProbeAddress(是否小于系统地址),不是则将其设置为MmUserProbeAddress。
      用参数ProcessObjectAttributes.Attributes初始化var_AccessState1.HandleAttributes,var_AccessState1后面将作为创建新进程句柄的参数。

    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
    000000014031D745                 mov     [rsp+0B28h+var_ThreadDesiredAccess], r9d ; ThreadDesiredAccess
    000000014031D74A                 mov     [rsp+0B28h+var_ProcessDesiredAccess], r8d ; ProcessDesiredAccess
    000000014031D74F                 mov     [rsp+0B28h+var_ThreadHandle], rdx ; ThreadHandle
    000000014031D757                 mov     [rsp+0B28h+var_ProcessHandle], rcx ; ProcessHandle
    000000014031D75F                 mov     rsi, [rsp+0B28h+ProcessObjectAttributes] ; ProcessObjectAttributes
    000000014031D767                 mov     [rsp+0B28h+var_ProcessObjectAttributes], rsi
    000000014031D76F                 mov     rax, [rsp+0B28h+ThreadObjectAttributes] ; ThreadObjectAttributes
    000000014031D777                 mov     [rsp+0B28h+var_ThreadObjectAttributes], rax ; ThreadFlags
    000000014031D77F                 mov     rax, [rsp+0B28h+ProcessParameters] ; ProcessParameters
    000000014031D787                 mov     [rsp+0B28h+var_ProcessParameters], rax
    000000014031D78F                 mov     r12, [rsp+0B28h+CreateInfo] ; CreateInfo
    000000014031D797                 mov     rdi, [rsp+0B28h+AttributeList] ; AttributeList
    000000014031D79F                 xor     ebx, ebx
    000000014031D7A1                 mov     [rsp+130h], rbx
    000000014031D7A9                 xor     edx, edx        ; Val
    000000014031D7AB                 lea     r8d, [rbx+38h]  ; Size
    000000014031D7AF                 lea     rcx, [rsp+0B28h+Dst] ; Dst
    000000014031D7B7                 call    memset
    000000014031D7BC                 mov     [rsp+0B28h+var_Context.P1Home], rbx
    000000014031D7C4                 xor     edx, edx        ; Val
    000000014031D7C6                 mov     r8d, 4C8h       ; Size
    000000014031D7CC                 lea     rcx, [rsp+0B28h+var_Context.P2Home] ; Dst
    000000014031D7D4                 call    memset          ; memset(&Context.P2Home,0,sizeof(Context) - 4);
    000000014031D7D9                 mov     r14, gs:188h
    000000014031D7E2                 mov     [rsp+0B28h+var_Ethread], r14
    000000014031D7EA                 mov     r15, [r14+_ETHREAD.Tcb.ApcState.ApcState.Process]
    000000014031D7EE                 mov     [rsp+0B28h+var_TempProcess], r15
    000000014031D7F3                 mov     r13b, [r14+_ETHREAD.Tcb.PreviousMode]
    000000014031D7FA                 mov     [rsp+0B28h+var_PreviousMode], r13b
    000000014031D7FF                 mov     edx, dword ptr [rsp+0B28h+CreateProcessFlags] ; ProcessFlags


    以及:
    初始化var_CreateProcessContext(见上文的结构体介绍)为0。
    1
    2
    3
    4
    000000014031D8E1                 xor     edx, edx        ; Val
    000000014031D8E3                 mov     r8d, 150h       ; Size
    000000014031D8E9                 lea     rcx, [rsp+0B28h+var_CreateProcessContext] ; Dst
    000000014031D8F1                 call    memset          ; memset(&CreateProcessContext,0,sizeof(CreateProcessContext));


    调用PspBuildCreateProcessContext解析参数AttributeList到var_CreateProcessContext中。(具体看之后的函数分析)
    000000014031D8FB                 lea     r9, [rsp+0B28h+var_CreateProcessContext] ; 参数pCreateProcessContext
    1
    2
    3
    4
    5
    6
    7
    8
    9
    000000014031D903                 xor     r8d, r8d        ; 参数Unkown=0
    000000014031D906                 mov     dl, r13b        ; 参数PreviousMode
    000000014031D909                 mov     rcx, rdi        ; 参数AttributeList
    000000014031D90C                 call    PspBuildCreateProcessContext ;
    000000014031D90C                                         ; PspBuildCreateProcessContext(
    000000014031D90C                                         ;     AttributeList,
    000000014031D90C                                         ;     PreviousMode,
    000000014031D90C                                         ;     Unkown=0,
    000000014031D90C                                         ;     pCreateProcessContext);


    调用PspCaptureCreateInfo解析参数CreateInfo到var_CreateProcessContext中。(具体看之后的函数分析) 
    1
    2
    3
    4
    5
    6
    7
    8
    000000014031D938                 lea     r8, [rsp+0B28h+var_CreateProcessContext] ; 参数pCreateProcessContext
    000000014031D940                 mov     rdx, r12        ; 参数pCreateInfo
    000000014031D943                 mov     cl, r13b        ; 参数AccessMode
    000000014031D946                 call    PspCaptureCreateInfo ;
    000000014031D946                                         ; PspCaptureCreateInfo(
    000000014031D946                                         ;     AccessMode,
    000000014031D946                                         ;     pCreateInfo,
    000000014031D946                                         ;     CreateProcessContext);


    接着:会根据CreateProcessContext.Flags的标志状态来选择父进程。在后续函数PspAllocateProcess中我们会看到,新进程在一定条件下,是可以获取父进程的section的,因此此处的判断很必要。
    如果CreateProcessContext.Flags&1的结果为假,则调用ObReferenceObjectByHandle获取CreateProcessContext.hProcess进程对象。这样就保证了无论如何新进程是有父进程的。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    000000014031D955                 mov     ecx, [rsp+0B28h+var_CreateProcessContext.Flags]
    000000014031D95C                 mov     r12d, 1
    000000014031D962                 test    r12b, cl
    000000014031D965                 jz      short loc_14031D9C8 ; if(CreateProcessContext.Flags&1)
    000000014031D965                                         ;          ParentEProcess=CurrentProcess
    000000014031D965                                         ; 如果CreateProcessContext.Flags&1为真,则父进程为当前进程
    000000014031D965                                         ; 否则父进程为参数AttributeList中指定的进程
    000000014031D967                 mov     [rsp+28h], rbx  ; 参数HandleInformation
    000000014031D96C                 lea     rax, [rsp+0B28h+var_Eprocess]
    000000014031D974                 mov     [rsp+20h], rax  ; 参数pEprocess
    000000014031D979                 mov     r9b, r13b       ; 参数AccessMode
    000000014031D97C                 mov     r8, cs:PsProcessType ; 参数ObjectType
    000000014031D983                 lea     edx, [r12+7Fh]  ; 参数DesiredAccess
    000000014031D988                 mov     rcx, [rsp+0B28h+var_CreateProcessContext.hParentProcess] ; Handle
    000000014031D990                 call    ObReferenceObjectByHandle ;
    000000014031D990                                         ; ObReferenceObjectByHandle(
    000000014031D990                                         ;     CreateProcessContext.hParentProcess,
    000000014031D990                                         ;     DesiredAccess,
    000000014031D990                                         ;     PsProcessType,
    000000014031D990                                         ;     AccessMode,
    000000014031D990                                         ;     pEprocess,
    000000014031D990                                         ;     HandleInformation);


    创建文件映射对象
    我们知道,代码最开始保存在PE文件中的,而最终执行前CPU是从内存中读取的,那么操作系统一定有一个步骤,实现了(磁盘上的)文件到内存中的加载。这一步就是在NtCreateUserProcess初始化完成后开始做的。

    具体而言:
    调用ZwOpenFile打开新进程可执行文件,并根据打开的文件句柄获取文件对象:
    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
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    000000014031DA18                 mov     [rsp+0B28h+var_ObjectAttributes.Length], 30h
    000000014031DA23                 mov     [rsp+0B28h+var_ObjectAttributes.RootDirectory], rbx
    000000014031DA2B                 or      eax, 240h
    000000014031DA30                 mov     [rsp+0B28h+var_ObjectAttributes.Attributes], eax
    000000014031DA37                 lea     rax, [rsp+0B28h+var_CreateProcessContext.FileName]
    000000014031DA3F                 mov     [rsp+0B28h+var_ObjectAttributes.ObjectName], rax
    000000014031DA47                 mov     [rsp+0B28h+var_ObjectAttributes.SecurityDescriptor], rbx
    000000014031DA4F                 mov     [rsp+0B28h+var_ObjectAttributes.SecurityQualityOfService], rbx
    000000014031DA57                 mov     edx, [rsp+0B28h+var_CreateProcessContext.DesiredAccess]
    000000014031DA5E                 or      edx, 100020h    ; 参数DesiredAccess
    000000014031DA64                 mov     dword ptr [rsp+28h], 60h ; 参数OpenOptions
    000000014031DA6C                 mov     dword ptr [rsp+20h], 5 ; 参数ShareAccess
    000000014031DA74                 lea     r9, [rsp+0B28h+var_IoStatusBlock] ; 参数IoStatusBlock
    000000014031DA7C                 lea     r8, [rsp+0B28h+var_ObjectAttributes] ; 参数ObjectAttributes
    000000014031DA84                 lea     rcx, [rsp+0B28h+var_CreateProcessContext.FileHandle] ; 参数FileHandle
    000000014031DA8C                 call    ZwOpenFile      ; ZwOpenFile(CreateProcessContext.FileHandle,
    000000014031DA8C                                         ;     DesiredAccess,
    000000014031DA8C                                         ;     ObjectAttributes,
    000000014031DA8C                                         ;     IoStatusBlock,
    000000014031DA8C                                         ;     ShareAccess,
    000000014031DA8C                                         ;     OpenOptions);
    000000014031DA91                 mov     edi, eax
    000000014031DA93                 cmp     eax, ebx
    000000014031DA95                 jge     short loc_14031DAD4
    000000014031DA97                 cmp     [rsp+0B28h+var_CreateProcessContext.DesiredAccess], ebx
    000000014031DA9E                 jz      short loc_14031DAD4
    000000014031DAA0                 mov     dword ptr [rsp+28h], 60h ; 参数OpenOptions
    000000014031DAA8                 mov     dword ptr [rsp+20h], 5 ; 参数ShareAccess
    000000014031DAB0                 lea     r9, [rsp+0B28h+var_IoStatusBlock] ; 参数IoStatusBlock
    000000014031DAB8                 lea     r8, [rsp+0B28h+var_ObjectAttributes] ; 参数ObjectAttributes
    000000014031DAC0                 mov     edx, 100020h    ; 参数DesiredAccess
    000000014031DAC5                 lea     rcx, [rsp+0B28h+var_CreateProcessContext.FileHandle] ; 参数FileHandle
    000000014031DACD                 call    ZwOpenFile      ; ZwOpenFile(CreateProcessContext.FileHandle,
    000000014031DACD                                         ;     DesiredAccess,
    000000014031DACD                                         ;     ObjectAttributes,
    000000014031DACD                                         ;     IoStatusBlock,
    000000014031DACD                                         ;     ShareAccess,
    000000014031DACD                                         ;     OpenOptions);
    000000014031DAD2                 mov     edi, eax
    000000014031DAD4
    000000014031DAD4 loc_14031DAD4:                          ; CODE XREF: NtCreateUserProcess+375j
    000000014031DAD4                                         ; NtCreateUserProcess+37Ej
    000000014031DAD4                 cmp     edi, ebx
    000000014031DAD6                 jge     short loc_14031DAF8
    000000014031DAD8                 mov     [rsp+0B28h+var_CreateProcessContext.FileHandle], rbx
    000000014031DAE0                 xor     r8d, r8d
    000000014031DAE3                 lea     rdx, [rsp+0B28h+var_CreateProcessContext]
    000000014031DAEB                 mov     ecx, r12d
    000000014031DAEE                 call    PspUpdateCreateInfo
    000000014031DAF3                 jmp     loc_14031E1D8   ; 打开文件失败
    000000014031DAF8 ; ---------------------------------------------------------------------------
    000000014031DAF8
    000000014031DAF8 loc_14031DAF8:                          ; CODE XREF: NtCreateUserProcess+3B6j
    000000014031DAF8                 mov     [rsp+0B28h+var_B00], rbx ; 参数HandleInformation
    000000014031DAFD                 lea     rax, [rsp+0B28h+var_File]
    000000014031DB05                 mov     [rsp+20h], rax  ; 参数pFile
    000000014031DB0A                 xor     r9d, r9d        ; 参数AccessMode
    000000014031DB0D                 mov     r8, cs:IoFileObjectType ; 参数ObjectType
    000000014031DB14                 mov     edx, 100020h    ; 参数DesiredAccess
    000000014031DB19                 mov     rcx, [rsp+0B28h+var_CreateProcessContext.FileHandle] ; 参数Handle
    000000014031DB21                 call    ObReferenceObjectByHandle ;
    000000014031DB21                                         ; ObReferenceObjectByHandle(
    000000014031DB21                                         ;     CreateProcessContext.FileHandle,
    000000014031DB21                                         ;     DesiredAccess,
    000000014031DB21                                         ;     IoFileObjectType,
    000000014031DB21                                         ;     AccessMode,
    000000014031DB21                                         ;     pFile,
    000000014031DB21                                         ;     HandleInformation);
    000000014031DB26                 mov     edi, eax
    000000014031DB28                 mov     rax, [rsp+0B28h+var_File]
    000000014031DB30                 mov     [rsp+0B28h+var_CreateProcessContext.FileObject], rax
    000000014031DB38                 cmp     edi, ebx
    000000014031DB3A                 jge     short loc_14031DB49
    000000014031DB3C                 mov     [rsp+0B28h+var_CreateProcessContext.FileObject], rbx
    000000014031DB44                 jmp     loc_14031E1D8   ; 获取文件对象失败


    调用ZwCreateSection通过文件句柄创建文件映像:
    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
    000000014031DB60                 mov     rax, [rsp+0B28h+var_CreateProcessContext.FileHandle]
    000000014031DB68                 mov     [rsp+30h], rax  ; 参数FileHandle
    000000014031DB6D                 mov     [rsp+28h], ecx  ; 参数AllocationAttributes
    000000014031DB71                 mov     dword ptr [rsp+20h], 10h ; 参数SectionPageProtection
    000000014031DB79                 xor     r9d, r9d        ; 参数MaximumSize
    000000014031DB7C                 lea     r8, [rsp+0B28h+var_ObjectAttributes] ; 参数ObjectAttributes
    000000014031DB84                 mov     edx, 0F001Fh    ; 参数DesiredAccess
    000000014031DB89                 lea     rcx, [rsp+0B28h+var_CreateProcessContext.SectionHandle] ; 参数SectionHandle
    000000014031DB91                 call    ZwCreateSection ; ZwCreateSection(SectionHandle,
    000000014031DB91                                         ;     DesiredAccess,
    000000014031DB91                                         ;     ObjectAttributes,
    000000014031DB91                                         ;     MaximumSize,
    000000014031DB91                                         ;     SectionPageProtection,
    000000014031DB91                                         ;     AllocationAttributes,
    000000014031DB91                                         ;     CreateProcessContext.FileHandle);
    000000014031DBBD                 mov     [rsp+28h], rbx  ; 参数HandleInformation
    000000014031DBC2                 lea     rax, [rsp+0B28h+var_SectionObject]
    000000014031DBCA                 mov     [rsp+20h], rax  ; 参数SectionObject
    000000014031DBCF                 xor     r9d, r9d        ; 参数AccessMode
    000000014031DBD2                 mov     r8, cs:MmSectionObjectType ; 参数ObjectType
    000000014031DBD9                 lea     edx, [r9+8]     ; 参数DesiredAccess
    000000014031DBDD                 mov     rcx, [rsp+0B28h+var_CreateProcessContext.SectionHandle] ; 参数Handle
    000000014031DBE5                 call    ObReferenceObjectByHandle ;
    000000014031DBE5                                         ; ObReferenceObjectByHandle(
    000000014031DBE5                                         ;     CreateProcessContext.SectionHandle,
    000000014031DBE5                                         ;     DesiredAccess,
    000000014031DBE5                                         ;     MmSectionObjectType,
    000000014031DBE5                                         ;     AccessMode,
    000000014031DBE5                                         ;     pSectionObject,
    000000014031DBE5                                         ;     HandleInformation);
    000000014031DBEA                 mov     edi, eax
    000000014031DBEC                 mov     rax, [rsp+0B28h+var_SectionObject]
    000000014031DBF4                 mov     [rsp+0B28h+var_CreateProcessContext.SectionObject], rax
    000000014031DBFC                 cmp     edi, ebx
    000000014031DBFE                 jge     short loc_14031DC0D
    000000014031DC00                 mov     [rsp+0B28h+var_CreateProcessContext.SectionObject], rbx
    000000014031DC08                 jmp     loc_14031E1D8   ; 获取进程文件映像对象失败


    此处使用的ZwOpenFile、与ZwCreateSection都是WDK文档中公开的函数,ZwOpenFile顾名思义就不用多说了,ZwCreateSection则类似于3环的CreateFileMapping,ZwCreateSection创建的Section Objects,既可用于进程间共享信息,又可用于文件映射,更具体的可以参考WDK文档。
    不过,在ZwCreateSection存在以下调用关系:

    而其中的MiVerifyImageHeader就是PE检查,对64位PE格式感兴趣的朋友,一定不能放过。我们将会在下一篇文章中,详细介绍MiVerifyImageHeader,并献上攻防实例。

    将参数整合到CREATEPROCESSCONTEXT结构体中

    如果文件映像对象Section不为空,则调用PspCaptureProcessParameters将参数
    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
    ProcessParameters中的信息保存到CreateProcessContext中:
    000000014031DC25                 cmp     rax, rbx
    000000014031DC28                 jz      short loc_14031DC7E ; if(CreateProcessContext.SectionObject==NULL)
    000000014031DC2A                 bt      [r15+_EPROCESS.Flags2], 0Bh
    000000014031DC33                 jb      short loc_14031DC46 ; 参数pCreateProcessContext
    000000014031DC35                 cmp     esi, ebx
    000000014031DC37                 jz      short loc_14031DC46 ; 参数pCreateProcessContext
    000000014031DC39                 cmp     r13b, bl
    000000014031DC3C                 jz      short loc_14031DC46 ; 参数pCreateProcessContext
    000000014031DC3E                 or      [rsp+0B28h+var_CreateProcessContext.Flags2], 10h
    000000014031DC46
    000000014031DC46 loc_14031DC46:                          ; CODE XREF: NtCreateUserProcess+513j
    000000014031DC46                                         ; NtCreateUserProcess+517j
    000000014031DC46                                         ; NtCreateUserProcess+51Cj
    000000014031DC46                 lea     r8, [rsp+0B28h+var_CreateProcessContext] ; 参数pCreateProcessContext
    000000014031DC4E                 mov     rdx, [rsp+0B28h+var_ProcessParameters] ; 参数ProcessParameters
    000000014031DC56                 mov     cl, r13b        ; 参数PreviousMode
    000000014031DC59                 call    PspCaptureProcessParameters ; //初始化pRtlUserProcessParameter
    000000014031DC59                                         ; PspCaptureProcessParameters(
    000000014031DC59                                         ;     PreviousMode,
    000000014031DC59                                         ;     ProcessParameters,
    000000014031DC59                                         ;     pCreateProcessContext);
    000000014031DC5E                 mov     edi, eax
    000000014031DC60                 cmp     eax, ebx
    000000014031DC62                 jge     short loc_14031DC71
    000000014031DC64                 and     [rsp+0B28h+var_CreateProcessContext.Flags2], 0FBh
    000000014031DC6C                 jmp     loc_14031E1D8   ; PspCaptureProcessParameters执行失败


    关于PspCaptureProcessParameters内部的具体分析见本贴最后部分。

    接着,调用PspAllocateProcess创建进程:
    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
    000000014031DD27                 lea     rax, [rsp+0B28h+var_pTempNewEprocess] ; 参数pNewProcess
    000000014031DD2C                 mov     [rsp+40h], rax
    000000014031DD31                 lea     rax, [rsp+0B28h+var_AA0] ; 参数Unkown
    000000014031DD39                 mov     [rsp+38h], rax
    000000014031DD3E                 lea     rax, [rsp+0B28h+var_CreateProcessContext] ; 参数CreateProcessContext
    000000014031DD46                 mov     [rsp+30h], rax
    000000014031DD4B                 mov     eax, dword ptr [rsp+0B28h+CreateProcessFlags] ; 参数ProcessFlags
    000000014031DD52                 mov     [rsp+28h], eax
    000000014031DD56                 mov     rax, [rsp+0B28h+var_CreateProcessContext.hSeTokenObject] ; 参数hSeTokenObject
    000000014031DD5E                 mov     [rsp+20h], rax
    000000014031DD63                 mov     r9, [rsp+0B28h+var_CreateProcessContext.SectionObject] ; 参数SectionObject
    000000014031DD6B                 mov     r8, [rsp+0B28h+var_ProcessObjectAttributes] ; 参数ProcessObjectAttributes
    000000014031DD73                 mov     dl, r13b        ; 参数PreviousMode
    000000014031DD76                 mov     rcx, qword ptr [rsp+0B28h+var_pProcess] ; 参数ParentEProcess
    000000014031DD7E                 call    PspAllocateProcess ;
    000000014031DD7E                                         ; PspAllocateProcess(
    000000014031DD7E                                         ;     ParentEProcess,
    000000014031DD7E                                         ;     PreviousMode,
    000000014031DD7E                                         ;     ProcessObjectAttributes,
    000000014031DD7E                                         ;     SectionObject,
    000000014031DD7E                                         ;     hSeTokenObject,
    000000014031DD7E                                         ;     ProcessFlags,
    000000014031DD7E                                         ;     CreateProcessContext,
    000000014031DD7E                                         ;     Unkown,
    000000014031DD7E                                         ;     pNewProcess);


    然后调用PspCreateUserContext创建新进程主线程运行环境:
    000000014031DDB6                 mov     dword ptr [rsp+0B28h+var_B08], ebx
    000000014031DDBA                 mov     r8, [rsp+0B28h+var_CreateProcessContext.SectionImageInfo.TransferAddress] ; 参数TransferAddress
    000000014031DDC2                 mov     rdx, cs:PspUserThreadStart ; 参数StartAddress
    000000014031DDC9                 lea     rcx, [rsp+0B28h+var_Context] ; 参数Context
    000000014031DDD1                 call    PspCreateUserContext ;
    000000014031DDD1                                         ; PspCreateUserContext(
    000000014031DDD1                                         ;     Context,
    000000014031DDD1                                         ;     StartAddress,
    000000014031DDD1                                         ;     TransferAddress,
    000000014031DDD1                                         ;     Peb);

    另外,从我们的流程图很容易看出,若Section Object为空的话,也并不意味着创建进程失败,系统会PspGetContextThreadInternal获取当前线程环境(此系列的后续文章会剖析它),之后的流程与Section不为空类似,不再详述。

    总之,当得到了线程Context之后,系统会调用PspAllocateThread创建、初始化线程:
    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
    000000014031DCE8                 mov     [rsp+0B28h+var_Context.ContextFlags], 10001Bh
    000000014031DCF3                 mov     [rsp+20h], r12b ; 参数dwOne=1
    000000014031DCF8                 mov     r9b, r12b       ; 参数isSystemThread=1
    000000014031DCFB                 xor     r8d, r8d        ; 参数AccessMode=0
    000000014031DCFE                 lea     rdx, [rsp+0B28h+var_Context] ; 参数pContext
    000000014031DD06                 mov     rcx, r14        ; 参数Ethread
    000000014031DD09                 call    PspGetContextThreadInternal ;
    000000014031DD09                                         ; PspGetContextThreadInternal(
    000000014031DD09                                         ;     Ethread,
    000000014031DD09                                         ;     pContext,
    000000014031DD09                                         ;     AccessMode,
    000000014031DD09                                         ;     isSystemThread,
    000000014031DD09                                         ;     dwOne);
     
    000000014031DE77                 mov     [rsp+0B28h+var_AccessStateExpand], eax
    000000014031DE7B                 lea     rax, [rsp+0B28h+var_AccessState2]
    000000014031DE83                 mov     [rsp+58h], rax  ; 参数pNewAccessState
    000000014031DE88                 mov     [rsp+50h], r14  ; 参数unknow
    000000014031DE8D                 lea     rax, [rsp+0B28h+var_pThread]
    000000014031DE95                 mov     [rsp+48h], rax  ; 参数pptrEthread
    000000014031DE9A                 lea     rax, [rsp+6Ch]  ; 参数pProcessFlag
    000000014031DE9F                 mov     [rsp+40h], rax  ; __int64
    000000014031DEA4                 mov     [rsp+38h], rbx  ; 参数StartContext
    000000014031DEA9                 mov     [rsp+30h], rbx  ; 参数StartRoutine
    000000014031DEAE                 lea     rax, [rsp+0B28h+var_Inital_teb] ; 参数pInitTeb
    000000014031DEB6                 mov     [rsp+28h], rax  ; __int64
    000000014031DEBB                 lea     rax, [rsp+0B28h+var_Context]
    000000014031DEC3                 mov     [rsp+20h], rax  ; 参数Context
    000000014031DEC8                 lea     r9, [rsp+0B28h+var_CreateProcessContext] ; __int64
    000000014031DED0                 mov     r8b, r13b       ; 参数AccessMode
    000000014031DED3                 mov     rdx, [rsp+0B28h+var_ThreadObjectAttributes] ; __int64
    000000014031DEDB                 mov     rcx, rsi        ; 参数newProcess
    000000014031DEDE                 call    PspAllocateThread ;
    000000014031DEDE                                         ; PspAllocateThread(
    000000014031DEDE                                         ;     newProcess,
    000000014031DEDE                                         ;     ObjectAttributes,
    000000014031DEDE                                         ;     AccessMode,
    000000014031DEDE                                         ;     CreateProcessContext,
    000000014031DEDE                                         ;     context,
    000000014031DEDE                                         ;     pInitTeb,
    000000014031DEDE                                         ;     StartRoutine,
    000000014031DEDE                                         ;     StartContext,
    000000014031DEDE                                         ;     ptrProcessFlag,
    000000014031DEDE                                         ;     pptrEthread,
    000000014031DEDE                                         ;     mydiy,
    000000014031DEDE                                         ;     pNewAccessState);


    新的进程及它的主线程就已经创建,只等ResumeThread(这个被放在3环),程序开始执行代码。

    进程链表、线程链表的更新
    在3环下编程,我们通常不大关心对方进程的信息,因为进程的内存是隔离的(想关心也关心不了)。但是,少数情况下,我们还是可以利用进程间通讯或者注入的手段,获取到对方进程中的信息。
    比如简单的SendMessage就可以在进程间通讯。
    那么深入一点点,就自然可以提出一个问题:既然进程间是隔离的,为什么SendMessage这样的API可以跨进程通讯呢?
    深入一点点,可以自然得到一个答案的方向:说明Windows操作系统本身,记录了所有进程的信息,以及各个进程之间的关系,使得各进程在操作系统那个层次,被组织到了一起。
    而这些进程被组织的具体细节,就藏在了NtCreateUserPorcess接下来调用的函数中:

    操作系统用链表的结构保存所有进程的EPROCESS结构体。

    NtCreateUserPorcess通过调用PspInsertProcess将新进程加入到那个全局链表中。
    关于PspInsertProcess的具体剖析,此系列的后续文章会介绍。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    000000014031DFC8                 lea     rdx, [rsp+0B28h+var_AccessState1]
    000000014031DFD0                 mov     [rsp+40h], rdx  ; 参数AccessState
    000000014031DFD5                 mov     [rsp+38h], rax  ; 参数enumType
    000000014031DFDA                 mov     [rsp+30h], r15d ; 参数unKnownFlag
    000000014031DFDF                 mov     rax, [rsp+0B28h+var_CreateProcessContext.DebugObjectHandle]
    000000014031DFE7                 mov     [rsp+28h], rax  ; 参数DebugObjectHandle
    000000014031DFEC                 mov     [rsp+20h], ebx  ; 参数JobMemberLevel
    000000014031DFF0                 mov     r9d, dword ptr [rsp+0B28h+CreateProcessFlags] ; 参数ProcessFlags
    000000014031DFF8                 mov     r8d, ecx        ; 参数ProcessDesiredAccess
    000000014031DFFB                 mov     rdx, qword ptr [rsp+0B28h+var_pProcess] ; 参数ParentEProcess
    000000014031E003                 mov     rcx, rsi        ; 参数Eprocess
    000000014031E006                 call    PspInsertProcess ;
    000000014031E006                                         ; PspInsertProcess(
    000000014031E006                                         ;     Eprocess,
    000000014031E006                                         ;     ParentEProcess,
    000000014031E006                                         ;     AccessMode,
    000000014031E006                                         ;     ProcessFlags,
    000000014031E006                                         ;     JobMemberLevel,
    000000014031E006                                         ;     DebugObjectHandle,
    000000014031E006                                         ;     unKnownFlag,
    000000014031E006                                         ;     enumType,
    000000014031E006                                         ;     AccessState);


    在调用PspInsertProcess失败后会调用PspDoHandleSweepSingle。
    1
    2
    3
    4
    5
    000000014031E09E                 jge     short loc_14031E0B0 ; 如果PspInsertProcess执行失败
    000000014031E0A0                 mov     rcx, rsi        ; 参数Eprocess
    000000014031E0A3                 call    PspDoHandleSweepSingle ; PspDoHandleSweepSingle(Eprocess);
    000000014031E0A8                 mov     edi, r13d
    000000014031E0AB                 jmp     loc_14031E1C1


    又因为进程与线程是一对多关系,每一个进程也对应着一个链表,该链表中保存着这个进程的所有线程信息。
    所以,NtCreateUserPorcess会调用PspInsertThread将新进程的主线程加入进程的线程链表中。
    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
    000000014031E00E                 mov     rcx, [rsp+0B28h+var_CreateProcessContext.pClient_ID]
    000000014031E016                 mov     [rsp+50h], rcx  ; 参数pClient_ID
    000000014031E01B                 mov     rax, [rsp+0B28h+var_ThreadHandle]
    000000014031E023                 mov     [rsp+48h], rax  ; 参数pThreadHandle
    000000014031E028                 mov     [rsp+40h], rbx  ; 参数
    000000014031E02D                 lea     rax, [rsp+0B28h+var_AccessState2]
    000000014031E035                 mov     [rsp+38h], rax  ; 参数NewAccessState
    000000014031E03A                 lea     rax, [rsp+0B28h+var_CreateProcessContext]
    000000014031E042                 mov     [rsp+30h], rax  ; 参数pCreateProcessContext
    000000014031E047                 mov     [rsp+28h], r14  ; 参数
    000000014031E04C                 mov     dword ptr [rsp+0B28h+var_B08], edi
    000000014031E050                 lea     r9, [rsp+0B28h+var_AccessStateExpand] ; 参数pProcessFlag
    000000014031E055                 lea     r8, [rsp+0B28h+var_Inital_teb] ; 参数pInital_teb
    000000014031E05D                 mov     rdx, rsi        ; 参数pEprocess
    000000014031E060                 mov     r14, [rsp+0B28h+var_pThread] ; 参数pThread
    000000014031E068                 mov     rcx, r14
    000000014031E06B                 call    PspInsertThread ;
    000000014031E06B                                         ; PspInsertProcess(
    000000014031E06B                                         ;     pThread,
    000000014031E06B                                         ;     pEprocess,
    000000014031E06B                                         ;     pInital_teb,
    000000014031E06B                                         ;     ProcessFlags,
    000000014031E06B                                         ;     pClient_ID,
    000000014031E06B                                         ;     pThreadHandle,
    000000014031E06B                                         ;     unknow,
    000000014031E06B                                         ;     NewAccessState,
    000000014031E06B                                         ;     CreateProcessContext,
    000000014031E06B                                         ;     );


    在调用PspInsertThread失败后会调用SeDeleteAccessState并接着调用PsTerminateProcess结束新进程。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    000000014031E1A6                 lea     rcx, [rsp+0B28h+var_AccessState1] ; 参数AccessState
    000000014031E1AE                 call    SeDeleteAccessState ; SeDeleteAccessState(pAccessState);
    000000014031E1B3                 cmp     edi, ebx
    000000014031E1B5                 jge     short loc_14031E1C1
    000000014031E1B7                 mov     edx, edi        ; 参数ExitStatus
    000000014031E1B9                 mov     rcx, rsi        ; 参数NewProcess
    000000014031E1BC                 call    PsTerminateProcess ; PsTerminateProcess(
    000000014031E1BC                                         ;     NewProcess,
    000000014031E1BC                                         ;     ExitStatus);


    交付APC
    异步过程调用(APC)是Windows提出的一种调用机制。对于有些函数调用,可能耗时比较多,而我们又希望调用完后函数能够立即返回,那么就适合用APC。
    APC的原理:对于需要使用APC的地方,一般,用户(程序员)会多传入一个函数指针,专有名词成为ApcRoutine,对于这样的调用,就是异步的了(即用户调用后立即返回),而当任务真正执行完毕,用户传入的ApcRoutine函数指针会被调用。类似我们传入了一个回调函数,响应任务完成的时机。
    它在Windows中应用很多,比如写文件时系统调用NtWriteFile().
    NtWriteFile声明如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    NTSTATUS NtWriteFile (
        __in HANDLE FileHandle,
        __in_opt HANDLE Event,
        __in_opt PIO_APC_ROUTINE ApcRoutine,
        __in_opt PVOID ApcContext,
        __out PIO_STATUS_BLOCK IoStatusBlock,
        __in_bcount(Length) PVOID Buffer,
        __in ULONG Length,
        __in_opt PLARGE_INTEGER ByteOffset,
        __in_opt PULONG Key
    )。

    可以看到NtWriteFile有使用APC。
    不过在此处,我们只要知道NtCreateUserPorcess会有APC检查和交付步骤就可以了,以后遇到会继续深入介绍:
    KiCheckForKernelApcDelivery交付当前线程APC:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    000000014031E072                 mov     rcx, [rsp+0B28h+var_Ethread]
    000000014031E07A                 add     [rcx+_ETHREAD.Tcb.___u22.__s5.KernelApcDisable], r12w
    000000014031E082                 jnz     short loc_14031E09B
    000000014031E084                 lea     rax, [rcx+_ETHREAD.Tcb.ApcState]
    000000014031E088                 cmp     [rax], rax
    000000014031E08B                 jz      short loc_14031E09B
    000000014031E08D                 cmp     [rcx+_ETHREAD.Tcb.___u22.__s5.SpecialApcDisable], bx
    000000014031E094                 jnz     short loc_14031E09B
    000000014031E096                 call    KiCheckForKernelApcDelivery


    接着,就是一些检查、释放资源类的扫尾工作了

    总之,若一切顺利,会调用PspUpdateCreateInfo将进程创建信息保存到传出参数CreateInfo中:
    1
    2
    3
    4
    5
    6
    7
    000000014031E131                 mov     r8, rsi         ; 参数Eprocess
    000000014031E134                 lea     rdx, [rsp+0B28h+var_CreateProcessContext] ; 参数pCreateProcessContext
    000000014031E13C                 mov     ecx, 6          ; 参数
    000000014031E141                 call    PspUpdateCreateInfo ; PspUpdateCreateInfo(
    000000014031E141                                         ;         dwEmCode,
    000000014031E141                                         ;         pCreateProcessContext,
    000000014031E141                                         ;         Eprocess);


    若不顺利,会调用PspDoHandleSweepSingle或者PsTerminateProcess结束新进程:
    1
    2
    3
    4
    5
    000000014031E1B7                 mov     edx, edi        ; 参数ExitStatus
    000000014031E1B9                 mov     rcx, rsi        ; 参数NewProcess
    000000014031E1BC                 call    PsTerminateProcess ; PsTerminateProcess(
    000000014031E1BC                                         ;     NewProcess,
    000000014031E1BC                                         ;     ExitStatus);


    最后,会调用PspDeleteCreateProcessContext清理CreateProcessContext,释放资源。


    PspBuildCreateProcessContext剖析
    函数原型:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    PspBuildCreateProcessContext(
          //属性列表
    IN  PNT_PROC_THREAD_ATTRIBUTE_LIST AtributeList, 
    //访问模式,表明调用来自用户态,还是内核态
    IN  BYTE                           AccessMode,
    //未知
    IN  DWORD                Unknown,
    //创建进程上下文
    OUT CreateProcessContext             pCreateProcessContext)

    函数功能:将参数AttributeList中信息保存到CreateProcessContext中。参数AttributeList为变长数组_NT_PROC_THREAD_ATTRIBUTE_LIST类型,定义如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    typedef struct _NT_PROC_THREAD_ATTRIBUTE_ENTRY 
    {
    //PROC_THREAD_ATTRIBUTE_XXX,参见MSDN中UpdateProcThreadAttribute
    //的说明
    ULONG_PTR Attribute;   
    //Value的大小 
    SIZE_T Size;            
    //保存4字节数据(比如一个Handle)或数据指针
    ULONG_PTR Value;    
    //总是0,可能是用来返回数据给调用者
    ULONG Unknown;      
    } PROC_THREAD_ATTRIBUTE_ENTRY, *PPROC_THREAD_ATTRIBUTE_ENTRY;
    typedef struct _NT_PROC_THREAD_ATTRIBUTE_LIST 
    {
    //结构总大小
        SIZE_T  Length;       
        PROC_THREAD_ATTRIBUTE_ENTRY Entry[1];
    } NT_PROC_THREAD_ATTRIBUTE_LIST,*PNT_PROC_THREAD_ATTRIBUTE_LIST;


    函数流程概要:
    1、  循环从AttributeList中取出PROC_THREAD_ATTRIBUTE_ENTRY对象。
    2、  根据PROC_THREAD_ATTRIBUTE_ENTRY对象的属性Attribute,判断大小Size是否正确,若正确则将值Value保存到CreateProcessContext相应的成员中。
    函数流程图:

    函数细节:
    1、检查参数,主要检查AttributeList的长度和地址:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    00000001403661CC                 mov     rax, [rbx+_NT_PROC_THREAD_ATTRIBUTE_LIST.Length]
    00000001403661CF                 mov     [rsp+128h+Length], rax
    00000001403661D4                 cmp     rax, 28h
    00000001403661D8                 jb      loc_140366763   ; if(AttributeList.Length<28h)
    00000001403661DE                 cmp     r8b, sil        ; if(PreviousMode==0)
    00000001403661E1                 jz      short loc_14036621A ; 取出AttributeList长度
    00000001403661E3                 add     rax, 0FFFFFFFFFFFFFFD8h
    00000001403661E7                 cmp     rax, rsi
    00000001403661EA                 jz      short loc_14036621A ; if(AttributeList.Length==28h)
    00000001403661EC                 test    r15b, bl
    00000001403661EF                 jnz     loc_14036676D   ; 检查地址是否对齐
    00000001403661F5                 mov     rdx, [rsp+128h+Length]
    00000001403661FA                 add     rdx, rbx
    00000001403661FD                 mov     rcx, cs:MmUserProbeAddress
    0000000140366204                 cmp     rdx, rcx
    0000000140366207                 ja      loc_140366773
    000000014036620D                 lea     rax, [rbx+28h]
    0000000140366211                 cmp     rdx, rax
    0000000140366214                 jb      loc_140366773


    2、循环取出数组元素:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    0000000140366230                 shr     [rsp+128h+Length], 5
    0000000140366236                 add     rbx, 8          ; 第一个元素
    000000014036623A                 mov     [rsp+128h+Entry], rbx
     
    000000014036632F                 add     rbx, 20h        ; +=sizeof(_NT_PROC_THREAD_ATTRIBUTE_ENTRY)
    0000000140366333                 mov     [rsp+128h+Entry], rbx
    0000000140366338                 dec     [rsp+128h+Length] ; AttributeList.Length--;
    000000014036633D                 mov     r8b, [rsp+128h+PreviousMode]
    0000000140366345                 jmp     loc_14036624C


    3、循环中间判断Entry的属性Attribute:
    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
    0000000140366298                 cmp     rax, 60010h     ; if(Attribute>60010h)
    000000014036629E                 ja      loc_140366EE0
    00000001403662A4                 cmp     eax, 2000Bh     ; if(Attribute>2000Bh)
    00000001403662A9                 ja      loc_14036669B
    00000001403662AF                 cmp     eax, 2000Bh     ; if(Attribute==2000Bh)
    00000001403662B4                 jz      loc_1403669C5
    00000001403662BA                 sub     eax, 6          ;  if(Attribute==6)
    00000001403662BD                 jz      loc_140366454
    00000001403662C3                 sub     eax, 0FFFDh     ; if(Attribute!=10003)
    00000001403662C8                 jnz     loc_14036636A
     
    000000014036669B                 sub     eax, 2000Dh
    00000001403666A0                 jz      loc_140366E53   ; if(Attribute==2000Dh)
    00000001403666A6                 sub     eax, 0FFFFh
    00000001403666AB                 jz      loc_140366D6B   ; if(Attribute==3000Ch)
    00000001403666B1                 sub     eax, 2
    00000001403666B4                 jz      loc_140366C8A   ; if(Attribute==3000Eh)
    00000001403666BA                 sub     eax, 1
    00000001403666BD                 jz      loc_140366B44   ; if(Attribute==3000Fh)
    00000001403666C3                 sub     eax, 2FFF1h
    00000001403666C8                 jz      loc_140366B1F   ; if(Attribute==60000h)
    00000001403666CE                 sub     eax, 1
    00000001403666D1                 jz      loc_140366AFA   ;  if(Attribute==60001h)
    00000001403666D7                 sub     eax, 1
    00000001403666DA                 jnz     loc_140366A99   ;  if(Attribute!=60002h)
     
    0000000140366593                 sub     eax, 2
    0000000140366596                 jz      loc_140366861   ; if(Attribute==20007h)
    000000014036659C                 sub     eax, 1
    000000014036659F                 jz      loc_14036670A   ; if(Attribute==20008h)
    00000001403665A5                 sub     eax, 1
    00000001403665A8                 jz      loc_1403667F8   ; if(Attribute==20009h)
    00000001403665AE                 sub     eax, 1
    00000001403665B1                 jnz     loc_140366EE0   ; if(Attribute!=2000Ah)
    000000014036636A                 sub     eax, 1
    000000014036636D                 jz      loc_1403664F1   ;  if(Attribute==10004)
    0000000140366373                 sub     eax, 10001h
    0000000140366378                 jnz     loc_140366593   ;  if(Attribute!=20005)


    4、根据属性Attribute检查值Value大小是否正确:
    1
    2
    3
    4
    5
    6
    7
    8
    000000014036637E                 mov     rdi, [rbx+_NT_PROC_THREAD_ATTRIBUTE_ENTRY.Size]
    0000000140366382                 mov     [rsp+128h+var_D0], rdi
    0000000140366387                 cmp     rdi, rsi
    000000014036638A                 jz      loc_140366961
    0000000140366390                 test    dil, 1
    0000000140366394                 jnz     loc_140366961
    000000014036639A                 cmp     rdi, 0FFFFh
    00000001403663A1                 ja      loc_140366961


    5、将Value保存到CreateProcessContext相应的成员中, ProcessCreateContext中的各成员的内容,由AttributeList中的Attribute的值决定,已经分析出的对应关系如下:


    PspCaptureCreateInfo剖析
    函数原型:
    1
    2
    3
    4
    5
    6
    7
    8
    NTSTATUS NTAPI PspCaptureCreateInfo(
              //访问模式
              IN  BYTE            AccessMode,
              //进程创建信息结构体
              IN  PPROCESS_CREATE_INFO CreateInfo,
        //创建进程上下文
    IN  CreateProcessContext*    pCreateProcessContext
    )


    函数功能:将CreateInfo的0x11(Flags2)偏移处进行运算后赋值给pCreateProcessContext的成员Flag2,将CreateInfo的0x13偏移处(ImageCharacteristics)赋值给pCreateProcessContext的成员ImageCharacteristics,将第二个参数CreateInfo的地址给pCreateProcessContext的成员pCreateInfo。
    函数流程图:


    关键代码实现:
    1
    2
    3
    4
    5
    6
    7
          pCreateProcessContext->UnKown_1 &= 0xFCu;
          pCreateProcessContext->UnKown_1 |= (pCreateInfo->UnKown0 & 3) & 3;
          pCreateProcessContext->DesiredAccess = pCreateInfo->DesiredAccess;
          pCreateProcessContext->Flags2 ^= (pCreateProcessContext->Flags2 ^ 2 * pCreateInfo->Flags2) & 2;
          pCreateProcessContext->Flags2 ^= (pCreateProcessContext->Flags2 ^ 16 * pCreateInfo->Flags2) & 0x20;
          pCreateProcessContext->ImageCharacteristics = pCreateInfo->ImageCharacteristics;
          pCreateProcessContext->pCreateInfo = pCreateInfo;


    PspCaptureProcessParameters剖析
    函数原型:
    1
    2
    3
    4
    5
    6
    7
    8
    NTSTATUS  PspCaptureProcessParameters(
    //访问模式,表明调用来自用户态,还是内核态
    IN  _MODE AccessMode,
    // 此结构体包含了创建进程指定的STARTINFO结构中的信息
    IN  PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    // 传入传出结构体指针, 存放进程创建过程中一些句柄 内核对象
    IN OUT PCREATEPROCESSCONTEXT  pCreateProcessContext
    );

    函数功能:
    检查ProcessParameters参数中的unicode字符串是否为有效的,并且申请新的内存将字符串复制到申请的空间中,把新申请的内存地址保存在pCreateProcessContext->pProcessParamers中后返回。
    主要流程: 
    判断accessMode是userMode还是kernelMode
    若为kernelMode则设置Flags2为0FBh,且pCreateProcessContext->pProcessParamers = ProcessParameters 赋值完成后直接返回,函数结束。
    若为userMode则先检查ProcessParameters参数中的unicode字符串是否有效,之后计算空间大小,申请新内存,将参数的unicode保存到新内存中,最后将内存地址赋值给pCreateProcessContext->pProcessParamers,函数结束。
    流程图:

    细节:
    1、  判断accessMode是userMode还是kernelMode。
    1
    2
    000000014031F83C                 cmp     cl, bl          ; if (accessMode != KernelMode)
    000000014031F83E                 jz      loc_1403C9EF2


    2、  若是kernelMode跳走,并且直接给pCreateProcessContext->Flags2和pCreateProcessContext->pProcessParameters赋值,完成后函数退出
    1
    2
    00000001403C9EF2                 and     [r8+CreateProcessContext.Flags2], 0FBh
    00000001403C9EF7                 mov     [r8+CreateProcessContext.PRTL_USER_PROCESS_PARAMETERS], rdx  //参数2直接给CreateProcessContext->PRTL_USER_PROCESS_PARAMETERS


    3、  若是UserMode 则先用PspCaptureAndValidateUnicodeString检测字符串有效性并获取字符串的unicode_string结构,保存在局部变量中
    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
    000000014031F8F1                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.CurrentDirectory] ; src
    000000014031F8F6                 lea     rdx, [rsp+118h+CurrentDirectory] ; dst
    000000014031F8FB                 call    PspCaptureAndValidateUnicodeString
    000000014031F900                 cmp     eax, ebx
    000000014031F902                 jl      loc_14031FC9F
    000000014031F908                 mov     eax, 208h
    000000014031F90D                 cmp     [rsp+118h+CurrentDirectory.Length], ax
    000000014031F912                 jnb     loc_1403C9F3E
    000000014031F918                 mov     [rsp+118h+CurrentDirectory.MaximumLength], ax
    000000014031F91D                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.DllPath]
    000000014031F922                 lea     rdx, [rsp+118h+dllPath]
    000000014031F927                 call    PspCaptureAndValidateUnicodeString
    000000014031F92C                 cmp     eax, ebx
    000000014031F92E                 jl      loc_14031FC9F
    000000014031F934
    000000014031F934 loc_14031F934:                          ; CODE XREF: PspCaptureProcessParameters+AA721j
    000000014031F934                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.ImagePathName]
    000000014031F939                 lea     rdx, [rsp+118h+ImagePathName]
    000000014031F941                 call    PspCaptureAndValidateUnicodeString
    000000014031F946                 cmp     eax, ebx
    000000014031F948                 jl      loc_14031FC9F
    000000014031F94E                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.CommandLine]
    000000014031F953                 lea     rdx, [rsp+118h+CommandLine]
    000000014031F95B                 call    PspCaptureAndValidateUnicodeString
    000000014031F960                 cmp     eax, ebx
    000000014031F962                 jl      loc_14031FC9F
    000000014031F968                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.WindowTitle]
    000000014031F970                 lea     rdx, [rsp+118h+WindowTitle]
    000000014031F978                 call    PspCaptureAndValidateUnicodeString
    000000014031F97D                 cmp     eax, ebx
    000000014031F97F                 jl      loc_14031FC9F
    000000014031F985                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.DesktopInfo]
    000000014031F98D                 lea     rdx, [rsp+118h+DesktopInfo]
    000000014031F995                 call    PspCaptureAndValidateUnicodeString
    000000014031F99A                 cmp     eax, ebx
    000000014031F99C                 jl      loc_14031FC9F
    000000014031F9A2                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.ShellInfo]
    000000014031F9AA                 lea     rdx, [rsp+118h+ShellInfo]
    000000014031F9B2                 call    PspCaptureAndValidateUnicodeString


    4、  之后计算空间,调用ExAllocatePoolWithQuotaTag申请内存
    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
    000000014031F9E4                 mov     r15, [rsp+118h+RuntimeData.Buffer]
    000000014031F9E9                 cmp     r15, rbx
    000000014031F9EC                 jnz     loc_1403C9F70
    000000014031F9F2                 movzx   r14d, [rsp+118h+RuntimeData.Length]
    000000014031F9F8                 cmp     r14w, bx
    000000014031F9FC                 jnz     loc_1403C9F66
    000000014031FA02                 mov     [rsp+118h+RuntimeData.MaximumLength], bx
    000000014031FA07
    000000014031FA07 loc_14031FA07:                          ; CODE XREF: PspCaptureProcessParameters+AA749j
    000000014031FA07                                         ; PspCaptureProcessParameters+AA7ABj
    000000014031FA07                 movzx   ecx, [rsp+118h+var_4E]
    000000014031FA0F                 movzx   eax, [rsp+118h+var_6E]
    000000014031FA17                 add     rcx, rax
    000000014031FA1A                 movzx   eax, [rsp+118h+var_7E]
    000000014031FA22                 add     rcx, rax
    000000014031FA25                 movzx   eax, [rsp+118h+var_5E]
    000000014031FA2D                 add     rcx, rax
    000000014031FA30                 movzx   eax, [rsp+118h+var_8E]
    000000014031FA38                 add     rcx, rax
    000000014031FA3B                 movzx   eax, [rsp+118h+dllPath.MaximumLength]
    000000014031FA40                 add     rcx, rax
    000000014031FA43                 movzx   eax, [rsp+118h+RuntimeData.MaximumLength]
    000000014031FA48                 add     rcx, rax
    000000014031FA4B                 movzx   eax, [rsp+118h+CurrentDirectory.MaximumLength]
    000000014031FA50                 lea     rcx, [rcx+rax+401h]
    000000014031FA58                 and     rcx, 0FFFFFFFFFFFFFFFEh
    000000014031FA5C                 mov     [rsp+118h+var_C8], rcx
    000000014031FA61                 mov     [rsp+118h+var_B0], rcx
    000000014031FA66                 mov     rax, [rsp+118h+EnvironmentSize]
    000000014031FA6B                 lea     rdx, [rcx+rax]  ; NumberOfBytes
    000000014031FA6F                 cmp     rdx, rcx
    000000014031FA72                 jb      loc_1403C9FD1
    000000014031FA78                 mov     [rsp+118h+var_A8], rdx
    000000014031FA7D                 mov     esi, ebx


    5、  通过PspCopyUnicodeString拷贝参数里的字符串到申请的空间中
    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
    000000014031FB09                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.CurrentDirectory]
    000000014031FB0D                 lea     r8, [rsp+118h+Dst]
    000000014031FB15                 lea     rcx, [rsp+118h+CurrentDirectory] ; src
    000000014031FB1A                 call    PspCopyUnicodeString
    000000014031FB1F                 mov     esi, eax
    000000014031FB21                 cmp     eax, ebx
    000000014031FB23                 jl      loc_1403CA0AC
    000000014031FB29                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.DllPath]
    000000014031FB2D                 lea     r8, [rsp+118h+Dst]
    000000014031FB35                 lea     rcx, [rsp+118h+dllPath]
    000000014031FB3A                 call    PspCopyUnicodeString
    000000014031FB3F                 mov     esi, eax
    000000014031FB41                 cmp     eax, ebx
    000000014031FB43                 jl      loc_1403CA0AC
    000000014031FB49                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.ImagePathName]
    000000014031FB4D                 lea     r8, [rsp+118h+Dst]
    000000014031FB55                 lea     rcx, [rsp+118h+ImagePathName]
    000000014031FB5D                 call    PspCopyUnicodeString
    000000014031FB62                 mov     esi, eax
    000000014031FB64                 cmp     eax, ebx
    000000014031FB66                 jl      loc_1403CA0AC
    000000014031FB6C                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.CommandLine]
    000000014031FB70                 lea     r8, [rsp+118h+Dst]
    000000014031FB78                 lea     rcx, [rsp+118h+CommandLine]
    000000014031FB80                 call    PspCopyUnicodeString
    000000014031FB85                 mov     esi, eax
    000000014031FB87                 cmp     eax, ebx
    000000014031FB89                 jl      loc_1403CA0AC
    000000014031FB8F                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.WindowTitle]
    000000014031FB96                 lea     r8, [rsp+118h+Dst]
    000000014031FB9E                 lea     rcx, [rsp+118h+WindowTitle]
    000000014031FBA6                 call    PspCopyUnicodeString
    000000014031FBAB                 mov     esi, eax
    000000014031FBAD                 cmp     eax, ebx
    000000014031FBAF                 jl      loc_1403CA0AC
    000000014031FBB5                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.DesktopInfo]
    000000014031FBBC                 lea     r8, [rsp+118h+Dst]
    000000014031FBC4                 lea     rcx, [rsp+118h+DesktopInfo]
    000000014031FBCC                 call    PspCopyUnicodeString
    000000014031FBD1                 mov     esi, eax
    000000014031FBD3                 cmp     eax, ebx
    000000014031FBD5                 jl      loc_1403CA0AC
    000000014031FBDB                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.ShellInfo] ; Src
    000000014031FBE2                 lea     r8, [rsp+118h+Dst] ; Dst
    000000014031FBEA                 lea     rcx, [rsp+118h+ShellInfo] ; Size
    000000014031FBF2                 call    PspCopyUnicodeString


    6、最后设置Flages2和pProcessParameters并退出
    1
    2
    3
    4
    5
    6
    7
    000000014031FC91                 or      [r13+CreateProcessContext.Flags2], 4
    000000014031FC96                 mov     [r13+CreateProcessContext.PRTL_USER_PROCESS_PARAMETERS], rdi
    000000014031FC9D                 xor     eax, eax
    000000014031FC9F                 add     rsp, 0E0h
    000000014031FCA6                 pop     r15
    000000014031FCA8                 pop     r14
    000000014031FCAA                 pop     r13


  • 相关阅读:
    每天OnLineJudge 之 “蛇形矩阵 ”
    Hello World 发生了什么?
    软件开发人员真的了解SQL索引吗(索引使用原则)
    软件开发人员真的了解SQL索引吗(聚集索引)
    项目经验总结(一)如何约定接口的定义
    min的个人网站终于创建起来了
    WCF单例服务,如何实现并发
    如何规范.net中的js开发(2)原理篇(更新版)
    网站架构之缓存应用(3)实现篇
    网站架构之缓存应用(1)概念篇
  • 原文地址:https://www.cnblogs.com/kuangke/p/11133720.html
Copyright © 2011-2022 走看看