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_ALLOWEDIN 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, //传出一些基本信息, 比如新进程的PEBOUT  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 ; ThreadDesiredAccess000000014031D74A                 mov     [rsp+0B28h+var_ProcessDesiredAccess], r8d ; ProcessDesiredAccess000000014031D74F                 mov     [rsp+0B28h+var_ThreadHandle], rdx ; ThreadHandle000000014031D757                 mov     [rsp+0B28h+var_ProcessHandle], rcx ; ProcessHandle000000014031D75F                 mov     rsi, [rsp+0B28h+ProcessObjectAttributes] ; ProcessObjectAttributes000000014031D767                 mov     [rsp+0B28h+var_ProcessObjectAttributes], rsi000000014031D76F                 mov     rax, [rsp+0B28h+ThreadObjectAttributes] ; ThreadObjectAttributes000000014031D777                 mov     [rsp+0B28h+var_ThreadObjectAttributes], rax ; ThreadFlags000000014031D77F                 mov     rax, [rsp+0B28h+ProcessParameters] ; ProcessParameters000000014031D787                 mov     [rsp+0B28h+var_ProcessParameters], rax000000014031D78F                 mov     r12, [rsp+0B28h+CreateInfo] ; CreateInfo000000014031D797                 mov     rdi, [rsp+0B28h+AttributeList] ; AttributeList000000014031D79F                 xor     ebx, ebx000000014031D7A1                 mov     [rsp+130h], rbx000000014031D7A9                 xor     edx, edx        ; Val000000014031D7AB                 lea     r8d, [rbx+38h]  ; Size000000014031D7AF                 lea     rcx, [rsp+0B28h+Dst] ; Dst000000014031D7B7                 call    memset000000014031D7BC                 mov     [rsp+0B28h+var_Context.P1Home], rbx000000014031D7C4                 xor     edx, edx        ; Val000000014031D7C6                 mov     r8d, 4C8h       ; Size000000014031D7CC                 lea     rcx, [rsp+0B28h+var_Context.P2Home] ; Dst000000014031D7D4                 call    memset          ; memset(&Context.P2Home,0,sizeof(Context) - 4);000000014031D7D9                 mov     r14, gs:188h000000014031D7E2                 mov     [rsp+0B28h+var_Ethread], r14000000014031D7EA                 mov     r15, [r14+_ETHREAD.Tcb.ApcState.ApcState.Process]000000014031D7EE                 mov     [rsp+0B28h+var_TempProcess], r15000000014031D7F3                 mov     r13b, [r14+_ETHREAD.Tcb.PreviousMode]000000014031D7FA                 mov     [rsp+0B28h+var_PreviousMode], r13b000000014031D7FF                 mov     edx, dword ptr [rsp+0B28h+CreateProcessFlags] ; ProcessFlags | 
以及:
初始化var_CreateProcessContext(见上文的结构体介绍)为0。
| 1 2 3 4 | 000000014031D8E1                 xor     edx, edx        ; Val000000014031D8E3                 mov     r8d, 150h       ; Size000000014031D8E9                 lea     rcx, [rsp+0B28h+var_CreateProcessContext] ; Dst000000014031D8F1                 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=0000000014031D906                 mov     dl, r13b        ; 参数PreviousMode000000014031D909                 mov     rcx, rdi        ; 参数AttributeList000000014031D90C                 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] ; 参数pCreateProcessContext000000014031D940                 mov     rdx, r12        ; 参数pCreateInfo000000014031D943                 mov     cl, r13b        ; 参数AccessMode000000014031D946                 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, 1000000014031D962                 testr12b, cl000000014031D965                 jz      short loc_14031D9C8 ; if(CreateProcessContext.Flags&1)000000014031D965                                         ;          ParentEProcess=CurrentProcess000000014031D965                                         ; 如果CreateProcessContext.Flags&1为真,则父进程为当前进程000000014031D965                                         ; 否则父进程为参数AttributeList中指定的进程000000014031D967                 mov     [rsp+28h], rbx  ; 参数HandleInformation000000014031D96C                 lea     rax, [rsp+0B28h+var_Eprocess]000000014031D974                 mov     [rsp+20h], rax  ; 参数pEprocess000000014031D979                 mov     r9b, r13b       ; 参数AccessMode000000014031D97C                 mov     r8, cs:PsProcessType ; 参数ObjectType000000014031D983                 lea     edx, [r12+7Fh]  ; 参数DesiredAccess000000014031D988                 mov     rcx, [rsp+0B28h+var_CreateProcessContext.hParentProcess] ; Handle000000014031D990                 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], 30h000000014031DA23                 mov     [rsp+0B28h+var_ObjectAttributes.RootDirectory], rbx000000014031DA2B                 or      eax, 240h000000014031DA30                 mov     [rsp+0B28h+var_ObjectAttributes.Attributes], eax000000014031DA37                 lea     rax, [rsp+0B28h+var_CreateProcessContext.FileName]000000014031DA3F                 mov     [rsp+0B28h+var_ObjectAttributes.ObjectName], rax000000014031DA47                 mov     [rsp+0B28h+var_ObjectAttributes.SecurityDescriptor], rbx000000014031DA4F                 mov     [rsp+0B28h+var_ObjectAttributes.SecurityQualityOfService], rbx000000014031DA57                 mov     edx, [rsp+0B28h+var_CreateProcessContext.DesiredAccess]000000014031DA5E                 or      edx, 100020h    ; 参数DesiredAccess000000014031DA64                 mov     dword ptr [rsp+28h], 60h ; 参数OpenOptions000000014031DA6C                 mov     dword ptr [rsp+20h], 5 ; 参数ShareAccess000000014031DA74                 lea     r9, [rsp+0B28h+var_IoStatusBlock] ; 参数IoStatusBlock000000014031DA7C                 lea     r8, [rsp+0B28h+var_ObjectAttributes] ; 参数ObjectAttributes000000014031DA84                 lea     rcx, [rsp+0B28h+var_CreateProcessContext.FileHandle] ; 参数FileHandle000000014031DA8C                 call    ZwOpenFile      ; ZwOpenFile(CreateProcessContext.FileHandle,000000014031DA8C                                         ;     DesiredAccess,000000014031DA8C                                         ;     ObjectAttributes,000000014031DA8C                                         ;     IoStatusBlock,000000014031DA8C                                         ;     ShareAccess,000000014031DA8C                                         ;     OpenOptions);000000014031DA91                 mov     edi, eax000000014031DA93                 cmpeax, ebx000000014031DA95                 jge     short loc_14031DAD4000000014031DA97                 cmp[rsp+0B28h+var_CreateProcessContext.DesiredAccess], ebx000000014031DA9E                 jz      short loc_14031DAD4000000014031DAA0                 mov     dword ptr [rsp+28h], 60h ; 参数OpenOptions000000014031DAA8                 mov     dword ptr [rsp+20h], 5 ; 参数ShareAccess000000014031DAB0                 lea     r9, [rsp+0B28h+var_IoStatusBlock] ; 参数IoStatusBlock000000014031DAB8                 lea     r8, [rsp+0B28h+var_ObjectAttributes] ; 参数ObjectAttributes000000014031DAC0                 mov     edx, 100020h    ; 参数DesiredAccess000000014031DAC5                 lea     rcx, [rsp+0B28h+var_CreateProcessContext.FileHandle] ; 参数FileHandle000000014031DACD                 call    ZwOpenFile      ; ZwOpenFile(CreateProcessContext.FileHandle,000000014031DACD                                         ;     DesiredAccess,000000014031DACD                                         ;     ObjectAttributes,000000014031DACD                                         ;     IoStatusBlock,000000014031DACD                                         ;     ShareAccess,000000014031DACD                                         ;     OpenOptions);000000014031DAD2                 mov     edi, eax000000014031DAD4000000014031DAD4 loc_14031DAD4:                          ; CODE XREF: NtCreateUserProcess+375j000000014031DAD4                                         ; NtCreateUserProcess+37Ej000000014031DAD4                 cmpedi, ebx000000014031DAD6                 jge     short loc_14031DAF8000000014031DAD8                 mov     [rsp+0B28h+var_CreateProcessContext.FileHandle], rbx000000014031DAE0                 xor     r8d, r8d000000014031DAE3                 lea     rdx, [rsp+0B28h+var_CreateProcessContext]000000014031DAEB                 mov     ecx, r12d000000014031DAEE                 call    PspUpdateCreateInfo000000014031DAF3                 jmp     loc_14031E1D8   ; 打开文件失败000000014031DAF8 ; ---------------------------------------------------------------------------000000014031DAF8000000014031DAF8 loc_14031DAF8:                          ; CODE XREF: NtCreateUserProcess+3B6j000000014031DAF8                 mov     [rsp+0B28h+var_B00], rbx ; 参数HandleInformation000000014031DAFD                 lea     rax, [rsp+0B28h+var_File]000000014031DB05                 mov     [rsp+20h], rax  ; 参数pFile000000014031DB0A                 xor     r9d, r9d        ; 参数AccessMode000000014031DB0D                 mov     r8, cs:IoFileObjectType ; 参数ObjectType000000014031DB14                 mov     edx, 100020h    ; 参数DesiredAccess000000014031DB19                 mov     rcx, [rsp+0B28h+var_CreateProcessContext.FileHandle] ; 参数Handle000000014031DB21                 call    ObReferenceObjectByHandle ;000000014031DB21                                         ; ObReferenceObjectByHandle(000000014031DB21                                         ;     CreateProcessContext.FileHandle,000000014031DB21                                         ;     DesiredAccess,000000014031DB21                                         ;     IoFileObjectType,000000014031DB21                                         ;     AccessMode,000000014031DB21                                         ;     pFile,000000014031DB21                                         ;     HandleInformation);000000014031DB26                 mov     edi, eax000000014031DB28                 mov     rax, [rsp+0B28h+var_File]000000014031DB30                 mov     [rsp+0B28h+var_CreateProcessContext.FileObject], rax000000014031DB38                 cmpedi, ebx000000014031DB3A                 jge     short loc_14031DB49000000014031DB3C                 mov     [rsp+0B28h+var_CreateProcessContext.FileObject], rbx000000014031DB44                 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  ; 参数FileHandle000000014031DB6D                 mov     [rsp+28h], ecx  ; 参数AllocationAttributes000000014031DB71                 mov     dword ptr [rsp+20h], 10h ; 参数SectionPageProtection000000014031DB79                 xor     r9d, r9d        ; 参数MaximumSize000000014031DB7C                 lea     r8, [rsp+0B28h+var_ObjectAttributes] ; 参数ObjectAttributes000000014031DB84                 mov     edx, 0F001Fh    ; 参数DesiredAccess000000014031DB89                 lea     rcx, [rsp+0B28h+var_CreateProcessContext.SectionHandle] ; 参数SectionHandle000000014031DB91                 call    ZwCreateSection ; ZwCreateSection(SectionHandle,000000014031DB91                                         ;     DesiredAccess,000000014031DB91                                         ;     ObjectAttributes,000000014031DB91                                         ;     MaximumSize,000000014031DB91                                         ;     SectionPageProtection,000000014031DB91                                         ;     AllocationAttributes,000000014031DB91                                         ;     CreateProcessContext.FileHandle);000000014031DBBD                 mov     [rsp+28h], rbx  ; 参数HandleInformation000000014031DBC2                 lea     rax, [rsp+0B28h+var_SectionObject]000000014031DBCA                 mov     [rsp+20h], rax  ; 参数SectionObject000000014031DBCF                 xor     r9d, r9d        ; 参数AccessMode000000014031DBD2                 mov     r8, cs:MmSectionObjectType ; 参数ObjectType000000014031DBD9                 lea     edx, [r9+8]     ; 参数DesiredAccess000000014031DBDD                 mov     rcx, [rsp+0B28h+var_CreateProcessContext.SectionHandle] ; 参数Handle000000014031DBE5                 call    ObReferenceObjectByHandle ;000000014031DBE5                                         ; ObReferenceObjectByHandle(000000014031DBE5                                         ;     CreateProcessContext.SectionHandle,000000014031DBE5                                         ;     DesiredAccess,000000014031DBE5                                         ;     MmSectionObjectType,000000014031DBE5                                         ;     AccessMode,000000014031DBE5                                         ;     pSectionObject,000000014031DBE5                                         ;     HandleInformation);000000014031DBEA                 mov     edi, eax000000014031DBEC                 mov     rax, [rsp+0B28h+var_SectionObject]000000014031DBF4                 mov     [rsp+0B28h+var_CreateProcessContext.SectionObject], rax000000014031DBFC                 cmpedi, ebx000000014031DBFE                 jge     short loc_14031DC0D000000014031DC00                 mov     [rsp+0B28h+var_CreateProcessContext.SectionObject], rbx000000014031DC08                 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                 cmprax, rbx000000014031DC28                 jz      short loc_14031DC7E ; if(CreateProcessContext.SectionObject==NULL)000000014031DC2A                 bt      [r15+_EPROCESS.Flags2], 0Bh000000014031DC33                 jb      short loc_14031DC46 ; 参数pCreateProcessContext000000014031DC35                 cmpesi, ebx000000014031DC37                 jz      short loc_14031DC46 ; 参数pCreateProcessContext000000014031DC39                 cmpr13b, bl000000014031DC3C                 jz      short loc_14031DC46 ; 参数pCreateProcessContext000000014031DC3E                 or      [rsp+0B28h+var_CreateProcessContext.Flags2], 10h000000014031DC46000000014031DC46 loc_14031DC46:                          ; CODE XREF: NtCreateUserProcess+513j000000014031DC46                                         ; NtCreateUserProcess+517j000000014031DC46                                         ; NtCreateUserProcess+51Cj000000014031DC46                 lea     r8, [rsp+0B28h+var_CreateProcessContext] ; 参数pCreateProcessContext000000014031DC4E                 mov     rdx, [rsp+0B28h+var_ProcessParameters] ; 参数ProcessParameters000000014031DC56                 mov     cl, r13b        ; 参数PreviousMode000000014031DC59                 call    PspCaptureProcessParameters ; //初始化pRtlUserProcessParameter000000014031DC59                                         ; PspCaptureProcessParameters(000000014031DC59                                         ;     PreviousMode,000000014031DC59                                         ;     ProcessParameters,000000014031DC59                                         ;     pCreateProcessContext);000000014031DC5E                 mov     edi, eax000000014031DC60                 cmpeax, ebx000000014031DC62                 jge     short loc_14031DC71000000014031DC64                 and     [rsp+0B28h+var_CreateProcessContext.Flags2], 0FBh000000014031DC6C                 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] ; 参数pNewProcess000000014031DD2C                 mov     [rsp+40h], rax000000014031DD31                 lea     rax, [rsp+0B28h+var_AA0] ; 参数Unkown000000014031DD39                 mov     [rsp+38h], rax000000014031DD3E                 lea     rax, [rsp+0B28h+var_CreateProcessContext] ; 参数CreateProcessContext000000014031DD46                 mov     [rsp+30h], rax000000014031DD4B                 mov     eax, dword ptr [rsp+0B28h+CreateProcessFlags] ; 参数ProcessFlags000000014031DD52                 mov     [rsp+28h], eax000000014031DD56                 mov     rax, [rsp+0B28h+var_CreateProcessContext.hSeTokenObject] ; 参数hSeTokenObject000000014031DD5E                 mov     [rsp+20h], rax000000014031DD63                 mov     r9, [rsp+0B28h+var_CreateProcessContext.SectionObject] ; 参数SectionObject000000014031DD6B                 mov     r8, [rsp+0B28h+var_ProcessObjectAttributes] ; 参数ProcessObjectAttributes000000014031DD73                 mov     dl, r13b        ; 参数PreviousMode000000014031DD76                 mov     rcx, qword ptr [rsp+0B28h+var_pProcess] ; 参数ParentEProcess000000014031DD7E                 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], 10001Bh000000014031DCF3                 mov     [rsp+20h], r12b ; 参数dwOne=1000000014031DCF8                 mov     r9b, r12b       ; 参数isSystemThread=1000000014031DCFB                 xor     r8d, r8d        ; 参数AccessMode=0000000014031DCFE                 lea     rdx, [rsp+0B28h+var_Context] ; 参数pContext000000014031DD06                 mov     rcx, r14        ; 参数Ethread000000014031DD09                 call    PspGetContextThreadInternal ;000000014031DD09                                         ; PspGetContextThreadInternal(000000014031DD09                                         ;     Ethread,000000014031DD09                                         ;     pContext,000000014031DD09                                         ;     AccessMode,000000014031DD09                                         ;     isSystemThread,000000014031DD09                                         ;     dwOne);000000014031DE77                 mov     [rsp+0B28h+var_AccessStateExpand], eax000000014031DE7B                 lea     rax, [rsp+0B28h+var_AccessState2]000000014031DE83                 mov     [rsp+58h], rax  ; 参数pNewAccessState000000014031DE88                 mov     [rsp+50h], r14  ; 参数unknow000000014031DE8D                 lea     rax, [rsp+0B28h+var_pThread]000000014031DE95                 mov     [rsp+48h], rax  ; 参数pptrEthread000000014031DE9A                 lea     rax, [rsp+6Ch]  ; 参数pProcessFlag000000014031DE9F                 mov     [rsp+40h], rax  ; __int64000000014031DEA4                 mov     [rsp+38h], rbx  ; 参数StartContext000000014031DEA9                 mov     [rsp+30h], rbx  ; 参数StartRoutine000000014031DEAE                 lea     rax, [rsp+0B28h+var_Inital_teb] ; 参数pInitTeb000000014031DEB6                 mov     [rsp+28h], rax  ; __int64000000014031DEBB                 lea     rax, [rsp+0B28h+var_Context]000000014031DEC3                 mov     [rsp+20h], rax  ; 参数Context000000014031DEC8                 lea     r9, [rsp+0B28h+var_CreateProcessContext] ; __int64000000014031DED0                 mov     r8b, r13b       ; 参数AccessMode000000014031DED3                 mov     rdx, [rsp+0B28h+var_ThreadObjectAttributes] ; __int64000000014031DEDB                 mov     rcx, rsi        ; 参数newProcess000000014031DEDE                 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  ; 参数AccessState000000014031DFD5                 mov     [rsp+38h], rax  ; 参数enumType000000014031DFDA                 mov     [rsp+30h], r15d ; 参数unKnownFlag000000014031DFDF                 mov     rax, [rsp+0B28h+var_CreateProcessContext.DebugObjectHandle]000000014031DFE7                 mov     [rsp+28h], rax  ; 参数DebugObjectHandle000000014031DFEC                 mov     [rsp+20h], ebx  ; 参数JobMemberLevel000000014031DFF0                 mov     r9d, dword ptr [rsp+0B28h+CreateProcessFlags] ; 参数ProcessFlags000000014031DFF8                 mov     r8d, ecx        ; 参数ProcessDesiredAccess000000014031DFFB                 mov     rdx, qword ptr [rsp+0B28h+var_pProcess] ; 参数ParentEProcess000000014031E003                 mov     rcx, rsi        ; 参数Eprocess000000014031E006                 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        ; 参数Eprocess000000014031E0A3                 call    PspDoHandleSweepSingle ; PspDoHandleSweepSingle(Eprocess);000000014031E0A8                 mov     edi, r13d000000014031E0AB                 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_ID000000014031E01B                 mov     rax, [rsp+0B28h+var_ThreadHandle]000000014031E023                 mov     [rsp+48h], rax  ; 参数pThreadHandle000000014031E028                 mov     [rsp+40h], rbx  ; 参数000000014031E02D                 lea     rax, [rsp+0B28h+var_AccessState2]000000014031E035                 mov     [rsp+38h], rax  ; 参数NewAccessState000000014031E03A                 lea     rax, [rsp+0B28h+var_CreateProcessContext]000000014031E042                 mov     [rsp+30h], rax  ; 参数pCreateProcessContext000000014031E047                 mov     [rsp+28h], r14  ; 参数000000014031E04C                 mov     dword ptr [rsp+0B28h+var_B08], edi000000014031E050                 lea     r9, [rsp+0B28h+var_AccessStateExpand] ; 参数pProcessFlag000000014031E055                 lea     r8, [rsp+0B28h+var_Inital_teb] ; 参数pInital_teb000000014031E05D                 mov     rdx, rsi        ; 参数pEprocess000000014031E060                 mov     r14, [rsp+0B28h+var_pThread] ; 参数pThread000000014031E068                 mov     rcx, r14000000014031E06B                 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] ; 参数AccessState000000014031E1AE                 call    SeDeleteAccessState ; SeDeleteAccessState(pAccessState);000000014031E1B3                 cmpedi, ebx000000014031E1B5                 jge     short loc_14031E1C1000000014031E1B7                 mov     edx, edi        ; 参数ExitStatus000000014031E1B9                 mov     rcx, rsi        ; 参数NewProcess000000014031E1BC                 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], r12w000000014031E082                 jnz     short loc_14031E09B000000014031E084                 lea     rax, [rcx+_ETHREAD.Tcb.ApcState]000000014031E088                 cmp[rax], rax000000014031E08B                 jz      short loc_14031E09B000000014031E08D                 cmp[rcx+_ETHREAD.Tcb.___u22.__s5.SpecialApcDisable], bx000000014031E094                 jnz     short loc_14031E09B000000014031E096                 call    KiCheckForKernelApcDelivery | 
接着,就是一些检查、释放资源类的扫尾工作了

总之,若一切顺利,会调用PspUpdateCreateInfo将进程创建信息保存到传出参数CreateInfo中:
| 1 2 3 4 5 6 7 | 000000014031E131                 mov     r8, rsi         ; 参数Eprocess000000014031E134                 lea     rdx, [rsp+0B28h+var_CreateProcessContext] ; 参数pCreateProcessContext000000014031E13C                 mov     ecx, 6          ; 参数000000014031E141                 call    PspUpdateCreateInfo ; PspUpdateCreateInfo(000000014031E141                                         ;         dwEmCode,000000014031E141                                         ;         pCreateProcessContext,000000014031E141                                         ;         Eprocess); | 
若不顺利,会调用PspDoHandleSweepSingle或者PsTerminateProcess结束新进程:
| 1 2 3 4 5 | 000000014031E1B7                 mov     edx, edi        ; 参数ExitStatus000000014031E1B9                 mov     rcx, rsi        ; 参数NewProcess000000014031E1BC                 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], rax00000001403661D4                 cmprax, 28h00000001403661D8                 jb      loc_140366763   ; if(AttributeList.Length<28h)00000001403661DE                 cmpr8b, sil        ; if(PreviousMode==0)00000001403661E1                 jz      short loc_14036621A ; 取出AttributeList长度00000001403661E3                 add     rax, 0FFFFFFFFFFFFFFD8h00000001403661E7                 cmprax, rsi00000001403661EA                 jz      short loc_14036621A ; if(AttributeList.Length==28h)00000001403661EC                 testr15b, bl00000001403661EF                 jnz     loc_14036676D   ; 检查地址是否对齐00000001403661F5                 mov     rdx, [rsp+128h+Length]00000001403661FA                 add     rdx, rbx00000001403661FD                 mov     rcx, cs:MmUserProbeAddress0000000140366204                 cmprdx, rcx0000000140366207                 ja      loc_140366773000000014036620D                 lea     rax, [rbx+28h]0000000140366211                 cmprdx, rax0000000140366214                 jb      loc_140366773 | 
2、循环取出数组元素:
| 1 2 3 4 5 6 7 8 9 | 0000000140366230                 shr     [rsp+128h+Length], 50000000140366236                 add     rbx, 8          ; 第一个元素000000014036623A                 mov     [rsp+128h+Entry], rbx000000014036632F                 add     rbx, 20h        ; +=sizeof(_NT_PROC_THREAD_ATTRIBUTE_ENTRY)0000000140366333                 mov     [rsp+128h+Entry], rbx0000000140366338                 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                 cmprax, 60010h     ; if(Attribute>60010h)000000014036629E                 ja      loc_140366EE000000001403662A4                 cmpeax, 2000Bh     ; if(Attribute>2000Bh)00000001403662A9                 ja      loc_14036669B00000001403662AF                 cmpeax, 2000Bh     ; if(Attribute==2000Bh)00000001403662B4                 jz      loc_1403669C500000001403662BA                 sub     eax, 6          ;  if(Attribute==6)00000001403662BD                 jz      loc_14036645400000001403662C3                 sub     eax, 0FFFDh     ; if(Attribute!=10003)00000001403662C8                 jnz     loc_14036636A000000014036669B                 sub     eax, 2000Dh00000001403666A0                 jz      loc_140366E53   ; if(Attribute==2000Dh)00000001403666A6                 sub     eax, 0FFFFh00000001403666AB                 jz      loc_140366D6B   ; if(Attribute==3000Ch)00000001403666B1                 sub     eax, 200000001403666B4                 jz      loc_140366C8A   ; if(Attribute==3000Eh)00000001403666BA                 sub     eax, 100000001403666BD                 jz      loc_140366B44   ; if(Attribute==3000Fh)00000001403666C3                 sub     eax, 2FFF1h00000001403666C8                 jz      loc_140366B1F   ; if(Attribute==60000h)00000001403666CE                 sub     eax, 100000001403666D1                 jz      loc_140366AFA   ;  if(Attribute==60001h)00000001403666D7                 sub     eax, 100000001403666DA                 jnz     loc_140366A99   ;  if(Attribute!=60002h)0000000140366593                 sub     eax, 20000000140366596                 jz      loc_140366861   ; if(Attribute==20007h)000000014036659C                 sub     eax, 1000000014036659F                 jz      loc_14036670A   ; if(Attribute==20008h)00000001403665A5                 sub     eax, 100000001403665A8                 jz      loc_1403667F8   ; if(Attribute==20009h)00000001403665AE                 sub     eax, 100000001403665B1                 jnz     loc_140366EE0   ; if(Attribute!=2000Ah)000000014036636A                 sub     eax, 1000000014036636D                 jz      loc_1403664F1   ;  if(Attribute==10004)0000000140366373                 sub     eax, 10001h0000000140366378                 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], rdi0000000140366387                 cmprdi, rsi000000014036638A                 jz      loc_1403669610000000140366390                 testdil, 10000000140366394                 jnz     loc_140366961000000014036639A                 cmprdi, 0FFFFh00000001403663A1                 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                 cmpcl, bl          ; if(accessMode != KernelMode)000000014031F83E                 jz      loc_1403C9EF2 | 
2、 若是kernelMode跳走,并且直接给pCreateProcessContext->Flags2和pCreateProcessContext->pProcessParameters赋值,完成后函数退出
| 1 2 | 00000001403C9EF2                 and     [r8+CreateProcessContext.Flags2], 0FBh00000001403C9EF7                 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] ; src000000014031F8F6                 lea     rdx, [rsp+118h+CurrentDirectory] ; dst000000014031F8FB                 call    PspCaptureAndValidateUnicodeString000000014031F900                 cmpeax, ebx000000014031F902                 jl      loc_14031FC9F000000014031F908                 mov     eax, 208h000000014031F90D                 cmp[rsp+118h+CurrentDirectory.Length], ax000000014031F912                 jnb     loc_1403C9F3E000000014031F918                 mov     [rsp+118h+CurrentDirectory.MaximumLength], ax000000014031F91D                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.DllPath]000000014031F922                 lea     rdx, [rsp+118h+dllPath]000000014031F927                 call    PspCaptureAndValidateUnicodeString000000014031F92C                 cmpeax, ebx000000014031F92E                 jl      loc_14031FC9F000000014031F934000000014031F934 loc_14031F934:                          ; CODE XREF: PspCaptureProcessParameters+AA721j000000014031F934                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.ImagePathName]000000014031F939                 lea     rdx, [rsp+118h+ImagePathName]000000014031F941                 call    PspCaptureAndValidateUnicodeString000000014031F946                 cmpeax, ebx000000014031F948                 jl      loc_14031FC9F000000014031F94E                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.CommandLine]000000014031F953                 lea     rdx, [rsp+118h+CommandLine]000000014031F95B                 call    PspCaptureAndValidateUnicodeString000000014031F960                 cmpeax, ebx000000014031F962                 jl      loc_14031FC9F000000014031F968                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.WindowTitle]000000014031F970                 lea     rdx, [rsp+118h+WindowTitle]000000014031F978                 call    PspCaptureAndValidateUnicodeString000000014031F97D                 cmpeax, ebx000000014031F97F                 jl      loc_14031FC9F000000014031F985                 lea     rcx, [r12+_RTL_USER_PROCESS_PARAMETERS.DesktopInfo]000000014031F98D                 lea     rdx, [rsp+118h+DesktopInfo]000000014031F995                 call    PspCaptureAndValidateUnicodeString000000014031F99A                 cmpeax, ebx000000014031F99C                 jl      loc_14031FC9F000000014031F9A2                 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                 cmpr15, rbx000000014031F9EC                 jnz     loc_1403C9F70000000014031F9F2                 movzx   r14d, [rsp+118h+RuntimeData.Length]000000014031F9F8                 cmpr14w, bx000000014031F9FC                 jnz     loc_1403C9F66000000014031FA02                 mov     [rsp+118h+RuntimeData.MaximumLength], bx000000014031FA07000000014031FA07 loc_14031FA07:                          ; CODE XREF: PspCaptureProcessParameters+AA749j000000014031FA07                                         ; PspCaptureProcessParameters+AA7ABj000000014031FA07                 movzx   ecx, [rsp+118h+var_4E]000000014031FA0F                 movzx   eax, [rsp+118h+var_6E]000000014031FA17                 add     rcx, rax000000014031FA1A                 movzx   eax, [rsp+118h+var_7E]000000014031FA22                 add     rcx, rax000000014031FA25                 movzx   eax, [rsp+118h+var_5E]000000014031FA2D                 add     rcx, rax000000014031FA30                 movzx   eax, [rsp+118h+var_8E]000000014031FA38                 add     rcx, rax000000014031FA3B                 movzx   eax, [rsp+118h+dllPath.MaximumLength]000000014031FA40                 add     rcx, rax000000014031FA43                 movzx   eax, [rsp+118h+RuntimeData.MaximumLength]000000014031FA48                 add     rcx, rax000000014031FA4B                 movzx   eax, [rsp+118h+CurrentDirectory.MaximumLength]000000014031FA50                 lea     rcx, [rcx+rax+401h]000000014031FA58                 and     rcx, 0FFFFFFFFFFFFFFFEh000000014031FA5C                 mov     [rsp+118h+var_C8], rcx000000014031FA61                 mov     [rsp+118h+var_B0], rcx000000014031FA66                 mov     rax, [rsp+118h+EnvironmentSize]000000014031FA6B                 lea     rdx, [rcx+rax]  ; NumberOfBytes000000014031FA6F                 cmprdx, rcx000000014031FA72                 jb      loc_1403C9FD1000000014031FA78                 mov     [rsp+118h+var_A8], rdx000000014031FA7D                 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] ; src000000014031FB1A                 call    PspCopyUnicodeString000000014031FB1F                 mov     esi, eax000000014031FB21                 cmpeax, ebx000000014031FB23                 jl      loc_1403CA0AC000000014031FB29                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.DllPath]000000014031FB2D                 lea     r8, [rsp+118h+Dst]000000014031FB35                 lea     rcx, [rsp+118h+dllPath]000000014031FB3A                 call    PspCopyUnicodeString000000014031FB3F                 mov     esi, eax000000014031FB41                 cmpeax, ebx000000014031FB43                 jl      loc_1403CA0AC000000014031FB49                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.ImagePathName]000000014031FB4D                 lea     r8, [rsp+118h+Dst]000000014031FB55                 lea     rcx, [rsp+118h+ImagePathName]000000014031FB5D                 call    PspCopyUnicodeString000000014031FB62                 mov     esi, eax000000014031FB64                 cmpeax, ebx000000014031FB66                 jl      loc_1403CA0AC000000014031FB6C                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.CommandLine]000000014031FB70                 lea     r8, [rsp+118h+Dst]000000014031FB78                 lea     rcx, [rsp+118h+CommandLine]000000014031FB80                 call    PspCopyUnicodeString000000014031FB85                 mov     esi, eax000000014031FB87                 cmpeax, ebx000000014031FB89                 jl      loc_1403CA0AC000000014031FB8F                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.WindowTitle]000000014031FB96                 lea     r8, [rsp+118h+Dst]000000014031FB9E                 lea     rcx, [rsp+118h+WindowTitle]000000014031FBA6                 call    PspCopyUnicodeString000000014031FBAB                 mov     esi, eax000000014031FBAD                 cmpeax, ebx000000014031FBAF                 jl      loc_1403CA0AC000000014031FBB5                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.DesktopInfo]000000014031FBBC                 lea     r8, [rsp+118h+Dst]000000014031FBC4                 lea     rcx, [rsp+118h+DesktopInfo]000000014031FBCC                 call    PspCopyUnicodeString000000014031FBD1                 mov     esi, eax000000014031FBD3                 cmpeax, ebx000000014031FBD5                 jl      loc_1403CA0AC000000014031FBDB                 lea     rdx, [rdi+_RTL_USER_PROCESS_PARAMETERS.ShellInfo] ; Src000000014031FBE2                 lea     r8, [rsp+118h+Dst] ; Dst000000014031FBEA                 lea     rcx, [rsp+118h+ShellInfo] ; Size000000014031FBF2                 call    PspCopyUnicodeString | 
6、最后设置Flages2和pProcessParameters并退出
| 1 2 3 4 5 6 7 | 000000014031FC91                 or      [r13+CreateProcessContext.Flags2], 4000000014031FC96                 mov     [r13+CreateProcessContext.PRTL_USER_PROCESS_PARAMETERS], rdi000000014031FC9D                 xor     eax, eax000000014031FC9F                 add     rsp, 0E0h000000014031FCA6                 pop     r15000000014031FCA8                 pop     r14000000014031FCAA                 pop     r13 | 
64位CreateProcess逆向:(二)0环下参数的整合即创建进程的整体流程的更多相关文章
- WindowsServer2012 R2 64位中文标准版(IIS8.5)下手动搭建PHP环境详细图文教程(二)安装IIS8.5
		//来源:http://www.imaoye.com/Technology/WindowsServer2012R264IIS85.html 阿里云服务器ECS Windows Server 2012 ... 
- WIN7 64位系统搭建WINCE6.0系统遇到的问题
		WIN7 64位系统搭建WINCE6.0系统遇到的问题 安装顺序如下: .先装Visual Studio2005: .安装Visual Studio2005 Service Pack 1: .安装Vi ... 
- win7(64位)+IE8+QC9.0
		环境win7(64位)+IE8+QC9.0出现的问题IE8访问QC9.0有时访问登录显示正常,但是有时访问QC页面无法显示正常,然后在ie8中安全中设置“启用内存保护帮助减少联机攻击*”也无法找到该项 ... 
- 64位windows系统安装javaee6.0不成功解决方案
		64位windows系统安装javaee6.0不成功解决方案 (2013-01-19 14:59:51) 转载▼ 标签: 杂谈 could not find the required versio ... 
- Windows系统调用中API从3环到0环(下)
		Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(下) 如果对API在 ... 
- VS2012在win7 64位机中x86和x64下基本类型的占用空间大小(转)
		VS2012在win7 64位机中x86和x64下基本类型的占用空间大小 #include "stdafx.h" #include <windows.h> int _t ... 
- Win10 64位+VS2015+Opencv3.3.0安装配置
		Win10 64位+VS2015+Opencv3.3.0安装配置 1.我们首先下载VS2015.OpenCV3.3.0. 1.1 VS2015下载 在官网https://visualstudio.mi ... 
- 64位win7+PCL1.6.0+VS2010,64位win10+PCL1.6.0+VS2010
		https://blog.csdn.net/liukunrs/article/details/80216329 大体转载自:https://blog.csdn.net/sinat_24206709/a ... 
- Ubuntu14.04 64位机上安装cuda8.0 cudnn5.0操作步骤 - 网络资源是无限的
		查看Ubuntu14.04 64位上显卡信息,执行: lspci | grep -i vga lspci -v -s 01:00.0 nvidia-smi 第一条此命令可以显示一些显卡的相关信息:如果 ... 
随机推荐
- OpenStack核心组件-keystone
			1. Keystone介绍 keystone是OpenStack的组件之一,用于为OpenStack家族中的其它组件成员提供统一的认证服务,包括身份验证.令牌的发放和校验.服务列表.用户权限的定义等等 ... 
- beta版本——第七次冲刺
			第七次冲刺 (1)SCRUM部分☁️ 成员描述: 姓名 李星晨 完成了哪个任务 编写个人信息修改界面的js 花了多少时间 3h 还剩余多少时间 0h 遇到什么困难 密码验证部分出现问题 这两天解决的进 ... 
- 关于 ES5 & ES6 数组遍历的方法
			ES5 数组遍历方法 1.for 循环 , , , , ] ; i < arr.length; i++) { console.log(arr[i]) } 2.forEach , , , , ] ... 
- Django项目中使用qq第三方登录。
			使用qq登录的前提是已经在qq互联官网创建网站应用并获取到QQ互联中网站应用的APP ID和APP KEY 1,建路由 # qq登录 path('loginQq/',qq.loginQq,name=' ... 
- Koadic的安装和使用---http c2远控工具
			Koadic的安装和使用 2017.11.26 11:02 字数 690 阅读 611评论 0喜欢 2 概述 Koadic是DEFCON分型出来的一个后渗透工具,主要通过vbscript.jscr ... 
- C# CustomValidator
			当各种验证控件的验证类型都不能满足需要时可以使用CustomValidator验证控件,通过自定义验证函数来验证.直接看例子 <%@ Page Language="C#" A ... 
- QT 子文件的建立(pri)
			QT 在做项目的时候有时会有许多不同种类的文件,如果这些文件放在一起会显得特别乱,我们可以将文件用文件夹分类,这样会比较有条理. 1. 在项目文件夹下建立新的文件夹,并在文件夹中添加文本文档将后缀改为 ... 
- 服务端高并发分布式架构演进之路   转载,原文地址:https://segmentfault.com/a/1190000018626163
			1. 概述 本文以淘宝作为例子,介绍从一百个到千万级并发情况下服务端的架构的演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知,文章最后汇总了一些架构设计的原则. 特 ... 
- python接口自动化—封装获取常量的类
			背景: 一.执行case的过程: 首先需要,我们能够通过excel获取单元格的内容.获取内容时,首先需要知道获取的数据是哪一行的,这行数据中需要拿那些参数,比如case 名称.请求url.请求方式.h ... 
- IDEA-相关插件使用
			IDEA日常开发中,整理一些用到的插件,以便后续使用起来方便. 点击File-Settings->Plugins. 1.进度条-彩虹,搜索Nyan字样,如图所示(本人已安装),点击Install ... 
