WINLOGON 初始化与作用分析

WINLOGON 初始化与作用分析

概述

WINLOGON.EXE 是 ReactOS 的用户登录进程,由 SMSS 在启动 CSRSS 之后创建。它负责创建窗口站 WinSta0 和三个桌面(Default/Winlogon/Screen-Saver)、加载 GINA DLL 处理用户身份验证、启动 Shell(explorer.exe)和服务管理器(services.exe),并作为系统安全关注序列(SAS,即 Ctrl+Alt+Del)的处理者。

源码目录d:\reactos\base\system\winlogon\

文件 用途
winlogon.c 主入口点 WinMain
wlx.c GINA 加载/窗口站和桌面创建/WINLOGON 分发表
sas.c SAS 处理/登录注销/Shell 启动
security.c 安全描述符/桌面和窗口站访问控制
notify.c 通知包管理
shutdown.c 系统关闭对话框
screensaver.c 屏幕保护管理
environment.c 用户环境创建
setup.c 安装模式支持
rpcserver.c 远程注册表 RPC 服务

1. WINLOGON 启动的完整路径

1.1 SMSS 启动 WINLOGON

复制代码
SMSS _main()
  │
  ├─ SmpInit()                    ← SMSS 自身初始化
  │   └─ SmpLoadSubSystemsForMuSession()
  │       ├─ 创建会话 0
  │       ├─ 加载 win32k.sys
  │       └─ 启动 CSRSS (csrss.exe)
  │
  └─ SmpExecuteInitialCommand(0, "winlogon.exe", Handles[1], NULL)
      ├─ SmConnectToSm(\SmApiPort)                  ← 连接 SMSS 的 LPC 端口
      ├─ SmpExecuteImage(winlogon.exe, DEFERRED)     ← 创建 WINLOGON (挂起)
      └─ SmExecPgm() → SmpExecPgm() → SmpSbCreateSession()
           ├─ SmpLocateKnownSubSysByType() → 找 CSRSS
           ├─ NtDuplicateObject() → 传递句柄到 CSRSS
           ├─ SmpAllocateSessionId() → 分配会话 1
           ├─ NtRequestWaitReplyPort(SbpCreateSession) → CSRSS 创建会话 1
           └─ NtResumeThread(WINLOGON)              ← ★ WINLOGON 开始运行

1.2 与 SMSS 的关系

复制代码
SMSS ←→ CSRSS = 通过 \SmApiPort (LPC) 和 SbApiPort 双向通信
SMSS → WINLOGON = 创建进程 + SmExecPgm LPC 消息(含会话创建)
WINLOGON → SMSS = 不直接通信 (通过 CSRSS 间接)
     |
     v
SMSS 在 _main 末尾:
  NtWaitForMultipleObjects(CSRSS_Handle, WINLOGON_Handle)
  └─ 任一终止 → SmpTerminate() → 系统关闭

2. WinMain --- 初始化序列

文件winlogon.c#L431(file:///d:/reactos/base/system/winlogon/winlogon.c#L431)

复制代码
WinMain()
  │
  ├─ 1. RtlSetProcessIsCritical(TRUE)         ← 标记为关键进程
  ├─ 2. RtlSetThreadIsCritical(TRUE)           ← 线程也为关键
  │
  ├─ 3. UpdateTcpIpInformation()              ← 更新 TCP/IP 主机名
  │
  ├─ ★ 4. RegisterLogonProcess()              ← 注册到 win32k.sys + CSRSS
  │
  ├─ 5. 分配并初始化 WLSession 结构体
  │
  ├─ ★ 6. CreateWindowStationAndDesktops()     ← ★ 创建 WinSta0 + 三个桌面
  │
  ├─ 7. InitKeyboardLayouts()                 ← 加载键盘布局
  │
  ├─ 8. StartRpcServer()                      ← 启动远程注册表 RPC
  │
  ├─ ★ 9. StartServicesManager()              ← ★ 启动 services.exe (SCM)
  │
  ├─ ★ 10. StartLsass()                       ← ★ 启动 lsass.exe (LSA)
  │
  ├─ 11. WaitForLsass()                       ← 等待 LSA 事件
  │
  ├─ 12. InitNotifications()                  ← 加载通知包
  │
  ├─ ★ 13. GinaInit(msgina.dll)               ← ★ 加载 GINA DLL
  │
  ├─ 14. CallNotificationDlls(Startup)        ← 发送启动通知
  │
  ├─ ★ 15. InitializeSAS()                    ← ★ 创建 SAS 窗口 + 注册热键
  │
  ├─ 16. 检查安装模式 (GetSetupType())
  │
  └─ 17. NtInitializeRegistry()               ← 标记 ControlSet 有效
  │
  └─ 18. 进入消息循环 (GetMessage/DispatchMessage)

3. 注册到 Win32 子系统 --- 三步注册

3.1 注册到内核模式 win32k.sys

复制代码
WinMain()
  └─ RegisterLogonProcess(GetCurrentProcessId(), TRUE)     [winlogon.c:463]
       └─ user32!RegisterLogonProcess()                    [logon.c:43]
            ├─ NtUserRegisterLogonProcess() → 系统调用进入 win32k.sys
            │   └─ co_IntRegisterLogonProcess()             [simplecall.c:18]
            │       └─ gpidLogon = PID                      [simplecall.c:40]
            │          ← win32k 全局变量记录登录进程 PID
            │
            └─ CsrClientCallServer(UserpRegisterLogonProcess) → 发到 CSRSS
                 └─ CSRSS!SrvRegisterLogonProcess()          [register.c:30]
                      └─ LogonProcessId = WINLOGON PID

3.2 注册 SAS 通知窗口

复制代码
InitializeSAS()                                          [sas.c:1740]
  └─ CreateWindow("SAS Window class", "SAS window", WS_POPUP, ...)
  └─ SetLogonNotifyWindow(Session->SASWindow)            [sas.c:1786]
       └─ user32!SetLogonNotifyWindow(hWnd)
            └─ NtUserSetLogonNotifyWindow() → win32k.sys  [winsta.c:1963]
                 └─ gspm.hwndSAS = hWnd                   [winsta.c:1978]
                    ← win32k 全局变量记录 SAS 窗口句柄

3.3 注册热键

复制代码
InitializeSAS()                                          [sas.c:1740]
  └─ RegisterHotKeys(SASWindow, ...)                     [sas.c:1437]
       ├─ Ctrl+Alt+Del    → IDHK_CTRL_ALT_DEL (0)   ← SAS 触发
       ├─ Ctrl+Shift+Esc  → IDHK_CTRL_SHIFT_ESC (1) ← 任务管理器
       ├─ Win+L           → IDHK_WIN_L (2)          ← 锁定工作站
       └─ Win+U           → IDHK_WIN_U (3)          ← 辅助工具管理器

4. 创建窗口站和桌面

文件wlx.c#L953(file:///d:/reactos/base/system/winlogon/wlx.c#L953)

这是 WINLOGON 最关键的初始化操作之一。它创建了所有 Win32 应用程序运行的窗口环境。

复制代码
CreateWindowStationAndDesktops()
  │
  ├─ 1. CreateWinstaSecurity()                         [security.c:112]
  │     权限: SYSTEM(全部), Administrators(受限)
  │
  ├─ 2. CreateWindowStationW(L"WinSta0", ...)          [wlx.c:1010]
  │     → 创建 WinSta0 窗口站
  │
  ├─ 3. SetProcessWindowStation(WinSta0)              [wlx.c:1021]
  │     → 将 WINLOGON 进程关联到 WinSta0
  │
  ├─ 4. 创建三个桌面的安全描述符                       [security.c:359-854]
  │
  ├─ 5. CreateDesktopW("Default", ...)                 [wlx.c:1030]
  │     → 创建 Default 桌面 (应用程序桌面)
  │
  ├─ 6. CreateDesktopW("Winlogon", ...)                [wlx.c:1046]
  │     → 创建 Winlogon 桌面 (安全桌面)
  │
  ├─ 7. CreateDesktopW("Screen-Saver", ...)            [wlx.c:1062]
  │     → 创建 Screen-Saver 桌面
  │
  ├─ 8. SetThreadDesktop(Winlogon)                     [wlx.c:1078]
  ├─ 9. SwitchDesktop(Winlogon)                        [wlx.c:1079]
  │     → ★ 切换到 Winlogon 安全桌面
  │
  └─ 10. SetWindowStationUser(...)                     [wlx.c:1085]

三个桌面

桌面 用途 安全权限
Winlogon 安全桌面 --- 登录界面 SYSTEM(全部), Administrators(受限)
Default 应用程序桌面 --- 用户日常工作 SYSTEM(全部), 用户(全部)
Screen-Saver 屏幕保护桌面 SYSTEM(全部), Interactive(受限)

登录后,AllowAccessOnSessionsecurity.c#L1391(file:///d:/reactos/base/system/winlogon/security.c#L1391))为当前登录用户授予 WinSta0 和 Default 桌面的访问权限。


5. 启动关键系统进程

5.1 启动服务管理器 (services.exe)

文件winlogon.c#L46(file:///d:/reactos/base/system/winlogon/winlogon.c#L46)

c 复制代码
static BOOL StartServicesManager(VOID)
{
    return CreateProcessW(L"services.exe", NULL, ...,
                          DETACHED_PROCESS, ...);
}

WinMain 第 508 行调用。SCM 以独立进程方式启动,负责管理系统服务。

5.2 启动 LSA (lsass.exe)

文件winlogon.c#L82(file:///d:/reactos/base/system/winlogon/winlogon.c#L82)

c 复制代码
static BOOL StartLsass(VOID)
{
    return CreateProcessW(L"lsass.exe", NULL, ...,
                          CREATE_SUSPENDED | DETACHED_PROCESS, ...);
}

创建后通过 WaitForLsass() 等待 LSA_RPC_SERVER_ACTIVE 事件,确保 LSA 已完成初始化后再继续。


6. GINA 接口

6.1 GINA DLL 定位

文件wlx.c#L779(file:///d:/reactos/base/system/winlogon/wlx.c#L779)

从注册表读取:

复制代码
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL

默认值:msgina.dll(ReactOS 内置)

6.2 GINA 函数表

文件wlx.c#L830(file:///d:/reactos/base/system/winlogon/wlx.c#L830)

GINA DLL 需导出的函数(按版本):

函数 版本 用途
WlxNegotiate v1.0 协商接口版本(可选)
WlxInitialize v1.0 初始化 GINA,接收 WINLOGON 分发表
WlxDisplaySASNotice v1.0 显示 SAS 提示(如"按 Ctrl+Alt+Del 登录")
WlxLoggedOutSAS v1.0 处理登录 SAS(显示登录对话框)
WlxActivateUserShell v1.0 激活用户 Shell(启动 explorer.exe)
WlxLoggedOnSAS v1.0 处理已登录时的 SAS
WlxDisplayLockedNotice v1.0 显示锁定提示
WlxWkstaLockedSAS v1.0 处理锁定状态的 SAS(解锁对话框)
WlxIsLockOk v1.0 检查是否允许锁定
WlxIsLogoffOk v1.0 检查是否允许注销
WlxLogoff v1.0 注销处理
WlxShutdown v1.0 关机处理
WlxScreenSaverNotify v1.1 屏保通知(可选)
WlxStartApplication v1.1 启动应用程序(可选)
WlxDisplayStatusMessage v1.3 显示状态消息
WlxGetStatusMessage v1.3 获取状态消息
WlxNetworkProviderLoad v1.3 网络提供者加载
WlxRemoveStatusMessage v1.3 移除状态消息

6.3 WINLOGON 分发表(提供给 GINA)

文件wlx.c#L747(file:///d:/reactos/base/system/winlogon/wlx.c#L747)

WINLOGON 暴露 27 个函数给 GINA:

函数 用途
WlxUseCtrlAltDel 启用/禁用 Ctrl+Alt+Del
WlxSetContextPointer 设置上下文指针
WlxSasNotify 发送 SAS 通知
WlxSetTimeout 设置对话框超时
WlxMessageBox 消息框
WlxDialogBox / WlxDialogBoxParam / WlxDialogBoxIndirect 对话框
WlxSwitchDesktopToUser 切换到 Default 桌面
WlxSwitchDesktopToWinlogon 切换到 Winlogon 桌面
WlxSetOption / WlxGetOption 选项管理
... 密码通知、桌面管理等

7. SAS 处理机制

7.1 SAS 触发路径

复制代码
用户按下 Ctrl+Alt+Del
  │
  ├─ 键盘驱动 → win32k.sys (MOD_WINLOGON_SAS 标志)
  │   └─ PostMessage(hwndSAS, WM_HOTKEY, IDHK_CTRL_ALT_DEL, ...)
  │
  └─ SASWindowProc()                                    [sas.c:1526]
       └─ PostMessage(SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0)
            └─ DispatchSAS()                            [sas.c:1322]
                 └─ 根据 LogonState 分发:
                      STATE_INIT         → GINA.WlxDisplaySASNotice()
                      STATE_LOGGED_OFF   → GINA.WlxLoggedOutSAS()
                      STATE_LOGGED_ON    → GINA.WlxLoggedOnSAS()
                      STATE_LOCKED       → GINA.WlxWkstaLockedSAS()

7.2 SAS 窗口

文件sas.c#L1526(file:///d:/reactos/base/system/winlogon/sas.c#L1526)

  • 窗口类 : "SAS Window class"(隐藏弹出窗口)
  • 窗口标题 : "SAS window"
  • 注册 : SetLogonNotifyWindow(SASWindow)gspm.hwndSAS
  • 消息处理 :
    • WM_HOTKEY → 转换为 SAS 事件或直接动作
    • WM_LOGONNOTIFY → 系统级通知(Shell退出、锁屏、注销等)
    • WLX_WM_SAS → 分发给 GINA

7.3 SAS 动作分发

文件sas.c#L1206(file:///d:/reactos/base/system/winlogon/sas.c#L1206)

GINA 返回 wlxAction 后,由 DoGenericAction 调度:

动作 处理
WLX_SAS_ACTION_LOGON HandleLogon() → 加载用户配置、启动 Shell
WLX_SAS_ACTION_LOGOFF HandleLogoff() → 卸载配置、杀死进程
WLX_SAS_ACTION_SHUTDOWN HandleLogoff() + HandleShutdown()
WLX_SAS_ACTION_LOCK_WKSTA 锁定工作站
WLX_SAS_ACTION_TASKLIST StartTaskManager()
WLX_SAS_ACTION_FORCE_LOGOFF 强制注销
WLX_SAS_ACTION_SHUTDOWN_REBOOT 重启
WLX_SAS_ACTION_SHUTDOWN_POWER_OFF 关机断电

8. 登录流程详解

复制代码
用户输入凭据 → GINA.WlxLoggedOutSAS() 返回 WLX_SAS_ACTION_LOGON
  │
  └─ DoGenericAction(WLX_SAS_ACTION_LOGON)
       └─ HandleLogon(Session)                         [sas.c:571]
            │
            ├─ 1. GINA.WlxLogoff()                    ← 清理旧会话
            │
            ├─ ★ 2. GINA.WlxLoggedOutSAS() 返回 WLX_SAS_ACTION_LOGON
            │      ↓ 用户凭据已验证
            │
            ├─ 3. LoadUserProfileW(hToken)             ← 加载用户配置文件
            ├─ 4. CreateEnvironmentBlock()              ← 创建环境块
            │
            ├─ 5. CallNotificationDlls(LogonHandler)   ← 登录通知
            │
            ├─ 6. CallNotificationDlls(StartShellHandler)
            │
            ├─ ★ 7. GINA.WlxActivateUserShell()        ← ★ 启动 Shell
            │     └─ msgina.dll 读取注册表:
            │         HKLM\...\Winlogon\Shell = "explorer.exe"
            │         → CreateProcessAsUser(hToken, "explorer.exe", ...)
            │
            ├─ 8. CallNotificationDlls(PostShellHandler)
            │
            ├─ 9. InitializeScreenSaver()               ← 初始化屏保
            │
            ├─ 10. SwitchDesktopToUser()                  ← 切换到 Default 桌面
            │
            └─ 11. LogonState = STATE_LOGGED_ON

9. 通知包机制

文件notify.c(file:///d:/reactos/base/system/winlogon/notify.c)

WINLOGON 提供可扩展的通知包机制,允许第三方软件获知登录/注销事件。

复制代码
InitNotifications()                                    [notify.c:417]
  │
  ├─ InitializeListHead(通知链表)
  ├─ AddSfcNotification()                        
  │   → sfc.dll: SfcWLEventLogon / SfcWLEventLogoff
  │
  └─ 枚举注册表:
      HKLM\...\Winlogon\Notify\*
        ├─ DllName = 通知 DLL 路径
        ├─ Logon / Logoff / Lock / Unlock 等处理函数
        ├─ Asynchronous / Impersonate / MaxWait 配置
        └─ → AddNotificationDll()                     [notify.c:467]

12 种通知类型

复制代码
LogonHandler       → 登录
LogoffHandler      → 注销
LockHandler        → 锁定
UnlockHandler      → 解锁
StartupHandler     → 系统启动
ShutdownHandler     → 系统关闭
StartScreenSaverHandler → 启动屏保
StopScreenSaverHandler  → 停止屏保
DisconnectHandler  → 断开连接
ReconnectHandler   → 重新连接
StartShellHandler  → 启动 Shell
PostShellHandler   → Shell 启动后

10. 完整交互架构图

复制代码
  ┌─────────────────────────────────────────────────────────────────┐
  │                     用户模式                                      │
  │                                                                   │
  │  ┌────────────┐   ┌────────────┐   ┌────────────┐                │
  │  │   SMSS     │   │   CSRSS    │   │  WINLOGON  │                │
  │  │            │   │            │   │            │                │
  │  │ 启动进程    │   │ Win32 API  │   │ WinSta0    │                │
  │  │ 管理会话    │   │ 控制台     │   │ 三个桌面    │                │
  │  │ \SmApiPort │   │ 硬错误     │   │ SAS 处理    │                │
  │  └─────┬──────┘   └─────┬──────┘   └──────┬─────┘                │
  │        │                │                 │                       │
  │        │  LPC           │  LPC            │                       │
  │        │  (SbApiPort)   │  (ApiPort)      │                       │
  │        └────────────────┼─────────────────┘                       │
  │                         │                                         │
  │                    ┌────┴──────┐                                  │
  │                    │ 用户进程   │                                  │
  │                    │ explorer   │                                  │
  │                    │ notepad    │                                  │
  │                    └───────────┘                                  │
  │                         │                                         │
  │                         │ system call (0x1XXX)                    │
  ├─────────────────────────┼─────────────────────────────────────────┤
  │                    内核模式                                        │
  │                         │                                         │
  │                    ┌────┴──────────────────────────────────────┐  │
  │                    │         win32k.sys                         │  │
  │                    │  ┌──────────────┐ ┌─────────────────────┐  │  │
  │                    │  │  USER 子系统  │ │ GDI 子系统          │  │  │
  │                    │  │              │ │                     │  │  │
  │                    │  │ 窗口管理      │ │ 绘图/字体/调色板    │  │  │
  │                    │  │ 消息路由      │ │ 设备上下文(DC)      │  │  │
  │                    │  │ 输入处理      │ │ 位图/画刷/区域      │  │  │
  │                    │  │              │ │                     │  │  │
  │                    │  │ gpidLogon    │ │                     │  │  │
  │                    │  │   = WINLOGON │ │                     │  │  │
  │                    │  │ hwndSAS =    │ │                     │  │  │
  │                    │  │   SAS 窗口   │ │                     │  │  │
  │                    │  └──────────────┘ └─────────────────────┘  │  │
  │                    └─────────────────────────────────────────────┘  │
  └─────────────────────────────────────────────────────────────────┘

11. 四者关系总结

启动顺序

复制代码
SMSS ──(SystemSessionCreate)──→ 创建会话 0
SMSS ──(ExtendServiceTable)───→ 加载 win32k.sys
SMSS ──(CreateProcess)────────→ CSRSS
  │                              │
  │   ──(LPC 连接互认)──────────────→ CSRSS 开始运行
  │
SMSS ──(CreateProcess DEFERRED)→ WINLOGON
  │   ──(LPC: SbpCreateSession)─→ CSRSS: 创建会话 1
  │   ──(ResumeThread)──────────→ WINLOGON 开始运行
  │
SMSS ←→ CSRSS = LPC 双向通信 (\SmApiPort / SbApiPort)
SMSS ←→ WINLOGON = 间接通信 (通过 CSRSS)

角色职责

进程 作用 与 WINLOGON 的关系
SMSS 会话管理器,系统引导第二阶段 启动 WINLOGON(挂起 → LPC 会话创建 → 恢复)
CSRSS Win32 子系统服务器端 注册登录进程、会话创建、LPC API 服务
win32k.sys 内核模式窗口/图形子系统 记录登录 PID(gpidLogon)、接收 SAS 热键、桌面管理
WINLOGON 用户登录管理 创建 WinSta0/桌面、加载 GINA、启动 Shell/SCM/LSA

关键注册点

复制代码
WINLOGON → win32k.sys:  RegisterLogonProcess → gpidLogon = PID
WINLOGON → win32k.sys:  SetLogonNotifyWindow → hwndSAS = SAS Window
WINLOGON → CSRSS:       SrvRegisterLogonProcess
WINLOGON → CSRSS:       SrvLogon (GINA 登录成功后)

设计要点

概念 说明
关键进程 RtlSetProcessIsCritical(TRUE),终止即蓝屏
安全桌面 Winlogon 桌面隔离登录界面,防止应用程序窃取密码
SAS 独占 Ctrl+Alt+Del 由 win32k 捕获后发给 WINLOGON,用户程序无法拦截
GINA 可替换 通过注册表 GinaDLL 可替换为自定义登录界面
通知包 HKLM\...\Winlogon\Notify 允许第三方注册登录/注销回调
Shell 独立 WINLOGON 不直接管理 Shell(通过 GINA 代理),崩溃后自动重启
状态机 STATE_INIT → LOGGED_OFF → LOGGED_ON → LOCKED 等 10+ 个状态
相关推荐
caimouse1 小时前
Chrome V49 (49.0.2623.112) 在 ReactOS 上运行所需的系统依赖
chrome·reactos
caimouse2 小时前
Windows 内存管理概念详解
reactos
caimouse7 小时前
MM 学习笔记 01:miarm.h 核心头文件分析
笔记·学习·reactos
caimouse14 小时前
Chrome V49 SxS 加载问题分析与修复
chrome·reactos
caimouse16 小时前
mm学习笔记_04:VAD树算法与地址空间分配
笔记·学习·算法·reactos
caimouse1 天前
KPRCB 结构分析与调度流程
reactos
caimouse2 天前
ReactOS.exe 安装程序分析
reactos
caimouse3 天前
Phase1Initialization 函数分析
单片机·嵌入式硬件·reactos
caimouse4 天前
ReactOS bootcd.iso 引导到桌面显示过程分析
reactos