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


原文地址:https://www.cnblogs.com/kuangke/p/11133720.html