0x00前言
windows11是如何创建进程并管理他们的呢?这篇分析CreateProcess在3环用户层做了哪些事情。
操作系统:windows 11
工具:vs,IDA,windbg
这是《深入解析Windows Kenrel》系列文章的第4章 第一篇
0x01CreateProcess第一阶段
CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件。下面看一个示例 创建一个进程
#include <stdio.h> #include <windows.h> int main(int argc, char* argv[]) { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); TCHAR szCommandLine[] = TEXT("powershell.exe"); if (!CreateProcess(NULL, // No module name (use command line) szCommandLine, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi) // Pointer to PROCESS_INFORMATION structure ) return 0; }
现在我们就来分析CreateProcess 这个函数的内部实现
根据是你union 编码还是ascii 调用CreateProcessW或者CreateProcessA 会调用kenrel32.dll 的createprocess
参数复制 完了 接着会继续调用KERNELBASE.dll 里面的CreateProcessW 这里面就是他的3环具体实现
0x02CreateProcess第二阶段
CreateProcessW 可以看到复制完参数 调用了 CreateProcessInternalW 去实现创建进程代码
真正的起点,应该是从CreateProcessInternal开始的
下面开始分析CreateProcessInternal函数
第一步就是 参数初始化和赋值
首先是参数的是否为空判断
lpCommandLine命令行字符串 不能为空
lpStartupInfo传递给新进程的信息 不能为空
lpProcessInformation新进程返回的信息 不能为空
获取当前进程peb的地址
接着dwCreationFlags 控制优先级等一系列标志判断
其中有代码会判断dwCreationFlags是否包含DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS标志位,
有则调用DbgUiConnectToDbg创建调试对象,并调用DbgUiGetThreadDebugObject获取该调试对象。
这也是一些调试器打开进程的原理
接着创建新进程的环境块RtlCreateEnvironmentEx
接着STARTUPINFO 数据处理
检测到STARTUPINFO 包含扩展数据 会调用函数BasepConvertWin32AttributeList
判断lpCurrentDirectory是否为NULL,不为NULL则申请堆空间,调用GetFullPathNameW由字符串获取对应的全路径
接着调用BaseFormatObjectAttributes通过参数ProcessAttributes格式化ProcessObjectAttributes对象,
通过参数ThreadAttributes格式化ThreadObjectAttributes对象,准备进入0环
接着就是对传入的lpCommandLine 参数做处理
最后到BasepCreateProcessParameters 根据FileName、bInheritHandles、Environment、StartupInfo这些信息,
创建RTL_USER_PROCESS_PARAMETERS结构体作为0环参数。
接着就是进入0环 NtCreateUserProcess 后面开始分析0环