From 232ab26ec57d42cc9b95f5d96658e46dcd2dc1d8 Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Tue, 6 Aug 2024 14:47:18 -0700 Subject: [PATCH] Launch app into Winlogon desktop when LogonUI.exe or consent.exe is present in the target session. --- Agent/Services/Windows/AppLauncherWin.cs | 6 -- Desktop.Native/Windows/Win32Interop.cs | 73 +++++++++++++------ .../Startup/IServiceProviderExtensions.cs | 2 - 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/Agent/Services/Windows/AppLauncherWin.cs b/Agent/Services/Windows/AppLauncherWin.cs index bd3775992..13387ce54 100644 --- a/Agent/Services/Windows/AppLauncherWin.cs +++ b/Agent/Services/Windows/AppLauncherWin.cs @@ -49,8 +49,6 @@ public async Task LaunchChatService(string pipeName, string userConnectionI $" --org-name \"{orgName}\"" + $" --org-id \"{orgId}\"", targetSessionId: -1, - forceConsoleSession: false, - desktopName: "default", hiddenWindow: false, out var procInfo); if (!result) @@ -122,8 +120,6 @@ await hubConnection.SendAsync("DisplayMessage", $" --session-id \"{sessionId}\"" + $" --access-key \"{accessKey}\"", targetSessionId: targetSessionId, - forceConsoleSession: Shlwapi.IsOS(OsType.OS_ANYSERVER) && targetSessionId == -1, - desktopName: "default", hiddenWindow: false, out _); if (!result) @@ -180,8 +176,6 @@ public async Task RestartScreenCaster(string[] viewerIds, string sessionId, stri $" --viewers {string.Join(",", viewerIds)}", targetSessionId: targetSessionID, - forceConsoleSession: Shlwapi.IsOS(OsType.OS_ANYSERVER) && targetSessionID == -1, - desktopName: "default", hiddenWindow: false, out _); diff --git a/Desktop.Native/Windows/Win32Interop.cs b/Desktop.Native/Windows/Win32Interop.cs index c565a3f60..873e6e044 100644 --- a/Desktop.Native/Windows/Win32Interop.cs +++ b/Desktop.Native/Windows/Win32Interop.cs @@ -104,11 +104,9 @@ public static nint OpenInputDesktop() public static bool CreateInteractiveSystemProcess( string commandLine, - int targetSessionId, - bool forceConsoleSession, - string desktopName, - bool hiddenWindow, - out PROCESS_INFORMATION procInfo) + int targetSessionId, + bool hiddenWindow, + out PROCESS_INFORMATION procInfo) { uint winlogonPid = 0; var hUserTokenDup = nint.Zero; @@ -117,21 +115,7 @@ public static bool CreateInteractiveSystemProcess( procInfo = new PROCESS_INFORMATION(); - // If not force console, find target session. If not present, - // use last active session. - var dwSessionId = Kernel32.WTSGetActiveConsoleSessionId(); - if (!forceConsoleSession) - { - var activeSessions = GetActiveSessions(); - if (activeSessions.Any(x => x.Id == targetSessionId)) - { - dwSessionId = (uint)targetSessionId; - } - else - { - dwSessionId = activeSessions.Last().Id; - } - } + var dwSessionId = ResolveWindowsSession(targetSessionId); // Obtain the process ID of the winlogon process that is running within the currently active session. var processes = Process.GetProcessesByName("winlogon"); @@ -171,7 +155,7 @@ public static bool CreateInteractiveSystemProcess( // interaction with the new process. var si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); - si.lpDesktop = @"winsta0\" + desktopName; + si.lpDesktop = @"winsta0\" + ResolveDesktopName(dwSessionId); // Flags that specify the priority and creation method of the process. uint dwCreationFlags; @@ -208,6 +192,53 @@ public static bool CreateInteractiveSystemProcess( return result; } + public static string ResolveDesktopName(uint targetSessionId) + { + var winDir = Environment.GetFolderPath(Environment.SpecialFolder.Windows); + var logonUiPath = Path.Combine(winDir, "System32", "LogonUI.exe"); + var consentPath = Path.Combine(winDir, "System32", "consent.exe"); + + var isLogonScreenVisible = Process + .GetProcessesByName("LogonUI") + .Any(x => x.SessionId == targetSessionId && x.MainModule?.FileName.Equals(logonUiPath, StringComparison.OrdinalIgnoreCase) == true); + + var isSecureDesktopVisible = Process + .GetProcessesByName("consent") + .Any(x => x.SessionId == targetSessionId && x.MainModule?.FileName.Equals(consentPath, StringComparison.OrdinalIgnoreCase) == true); + + if (isLogonScreenVisible || isSecureDesktopVisible) + { + return "Winlogon"; + } + + return "Default"; + } + + public static uint ResolveWindowsSession(int targetSessionId) + { + var activeSessions = GetActiveSessions(); + if (activeSessions.Any(x => x.Id == targetSessionId)) + { + // If exact match is found, return that session. + return (uint)targetSessionId; + } + + if (Shlwapi.IsOS(OsType.OS_ANYSERVER)) + { + // If Windows Server, default to console session. + return Kernel32.WTSGetActiveConsoleSessionId(); + } + + // If consumer version and there's an RDP session active, return that. + if (activeSessions.Find(x => x.Type == WindowsSessionType.RDP) is { } rdSession) + { + return rdSession.Id; + } + + // Otherwise, return the console session. + return Kernel32.WTSGetActiveConsoleSessionId(); + } + public static void SetMonitorState(MonitorState state) { SendMessage(0xFFFF, 0x112, 0xF170, (int)state); diff --git a/Desktop.Shared/Startup/IServiceProviderExtensions.cs b/Desktop.Shared/Startup/IServiceProviderExtensions.cs index de8e3ed37..2cee44933 100644 --- a/Desktop.Shared/Startup/IServiceProviderExtensions.cs +++ b/Desktop.Shared/Startup/IServiceProviderExtensions.cs @@ -154,8 +154,6 @@ private static void RelaunchElevated() commandLine, -1, false, - "default", - true, out var procInfo); Console.WriteLine($"Elevate result: {result}. Process ID: {procInfo.dwProcessId}."); Environment.Exit(0);