fix(agent): spawn helper on winsta0\\Winlogon when console session is… #9

Merged
HexC0d3rz merged 1 commit from fix/winlogon-input-desktop-attach into main 2026-06-22 12:20:28 -04:00
HexC0d3rz commented 2026-06-22 12:19:50 -04:00 (Migrated from github.com)

… locked

Symptom (reported by user 2026-06-22): "after I remote in while on the desktop and then press the lock button, I cant see the password screen".

Root cause was a two-layer bug in the desktop attach path:

  1. The spawner hardcoded STARTUPINFOW.lpDesktop to "winsta0\default" regardless of session state. When the workstation is locked the helper is born on the user's Default desktop (which shows the lock-screen wallpaper only — NOT the Winlogon password UI).

  2. attach_to_interactive_desktop() called OpenInputDesktop(0, 0, ...) without DF_ALLOWOTHERACCOUNTHOOK. With no flag, OpenInputDesktop returns the calling thread's own desktop (Default), not the live input desktop of the console session (Winlogon). So SetThreadDesktop was effectively a no-op.

    Helper log showed: thread_desk="Winlogon" input_desk="Default" desk_match=NO — capture frame comes from Winlogon but SendInput clicks land on the wallpaper behind it. Operator sees the lock wallpaper but cannot interact with the password field.

Fix:

  • Spawner now sets lpDesktop to "winsta0\Winlogon" when console_is_locked, and mirrors the desktop name into a new ZENO_HELPER_DESKTOP env var so the helper can use it as an explicit fallback target.
  • attach_to_interactive_desktop() now passes DF_ALLOWOTHERACCOUNTHOOK (0x1) to OpenInputDesktop so it returns the live input desktop.
  • New Win11 23H2+ fallback: if OpenInputDesktop still returns NULL with ACCESS_DENIED (some hardened builds), call OpenDesktopW on the Winlogon desktop by name — only when ZENO_HELPER_DESKTOP says we're on the locked path (never blind-open Winlogon otherwise).

Regression coverage (compile-time assertions, run on WIN-GAME-SRV CI):

  • spawn_desktop_name_matches_session_state: locks the locked/unlocked decision table
  • df_allowotheracccounthook_is_one: pins the DF_ALLOWOTHERACCOUNTHOOK flag value so a future windows-sys upgrade can't silently break it
  • helper_desktop_env_var_name_is_stable: locks the spawner ↔ helper env var contract

Reference doc: docs/remote-desktop-locked-state.md captures the full pipeline, the bug history (5 prior fixes on the same subsystem), the manual verification procedure on a live locked workstation, and the symptom-to-cause table for future debugging.

Verified against helper log from WIN11--LAB-VM session b68158f4-... (15:41:37 on 2026-06-22) — pre-fix showed desk_match=NO with thread_desk="Winlogon" input_desk="Default", exactly the symptom described.

… locked Symptom (reported by user 2026-06-22): "after I remote in while on the desktop and then press the lock button, I cant see the password screen". Root cause was a two-layer bug in the desktop attach path: 1. The spawner hardcoded STARTUPINFOW.lpDesktop to "winsta0\\default" regardless of session state. When the workstation is locked the helper is born on the user's Default desktop (which shows the lock-screen wallpaper only — NOT the Winlogon password UI). 2. attach_to_interactive_desktop() called OpenInputDesktop(0, 0, ...) without DF_ALLOWOTHERACCOUNTHOOK. With no flag, OpenInputDesktop returns the *calling thread's own desktop* (Default), not the *live* input desktop of the console session (Winlogon). So SetThreadDesktop was effectively a no-op. Helper log showed: thread_desk="Winlogon" input_desk="Default" desk_match=NO — capture frame comes from Winlogon but SendInput clicks land on the wallpaper behind it. Operator sees the lock wallpaper but cannot interact with the password field. Fix: - Spawner now sets lpDesktop to "winsta0\\Winlogon" when console_is_locked, and mirrors the desktop name into a new ZENO_HELPER_DESKTOP env var so the helper can use it as an explicit fallback target. - attach_to_interactive_desktop() now passes DF_ALLOWOTHERACCOUNTHOOK (0x1) to OpenInputDesktop so it returns the live input desktop. - New Win11 23H2+ fallback: if OpenInputDesktop still returns NULL with ACCESS_DENIED (some hardened builds), call OpenDesktopW on the Winlogon desktop by name — only when ZENO_HELPER_DESKTOP says we're on the locked path (never blind-open Winlogon otherwise). Regression coverage (compile-time assertions, run on WIN-GAME-SRV CI): - spawn_desktop_name_matches_session_state: locks the locked/unlocked decision table - df_allowotheracccounthook_is_one: pins the DF_ALLOWOTHERACCOUNTHOOK flag value so a future windows-sys upgrade can't silently break it - helper_desktop_env_var_name_is_stable: locks the spawner ↔ helper env var contract Reference doc: docs/remote-desktop-locked-state.md captures the full pipeline, the bug history (5 prior fixes on the same subsystem), the manual verification procedure on a live locked workstation, and the symptom-to-cause table for future debugging. Verified against helper log from WIN11--LAB-VM session b68158f4-... (15:41:37 on 2026-06-22) — pre-fix showed desk_match=NO with thread_desk="Winlogon" input_desk="Default", exactly the symptom described.
Sign in to join this conversation.
No description provided.