SMSS 初始化过程分析

发布时间:2026/7/19 5:47:13
SMSS 初始化过程分析 SMSS 初始化过程分析概述SMSSSession Manager Subsystem会话管理器子系统是 ReactOS 中内核启动的第一个用户态进程。它负责完成系统启动的 Phase 1 初始化创建 LPC 通信端口、加载注册表配置、创建分页文件、初始化 KnownDLLs、加载 Win32 子系统win32k.sys、启动 CSRSS 和 WINLOGON。文件d:\reactos\base\system\smss\文件用途smss.c主入口点_main进程执行逻辑sminit.c核心初始化SmpInitsmloop.cLPC API 循环SmpApiLoopsmsubsys.c子系统加载smsbapi.c服务器到客户端 APIsmsessn.c会话管理smutil.c工具函数pagefile.c分页文件管理crashdmp.c崩溃转储检查存根1. 入口点_main文件[smss.c#L432](file:///d:/reactos/base/system/smss/smss.c#L432)_main(IN INT argc,IN PCHAR argv[],IN PCHAR envp[],IN ULONG DebugFlag)DebugFlag是 SMSS 从内核收到的唯一参数。SMSS 不是通过 LPC 端口句柄启动的——内核直接启动\SystemRoot\System32\smss.exe。LPC 端口是由 SMSS 自己创建的。_main的 6 个步骤_main() │ ├─ 1. 标记为关键进程 (RtlSetProcessIsCritical) │ → 如果 SMSS 终止系统蓝屏 │ ├─ 2. 提升优先级到基优先级 11 │ ├─ 3. SmpInit() ← ★ 所有实质性初始化 │ ├─ 4. SmpExecuteInitialCommand(WINLOGON) ← ★ 启动 Winlogon │ ├─ 5. 从会话空间分离 (SystemSessionDetach) │ └─ 6. NtWaitForMultipleObjects(CSRSS, WINLOGON) └─ 任一终止 → SmpTerminate() → 系统关闭2. SmpInit — 核心初始化文件[sminit.c#L2453](file:///d:/reactos/base/system/smss/sminit.c#L2453)这是所有实质性初始化的入口分为8 个步骤SmpInit() │ ├─ Step 1: 创建堆 (RtlCreateTagHeap) │ ├─ Step 2: 启用硬错误 (ProcessDefaultHardErrorMode) │ ├─ Step 3: 初始化列表及锁 │ ├─ SmpKnownSubSysHead (子系统列表) │ ├─ SmpSessionListHead (会话列表) │ ├─ NativeProcessList (本机进程列表) │ └─ SmpNextSessionId 1 │ ├─ Step 4: SmpCreateSecurityDescriptors(TRUE) │ ├─ SmpPrimarySecurityDescriptor — 管理員/SYSTEM完全访问 │ ├─ SmpLiberalSecurityDescriptor — World/受限执行访问 │ ├─ SmpKnownDllsSecurityDescriptor — \KnownDlls 目录 │ └─ SmpApiPortSecurityDescriptor — \SmApiPort (仅管理员SYSTEM) │ ├─ Step 5: 创建 \SmApiPort LPC 端口 │ ├─ NtCreatePort(\SmApiPort) — 主 LPC 端口 │ ├─ RtlCreateUserThread(SmpApiLoop) — 第一个监听线程 │ └─ RtlCreateUserThread(SmpApiLoop) — 第二个监听线程 │ ├─ Step 6: 创建 \Device\VolumesSafeForWriteAccess 事件 │ ├─ Step 7: SmpLoadDataFromRegistry(InitialCommand) ← ★ 最复杂 │ └─ Step 8: 返回3. SmpLoadDataFromRegistry — 注册表驱动初始化文件[sminit.c#L2245](file:///d:/reactos/base/system/smss/sminit.c#L2245)这是 SMSS 中最长、最关键的步骤通过读取注册表HKLM\System\CurrentControlSet\Control\Session Manager\下的配置来驱动整个初始化流程SmpLoadDataFromRegistry() │ ├─ 3a: 初始化 11 个列表 │ ├─ BootExecuteList — BootExecute 项 (默认: autocheck) │ ├─ SetupExecuteList — SetupExecute 项 │ ├─ PagingFileList — 分页文件配置 │ ├─ DosDevicesList — DOS 设备映射 │ ├─ FileRenameList — 挂起文件重命名 │ ├─ KnownDllsList — KnownDLL 列表 │ ├─ ExcludeKnownDllsList — 排除的 KnownDLL │ ├─ SubSystemList — 子系统条目 │ ├─ SubSystemsToLoad — 必需子系统 │ ├─ SubSystemsToDefer — 可选子系统 │ └─ ExecuteList — Execute 命令 │ ├─ 3b: SmpPagingFileInitialize() — 初始化分页文件描述符 │ ├─ 3c: RtlCreateEnvironment(TRUE) — 创建系统默认环境块 │ ├─ 3d: 检查 MiniNT 启动标志 │ ├─ 3e: RtlQueryRegistryValues() — ★ 读取注册表配置表 │ ├─ ProtectionMode → 保护模式 (默认开启) │ ├─ ObjectDirectories → NtCreateDirectoryObject(\Windows) │ │ NtCreateDirectoryObject(\RPC Control) │ ├─ BootExecute → 存到 BootExecuteList │ ├─ SetupExecute → 存到 SetupExecuteList │ ├─ PendingFileRenameOps → 存到 FileRenameList │ ├─ PagingFiles → 存到 PagingFileList │ ├─ DOS Devices → 存到 DosDevicesList │ ├─ KnownDlls → 存到 KnownDllsList │ ├─ Environment → 设置环境变量 │ ├─ SubSystems → 子系统配置 │ │ ├─ Required → 必需 (Debug, Windows) │ │ ├─ Optional → 可选 │ │ └─ Kmode → 内核模式子系统入口 │ └─ Execute → 存到 ExecuteList │ ├─ 3f: SmpInitializeDosDevices() │ 遍历 DosDevicesList → 创建 \??\C: → \Device\HarddiskVolume1 等 │ ├─ 3g: NtCreateDirectoryObject(\Sessions) │ ├─ 3h: 执行 BootExecute 项 (autocheck) │ ├─ 3i: SmpProcessFileRenames() — 处理挂起文件重命名 │ ├─ 3j: SmpInitializeKnownDlls() │ 创建 \KnownDlls 目录为每个 DLL 创建 Section 对象 │ ├─ 3k: SmpCreatePagingFiles() │ ├─ SmpCreateVolumeDescriptors() — 枚举所有固定卷 │ └─ NtCreatePagingFile() — 创建分页文件 │ ├─ 3l: NtInitializeRegistry(CM_BOOT_FLAG_SMSS) — 启用注册表写访问 │ ├─ 3m: SmpCreateDynamicEnvironmentVariables() │ 设置 OSWindows_NT, PROCESSOR_ARCHITECTURE, NUMBER_OF_PROCESSORS 等 │ └─ 3n: SmpLoadSubSystemsForMuSession() ← ★ 加载子系统4. SmpLoadSubSystemsForMuSession — 加载子系统文件[smsubsys.c#L510](file:///d:/reactos/base/system/smss/smsubsys.c#L510)这是创建会话 0 并启动 CSRSS 的关键步骤SmpLoadSubSystemsForMuSession() │ ├─ 4a: SmpTranslateSystemPartitionInformation() │ 把系统分区信息写入注册表 BootDir │ ├─ 4b: 执行 SetupExecute 列表 │ ├─ 4c: ★ 处理 Kmode 子系统 — 创建会话 0 加载 win32k.sys │ ├─ NtSetSystemInformation(SystemSessionCreate, ...) │ │ → ★ 创建会话 0 ★ (SMSS 的第一个会话创建点) │ ├─ AttachedSessionId MuSessionId │ └─ NtSetSystemInformation(SystemExtendServiceTableInformation, ...) │ → ★ 加载 win32k.sys ★ (窗口管理/图形子系统) │ ├─ 4d: 加载必需子系统 (CSRSS) │ └─ SmpLoadSubSystem(Windows CSRSS) │ ├─ SmpExecuteImage(csrss.exe) ← 创建进程 (挂起) │ ├─ SmpWindowsSubSysProcessId PID │ ├─ 等待 CSRSS 通过 \SmApiPort 连接 │ │ └─ SmpHandleConnectionRequest() │ │ ├─ NtAcceptConnectPort() │ │ ├─ NtCompleteConnectPort() │ │ └─ NtConnectPort(CSRSS 的 SbApiPort) │ └─ NtResumeThread(CSRSS) ← 恢复 CSRSS 运行 │ ├─ 4e: 确定初始命令 │ └─ 默认: winlogon.exe │ └─ 4f: 执行 Execute 列表5. 启动顺序与依赖关系内核启动 SMSS │ ├─ SMSS 创建 \SmApiPort (LPC 端口) ├─ SMSS 读取注册表创建分页文件 ├─ SMSS 初始化 KnownDLLs │ ├─ ★ SMSS 调用 SystemSessionCreate → 创建会话 0 ├─ ★ SMSS 调用 SystemExtendServiceTable → 加载 win32k.sys │ ├─ SMSS 启动 CSRSS (csrss.exe, 挂起) │ ├─ CSRSS 初始化自建 → 连接 \SmApiPort │ ├─ SMSS 接受连接 → 回连 CSRSS 的 SbApiPort │ └─ SMSS 恢复 CSRSS 线程 → CSRSS 开始运行 │ ├─ SMSS 启动 WINLOGON (winlogon.exe) │ ├─ WINLOGON 通过 \SmApiPort 连接 SMSS │ ├─ SMSS 创建新会话 → 跳转到会话 1 │ └─ WINLOGON → 创建 WinSta0 Default 桌面 │ └─ SMSS 从会话 0 分离 └─ NtWaitForMultipleObjects(CSRSS, WINLOGON) └─ 任一终止 → SmpTerminate() → 系统关闭进程树: SMSS.EXE / \ CSRSS.EXE WINLOGON.EXE | LSASS.EXE SERVICES.EXE6. 各关键步骤详解6.1 LPC 通信架构SMSS 使用两个方向的 LPC 端口┌─────────────────┐ ┌─────────────────┐ │ SMSS │ │ CSRSS │ │ │ │ │ │ \SmApiPort ◄───┼──接受────┼─── 客户端连接 │ │ │ │ │ │ SbApiPort ◄───┼──回连────┼───\SbApiPort │ │ │ │ │ │ SmpApiLoop x2 │ │ CSRSS API 循环 │ └─────────────────┘ └─────────────────┘\SmApiPort客户端CSRSS、WINLOGON向 SMSS 发送 API 请求SbApiPortSMSS 向每个子系统CSRSS发送请求如创建会话、创建进程6.2 API 分发表文件[smloop.c#L258](file:///d:/reactos/base/system/smss/smloop.c#L258)PSM_API_HANDLER SmpApiDispatch[]{SmpCreateForeignSession,// 未实现SmpSessionComplete,// 未实现SmpTerminateForeignSession,// 未实现SmpExecPgm,// 执行程序 (CSRSS 调用)SmpLoadDeferedSubsystem,// 加载延迟子系统SmpStartCsr,// 启动 CSRSS (新会话)SmpStopCsr// 停止 CSRSS (未实现)};6.3 CSRSS 启动详细过程文件[smsubsys.c#L138](file:///d:/reactos/base/system/smss/smsubsys.c#L138)SmpLoadSubSystem(Windows csrss.exe) │ ├─ SmpExecuteImage(csrss.exe, ...) │ ├─ RtlCreateProcessParameters() — 构造命令行 │ ├─ RtlCreateUserProcess() — 创建进程 (CREATE_SUSPENDED) │ ├─ SmpSetProcessMuSessionId() — 关联到会话 0 │ └─ 返回进程句柄、线程句柄、PID │ ├─ SmpWindowsSubSysProcessId PID ← 保存 CSRR PID │ ├─ ★ 等待 CSRSS 连接 \SmApiPort │ (CSRSS 启动后连接 \SmApiPort → 阻塞在 NtRequestWaitReplyPort) │ ├─ SmpHandleConnectionRequest() ← SMSS 处理连接 │ ├─ NtAcceptConnectPort() — 接受连接 │ ├─ NtCompleteConnectPort() — 完成连接 │ ├─ NtConnectPort(CSRSS_SbApiPort) — 回连 CSRSS │ │ → CSRSS 的 NtRequestWaitReplyPort 返回 │ ├─ NtSetEvent(SmpCidSubsystem.Event) │ └─ 分配 SMP_CLIENT_CONTEXT │ └─ NtResumeThread(CSRSS_Thread) ← ★ CSRSS 开始运行6.4 WINLOGON 启动详细过程文件[smss.c#L297](file:///d:/reactos/base/system/smss/smss.c#L297)SmpExecuteInitialCommand(0, winlogon.exe, Handles[1], NULL) │ ├─ SmConnectToSm(\SmApiPort) ← 连接自己的 LPC 端口 │ ├─ SmpExecuteImage(winlogon.exe, DEFERRED) │ → 以挂起状态创建 WINLOGON 进程 (DEFERRED 不恢复) │ (因为 WINLOGON 需要先通过 LPC 注册再由 SMSS 恢复) │ ├─ 保存 WINLOGON 句柄到 Handles[1] │ └─ SmExecPgm() 通过 LPC 发送到 SmpApiLoop └─ SmpExecPgm() [smloop.c:70] └─ SmpSbCreateSession() [smsbapi.c] ├─ SmpLocateKnownSubSysByType() → 找 CSRSS ├─ NtDuplicateObject() → 传递句柄 ├─ SmpAllocateSessionId() → 分配新会话 ├─ NtRequestWaitReplyPort(SbpCreateSession) │ → 发送到 CSRSSCSRSS 创建会话 └─ NtResumeThread(WINLOGON) → ★ WINLOGON 开始运行7. 会话管理文件[smsessn.c](file:///d:/reactos/base/system/smss/smsessn.c)SMSS 维护自己的会话 ID 分配函数用途SmpAllocateSessionId分配 SMSS 会话 ID从 1 开始SmpDeleteSession从会话列表删除SmpCheckDuplicateMuSessionId检查 MuSessionId 是否重复SmpGetProcessMuSessionId查询进程的会话 IDSmpSetProcessMuSessionId设置进程的会话 ID会话 0 和会话 1会话创建时机包含进程会话 0SmpLoadSubSystemsForMuSession→SystemSessionCreateSMSS、CSRSS会话 1WINLOGON 启动 →SmpSbCreateSession→ CSRSSSbpCreateSessionWINLOGON、LSASS、SERVICES8. 分页文件管理文件[pagefile.c](file:///d:/reactos/base/system/smss/pagefile.c)SMSS 创建分页文件的完整流程SmpCreatePagingFiles() │ ├─ SmpCreateVolumeDescriptors() │ 枚举所有固定磁盘检查可用空间 │ └─ 对每个分页文件描述符: ├─ 系统托管: 计算 RAM 依赖大小 (minRAM, max3*RAM) ├─ 手动配置: 验证大小 ├─ 如果都失败 → 紧急分页文件 (最小 16MB) └─ NtCreatePagingFile()9. KnownDLLs 初始化文件[sminit.c#L1692](file:///d:/reactos/base/system/smss/sminit.c#L1692)KnownDLLs 是 Windows 的一个性能优化机制。SMSS 在引导时创建\KnownDlls目录对象将系统 DLLkernel32.dll, user32.dll, ntdll.dll 等作为 Section 对象预加载SmpInitializeKnownDlls() │ ├─ 打开 \KnownDlls 目录或 NtCreateDirectoryObject ├─ 对每个 KnownDLL 条目: │ ├─ 检查是否在 ExcludeKnownDllsList 中 │ ├─ NtCreateSection() — 创建 DLL 的 Section 对象 │ └─ NtCreateSymbolicLinkObject() — 链接到目录 └─ 关闭句柄好处是当进程启动时这些 DLL 已经在缓存中无需重新从磁盘加载。10. 完整调用链_main() [smss.c:432] │ ├─ RtlSetProcessIsCritical(TRUE) [smss.c:447] ├─ NtSetInformationProcess(BasePriority11) [smss.c:452] │ ├─ SmpInit() [smss.c:469] │ ├─ RtlCreateTagHeap() [sminit.c:2461] │ ├─ NtSetInformationProcess(硬错误) [sminit.c:2468] │ ├─ 初始化列表和锁 [sminit.c:2475] │ ├─ SmpCreateSecurityDescriptors() [sminit.c:2489] │ ├─ NtCreatePort(\SmApiPort) [sminit.c:2505] │ ├─ RtlCreateUserThread(SmpApiLoop) x2 [sminit.c:2514] │ ├─ NtCreateEvent(VolumesSafeForWriteAccess) [sminit.c:2538] │ └─ SmpLoadDataFromRegistry() [sminit.c:2558] │ ├─ SmpPagingFileInitialize() [sminit.c:2274] │ ├─ RtlCreateEnvironment() [sminit.c:2277] │ ├─ RtlQueryRegistryValues() [sminit.c:2328] │ │ ├─ SmpConfigureProtectionMode │ │ ├─ SmpConfigureObjectDirectories │ │ │ └─ NtCreateDirectoryObject(\Windows) │ │ │ └─ NtCreateDirectoryObject(\RPC Control) │ │ ├─ SmpConfigureMemoryMgmt(BootExecute) │ │ ├─ SmpConfigureFileRenames │ │ ├─ SmpConfigureMemoryMgmt(PagingFiles) │ │ ├─ SmpConfigureDosDevices │ │ ├─ SmpConfigureKnownDlls │ │ ├─ SmpConfigureEnvironment() x2 │ │ ├─ SmpConfigureSubSystems() │ │ └─ SmpConfigureMemoryMgmt(Execute) │ ├─ SmpInitializeDosDevices() [sminit.c:2344] │ │ └─ NtCreateSymbolicLink(\??\C: → \Device\HarddiskVolume1) │ ├─ NtCreateDirectoryObject(\Sessions) [sminit.c:2355] │ ├─ SmpExecuteCommand(BootExecute) [sminit.c:2374] │ ├─ SmpProcessFileRenames() [sminit.c:2391] │ ├─ SmpInitializeKnownDlls() [sminit.c:2394] │ │ └─ NtCreateSection(DLL) → \KnownDlls │ ├─ SmpCreatePagingFiles() [sminit.c:2425] │ │ ├─ SmpCreateVolumeDescriptors() │ │ └─ NtCreatePagingFile() │ ├─ NtInitializeRegistry() [sminit.c:2429] │ ├─ SmpCreateDynamicEnvironmentVariables() [sminit.c:2432] │ └─ SmpLoadSubSystemsForMuSession() [sminit.c:2441] │ ├─ SmpTranslateSystemPartitionInformation() [smsubsys.c:522] │ ├─ SmpExecuteCommand(SetupExecute) [smsubsys.c:525] │ ├─ NtSetSystemInformation(SystemSessionCreate) [smsubsys.c:559] │ │ └─ ★ 创建会话 0 │ ├─ NtSetSystemInformation(ExtendServiceTable)[smsubsys.c:577] │ │ └─ ★ 加载 win32k.sys │ ├─ SmpLoadSubSystem(Windows) [smsubsys.c:596] │ │ ├─ SmpExecuteImage(csrss.exe) [smss.c:281] │ │ │ ├─ RtlCreateProcessParameters() │ │ │ ├─ RtlCreateUserProcess() │ │ │ └─ SmpSetProcessMuSessionId() │ │ ├─ 等待 CSRSS 连接 \SmApiPort │ │ │ └─ SmpHandleConnectionRequest() [smloop.c:273] │ │ │ ├─ NtAcceptConnectPort() │ │ │ ├─ NtCompleteConnectPort() │ │ │ └─ NtConnectPort(SbApiPort) │ │ │ └─ NtSetEvent(SmpCidSubsystem.Event) │ │ └─ NtResumeThread(CSRSS) [smsubsys.c:396] │ │ └─ ★ CSRSS 开始运行 │ └─ 确定初始命令 winlogon.exe [smsubsys.c:628] │ ├─ SmpExecuteInitialCommand(WINLOGON) [smss.c:493] │ ├─ SmConnectToSm(\SmApiPort) [smss.c:297] │ ├─ SmpExecuteImage(winlogon.exe, DEFERRED) [smss.c:328] │ └─ SmExecPgm() → SmpExecPgm() [smss.c:367] │ └─ SmpSbCreateSession() [smsbapi.c] │ ├─ SmpLocateKnownSubSysByType() → CSRSS │ ├─ NtDuplicateObject() │ ├─ SmpAllocateSessionId() │ ├─ NtRequestWaitReplyPort(SbpCreateSession) │ │ └─ ★ CSRSS 创建会话 1 │ └─ NtResumeThread(WINLOGON) │ └─ ★ WINLOGON 开始运行 │ ├─ NtSetSystemInformation(SystemSessionDetach) [smss.c:509] ├─ NtWaitForMultipleObjects(CSRSS_Handle, WINLOGON_Handle) [smss.c:518] └─ SmpTerminate() (当任一终止时) [smss.c:577]关键架构总结概念说明SMSS 是原生应用不依赖 Win32直接使用 NT API双 LPC 端口通信\SmApiPort接收SbApiPort发送CSRSS 先于 WINLOGONCSRSS 是本机映像启动后提供 Win32 环境会话 0 由 SMSS 创建SystemSessionCreate→ 加载 win32k.sys会话 1 由 WINLOGON 创建SMSS 发送SbpCreateSession→ CSRSS 创建关键进程守护CSRSS 或 WINLOGON 终止 → SMSS 关闭系统延迟进程启动DEFERRED标志创建挂起 → LPC 注册 → 恢复KnownDLLs 优化预加载系统 DLL 为 Section 对象加速进程启动