转载: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

64位CreateProcess逆向:(二)0环下参数的整合即创建进程的整体流程的更多相关文章

  1. WindowsServer2012 R2 64位中文标准版(IIS8.5)下手动搭建PHP环境详细图文教程(二)安装IIS8.5

    //来源:http://www.imaoye.com/Technology/WindowsServer2012R264IIS85.html 阿里云服务器ECS Windows Server 2012 ...

  2. WIN7 64位系统搭建WINCE6.0系统遇到的问题

    WIN7 64位系统搭建WINCE6.0系统遇到的问题 安装顺序如下: .先装Visual Studio2005: .安装Visual Studio2005 Service Pack 1: .安装Vi ...

  3. win7(64位)+IE8+QC9.0

    环境win7(64位)+IE8+QC9.0出现的问题IE8访问QC9.0有时访问登录显示正常,但是有时访问QC页面无法显示正常,然后在ie8中安全中设置“启用内存保护帮助减少联机攻击*”也无法找到该项 ...

  4. 64位windows系统安装javaee6.0不成功解决方案

    64位windows系统安装javaee6.0不成功解决方案 (2013-01-19 14:59:51) 转载▼ 标签: 杂谈   could not find the required versio ...

  5. Windows系统调用中API从3环到0环(下)

     Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(下) 如果对API在 ...

  6. VS2012在win7 64位机中x86和x64下基本类型的占用空间大小(转)

    VS2012在win7 64位机中x86和x64下基本类型的占用空间大小 #include "stdafx.h" #include <windows.h> int _t ...

  7. Win10 64位+VS2015+Opencv3.3.0安装配置

    Win10 64位+VS2015+Opencv3.3.0安装配置 1.我们首先下载VS2015.OpenCV3.3.0. 1.1 VS2015下载 在官网https://visualstudio.mi ...

  8. 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 ...

  9. Ubuntu14.04 64位机上安装cuda8.0 cudnn5.0操作步骤 - 网络资源是无限的

    查看Ubuntu14.04 64位上显卡信息,执行: lspci | grep -i vga lspci -v -s 01:00.0 nvidia-smi 第一条此命令可以显示一些显卡的相关信息:如果 ...

随机推荐

  1. The Instruction Set In Cortex-M3

    The Cortex-M3 supports the Thumb-2 instruction set. This is one of the most important features of th ...

  2. MySQL安装-glibc方式安装

    MySQL安装-glibc方式安装 版本说明:这里安装版本为MySQL-5.7系列的 mysql-5.7.27-linux-glibc2.12-x86_64.tar.gz 步骤 下载软件包 官网下载 ...

  3. Codeforces Round #598 (Div. 3)- E. Yet Another Division Into Teams - 动态规划

    Codeforces Round #598 (Div. 3)- E. Yet Another Division Into Teams - 动态规划 [Problem Description] 给你\( ...

  4. Unity经典案例之:Fire Balls

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  5. Mysql【第二课】

  6. CentOS6.9下手动编译并安装Python3.7.0

    CentOS6.9默认安装的python版本为2.6.6,若想安装python3以上版本,只能手工编译安装 下面介绍Python-3.7.0版本的手动编译并安装的步骤 1.下载Python-3.7.0 ...

  7. Serializable的作用

    前两天接触到VO,DTO,entity这些概念,发现别人的代码中会有 implements serializable这个东西,之前并没有见过这种写法,就去了解了一下原因 import java.io. ...

  8. 洛谷:P1783 海滩防御(二分+并查集 最短路 最小生成树)

    题意: 给定长度为N的海滩,然后有M做防御塔,给出每座塔的位置Xi,到海岸的距离Yi. 求防御塔上最小观测半径Ri,使得海滩被封锁. 思路:要使左边界和右边界连通. 很nice,可以二分+并查集做. ...

  9. [NOIp 2018]all

    Description 题库链接: Day1 T1 铺设道路 Day1 T2 货币系统 Day1 T3 赛道修建 Day2 T1 旅行 Day2 T2 填数游戏 Day2 T3 保卫王国 Soluti ...

  10. 【比赛题解】CSP2019 简要题解

    D1T1 code 签到题,大家都会. 可以从高位往低位确定,如果遇到 \(1\),则将排名取反一下. 注意要开 unsigned long long. #include <bits/stdc+ ...