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(受限) |
登录后,AllowAccessOnSession(security.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+ 个状态 |