一、Windows 进程创建的底层流程(六阶段深度解析)
进程创建是用户态 API 触发、内核态资源分配、子系统协同的复杂过程,核心依赖
CreateProcess
系列函数(实际为宏定义,映射到CreateProcessA/W
),具体分为六个阶段:1. 映像文件解析与重定向(用户态:Kernel32.dll)
- 文件格式判断:
CreateProcess
首先调用NtOpenFile
打开目标文件,通过解析 PE 头判断是否为合法可执行文件(32 位 / 64 位.exe)。若为非 Windows 原生格式(如 DOS 程序、Win16 程序、POSIX 程序),则启动对应兼容层程序:- DOS/Win16 程序:替换为
ntvdm.exe
(虚拟 DOS 机)作为执行载体; - POSIX 程序:替换为
posix.exe
; - 批处理文件(.bat/.cmd):替换为
cmd.exe
并传入批处理路径作为参数。
- DOS/Win16 程序:替换为
- 调试器重定向检测:查询注册表
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
,若目标程序存在Debugger
键值(如设置为windbg.exe
),则将执行目标替换为调试器程序,原程序作为参数传入,实现调试劫持。 - 内存区创建:通过
NtCreateSection
创建内存区(Section 对象),将映像文件映射到虚拟地址空间(此时仅建立映射关系,未实际加载数据)。
2. 内核进程对象构建(内核态:执行体)
此阶段由内核的执行体(Executive)模块完成,核心是创建EPROCESS 对象(进程控制块的核心),该对象包含进程的所有内核态元数据,结构拆解如下:
- 核心子结构:
KPROCESS
(偏移 + 0x000):存储进程调度信息(优先级、状态、时间片),是内核调度器的核心操作对象;ProcessLock
(偏移 + 0x06c):自旋锁,确保多 CPU 环境下进程对象的原子操作;CreateTime/ExitTime
(偏移 + 0x070/+0x078):进程生命周期时间戳;AccessToken
(隐藏字段):指向该进程关联的访问令牌(与用户账户直接关联的核心结构)。
- 地址空间初始化:为进程分配独立的虚拟地址空间(32 位系统默认 2GB 用户空间 + 2GB 内核空间,可通过启动参数调整为 3GB 用户空间),并初始化页表(PML4/PDPT 等页表结构)。
3. 初始线程对象创建(内核态:执行体 + 内核)
进程本身不具备执行能力,需创建初始线程(主线程)作为 CPU 调度单元:
- 线程对象构建:创建
ETHREAD
(执行体线程对象)和KTHREAD
(内核线程对象),KTHREAD
包含线程上下文(寄存器值、栈指针)、调度优先级、亲和性掩码等; - 栈初始化:为线程分配内核栈(默认 12KB)和用户栈(大小由 PE 头指定,通常为 1MB),并初始化栈帧(压入线程启动参数、返回地址);
- 上下文设置:将线程上下文设置为
LdrInitializeThunk
(加载器初始化函数),确保线程启动时优先执行 DLL 加载逻辑。
4. Windows 子系统通知(用户态:Csrss.exe)
Windows 子系统(
csrss.exe
)负责维护进程的用户态元数据,内核通过LPC(本地过程调用) 机制通知子系统创建进程:- W32PROCESS 对象创建:子系统为新进程创建
W32PROCESS
对象,存储窗口管理器相关数据(如窗口句柄表、消息队列); - 进程 ID 注册:将进程 ID(PID)与子系统内部索引关联,确保后续窗口操作(如
CreateWindow
)能定位到目标进程。
5. 线程启动与挂起判断(内核态:调度器)
- 启动逻辑:若未设置
CREATE_SUSPENDED
标志,内核调度器将线程状态设为READY
,放入调度队列等待 CPU 执行;若设置该标志,线程初始状态为SUSPENDED
,需通过ResumeThread
激活。 - 首次调度触发:当线程获得 CPU 时间片时,硬件将加载其上下文(寄存器值),从
LdrInitializeThunk
开始执行。
6. 用户态环境初始化(用户态:Ntdll.dll)
线程进入用户态后,由
Ntdll.dll
的加载器(Loader)完成最终初始化:- DLL 依赖加载:递归加载 PE 头中指定的依赖 DLL(如
kernel32.dll
、user32.dll
),通过LdrLoadDll
函数实现,每个 DLL 加载后执行其DllMain
函数(入口点); - 进程环境块(PEB)初始化:在用户空间固定地址(0x7ffdf000)创建 PEB,存储进程的用户态元数据(命令行参数、环境变量、加载的模块列表);
- 入口点跳转:调用 PE 头指定的程序入口点(通常为
WinMain
或main
),进程正式开始执行用户代码。
二、进程与 Windows 账户的关联机制(安全上下文注入)
进程与用户账户的关联核心是访问令牌(AccessToken) 的注入与权限控制,该过程由Lsass.exe(本地安全授权服务)和内核协同完成:
1. 访问令牌(AccessToken)的结构与生成
访问令牌是一个内核对象,包含当前进程所属用户的所有安全信息,结构核心字段如下:
- 用户 SID:安全标识符,唯一标识用户账户(如管理员账户的 SID 为
S-1-5-32-500
,普通用户为S-1-5-32-501
); - 组 SID 列表:用户所属的安全组(如
Administrators
组的 SID 为S-1-5-32-544
); - 权限掩码:包含该用户的所有权限(如
SE_DEBUG_NAME
对应调试权限,SE_SHUTDOWN_NAME
对应关机权限); - 默认所有者:新建对象时的默认所有者 SID;
- 会话 ID:标识当前用户的登录会话(远程桌面登录与本地登录会话 ID 不同)。
访问令牌的生成时机分两种场景:
- 交互式登录:用户输入账户密码后,
winlogon.exe
将凭证传递给Lsass.exe
,Lsass
通过 SAM 数据库(本地账户)或 Active Directory(域账户)验证凭证,验证通过后生成访问令牌,并通过NtCreateToken
将其与登录会话关联; - 进程创建继承:新进程默认继承父进程的访问令牌(如双击桌面程序时,父进程为
explorer.exe
,新进程继承当前登录用户的令牌)。
2. 权限注入与继承逻辑
- 默认继承机制:
CreateProcess
默认使用父进程的访问令牌创建新进程,通过EPROCESS
对象的AccessToken
字段关联。例如,管理员账户启动的explorer.exe
创建的所有子进程(如notepad.exe
)均继承管理员令牌; - 指定账户创建:若需以其他用户身份创建进程,需调用
CreateProcessAsUser
或CreateProcessWithLogonW
,流程如下:- 调用
LogonUser
获取目标用户的访问令牌(需提供账户密码); - 将令牌句柄传入
CreateProcessAsUser
的hToken
参数; - 内核在创建
EPROCESS
对象时,将该令牌绑定到新进程,而非继承父进程令牌;
- 调用
- 权限过滤:即使继承管理员令牌,新进程也可能被用户账户控制(UAC) 过滤权限:
- 标准用户启动程序:直接使用标准令牌;
- 管理员启动非特权程序:默认使用筛选令牌(移除高风险权限,如
SE_DEBUG_NAME
),仅当程序带requestedExecutionLevel=requireAdministrator
清单时,才通过 UAC 弹窗提升为完整管理员令牌。
3. 权限检查触发流程
进程执行特权操作(如打开系统进程、修改注册表)时,Windows 通过以下流程验证权限,核心依赖安全描述符(SD) 与访问令牌的匹配:
- 目标对象(如文件、进程)的安全描述符包含DACL(自主访问控制列表),列出允许 / 拒绝访问的用户 / 组 SID 及权限;
- 内核的安全引用监视器(SRM)获取当前进程的访问令牌;
- 对比令牌中的用户 / 组 SID 与 DACL 中的条目,判断是否拥有操作权限;
- 若匹配允许条目则执行操作,否则返回
ACCESS_DENIED
错误(错误码 0x80070005)。
三、关键系统组件与交互关系
进程创建与账户关联过程涉及多个核心系统进程,交互逻辑如下:
组件名称 | 运行态 | 核心作用 |
---|---|---|
Kernel32.dll |
用户态 | 提供CreateProcess API 封装,触发进程创建流程 |
Ntdll.dll |
用户态 | 实现用户态与内核态的过渡(通过系统调用),负责 DLL 加载 |
csrss.exe |
用户态 | Windows 子系统服务进程,维护进程的用户态窗口数据 |
Lsass.exe |
用户态 | 生成访问令牌,管理账户凭证验证(依赖 SAM 数据库或 AD) |
执行体(Executive) | 内核态 | 创建 EPROCESS/ETHREAD 对象,管理进程内核元数据 |
安全引用监视器(SRM) | 内核态 | 权限检查核心,对比访问令牌与目标对象的安全描述符 |
四、特殊场景扩展
1. 无账户进程(系统进程)
- 如
System
进程(PID=4)、smss.exe
(会话管理器),其访问令牌的用户 SID 为S-1-5-18
(本地系统账户),无对应交互式用户,权限最高且不受 UAC 限制。
2. 进程权限提升
- 通过
AdjustTokenPrivileges
函数启用令牌中已有的权限(但无法添加新权限); - 通过
CreateProcessWithTokenW
复用其他用户的令牌创建进程(需SE_IMPERSONATE_NAME
权限)。
3. 域环境下的进程关联
- 域用户登录时,
Lsass.exe
通过 LDAP 协议向域控制器(DC)验证凭证,生成包含域 SID(如S-1-5-21-域ID-用户ID
)的访问令牌; - 进程权限检查时,DACL 可包含域组 SID(如
Domain Admins
组),实现跨设备的权限统一管理。
综上,Windows 进程的创建是用户态 API、内核对象管理、子系统协同的多层过程,而与用户账户的关联则通过访问令牌这一核心结构实现,从权限注入到运行时检查形成完整的安全控制链。