From a2999ecdbac9f91f10133d74c3a01b685507c0eb Mon Sep 17 00:00:00 2001 From: Jared Goodwin Date: Thu, 23 Apr 2020 14:23:56 -0700 Subject: [PATCH] Add target session ID. --- Agent/Services/AppLauncher.cs | 30 ++++++++-- Agent/Services/DeviceSocket.cs | 2 +- Agent/Services/WindowsService.cs | 7 ++- .../Desktop.Win.Wrapper.csproj | 5 ++ Desktop.Win/App.xaml.cs | 2 + Shared/Win32/Shlwapi.cs | 55 +++++++++++++++++++ Shared/Win32/Win32Interop.cs | 26 +++++++-- 7 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 Shared/Win32/Shlwapi.cs diff --git a/Agent/Services/AppLauncher.cs b/Agent/Services/AppLauncher.cs index d16b3589..0e6bf645 100644 --- a/Agent/Services/AppLauncher.cs +++ b/Agent/Services/AppLauncher.cs @@ -42,7 +42,12 @@ namespace Remotely.Agent.Services } else { - var result = Win32Interop.OpenInteractiveProcess($"{rcBinaryPath} -mode Chat -requester {requesterID} -organization \"{orgName}\"", "default", false, out var procInfo); + var result = Win32Interop.OpenInteractiveProcess($"{rcBinaryPath} -mode Chat -requester {requesterID} -organization \"{orgName}\"", + targetSessionId: -1, + forceConsoleSession: false, + desktopName: "default", + hiddenWindow: false, + out var procInfo); if (!result) { await hubConnection.SendAsync("DisplayMessage", "Remote control failed to start on target device.", "Failed to start remote control.", requesterID); @@ -67,7 +72,7 @@ namespace Remotely.Agent.Services return -1; } - public async Task LaunchRemoteControl(string requesterID, string serviceID, HubConnection hubConnection) + public async Task LaunchRemoteControl(int targetSessionId, string requesterID, string serviceID, HubConnection hubConnection) { try { @@ -90,7 +95,12 @@ namespace Remotely.Agent.Services } else { - var result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -deviceid {ConnectionInfo.DeviceID} -host {ConnectionInfo.Host}", "default", true, out _); + var result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -deviceid {ConnectionInfo.DeviceID} -host {ConnectionInfo.Host}", + targetSessionId: targetSessionId, + forceConsoleSession: false, + desktopName: "default", + hiddenWindow: true, + out _); if (!result) { await hubConnection.SendAsync("DisplayMessage", "Remote control failed to start on target device.", "Failed to start remote control.", requesterID); @@ -128,13 +138,23 @@ namespace Remotely.Agent.Services // Give a little time for session changing, etc. await Task.Delay(1000); - var result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -deviceid {ConnectionInfo.DeviceID} -host {ConnectionInfo.Host} -relaunch true -viewers {String.Join(",", viewerIDs)}", "default", true, out _); + var result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -deviceid {ConnectionInfo.DeviceID} -host {ConnectionInfo.Host} -relaunch true -viewers {String.Join(",", viewerIDs)}", + targetSessionId: -1, + forceConsoleSession: Shlwapi.IsOS(OsType.OS_ANYSERVER) ? true : false, + desktopName: "default", + hiddenWindow: true, + out _); if (!result) { await Task.Delay(1000); // Try one more time. - result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -deviceid {ConnectionInfo.DeviceID} -host {ConnectionInfo.Host} -relaunch true -viewers {String.Join(",", viewerIDs)}", "default", true, out _); + result = Win32Interop.OpenInteractiveProcess(rcBinaryPath + $" -mode Unattended -requester {requesterID} -serviceid {serviceID} -deviceid {ConnectionInfo.DeviceID} -host {ConnectionInfo.Host} -relaunch true -viewers {String.Join(",", viewerIDs)}", + targetSessionId: -1, + forceConsoleSession: Shlwapi.IsOS(OsType.OS_ANYSERVER) ? true : false, + desktopName: "default", + hiddenWindow: true, + out _); if (!result) { diff --git a/Agent/Services/DeviceSocket.cs b/Agent/Services/DeviceSocket.cs index 0c104075..76173dca 100644 --- a/Agent/Services/DeviceSocket.cs +++ b/Agent/Services/DeviceSocket.cs @@ -223,7 +223,7 @@ namespace Remotely.Agent.Services Uninstaller.UninstallAgent(); return; } - await AppLauncher.LaunchRemoteControl(requesterID, serviceID, HubConnection); + await AppLauncher.LaunchRemoteControl(-1, requesterID, serviceID, HubConnection); }); HubConnection.On("RestartScreenCaster", async (List viewerIDs, string serviceID, string requesterID) => { diff --git a/Agent/Services/WindowsService.cs b/Agent/Services/WindowsService.cs index dd25ba40..9b4359bb 100644 --- a/Agent/Services/WindowsService.cs +++ b/Agent/Services/WindowsService.cs @@ -24,8 +24,11 @@ namespace Remotely.Agent.Services foreach (var screenCaster in Process.GetProcessesByName("Remotely_ScreenCast")) { - Logger.Write($"Session changed. Kill process ID {screenCaster.Id}."); - screenCaster.Kill(); + if (screenCaster.SessionId == changeDescription.SessionId) + { + Logger.Write($"Session changed. Kill process ID {screenCaster.Id}."); + screenCaster.Kill(); + } } } base.OnSessionChange(changeDescription); diff --git a/Desktop.Win.Wrapper/Desktop.Win.Wrapper.csproj b/Desktop.Win.Wrapper/Desktop.Win.Wrapper.csproj index 1cd01cd2..98848ef9 100644 --- a/Desktop.Win.Wrapper/Desktop.Win.Wrapper.csproj +++ b/Desktop.Win.Wrapper/Desktop.Win.Wrapper.csproj @@ -152,4 +152,9 @@ + + if $(ConfigurationName) == Debug ( + echo > $(ProjectDir)Remotely_Desktop.zip +) + \ No newline at end of file diff --git a/Desktop.Win/App.xaml.cs b/Desktop.Win/App.xaml.cs index 275cbcad..27b39b73 100644 --- a/Desktop.Win/App.xaml.cs +++ b/Desktop.Win/App.xaml.cs @@ -30,6 +30,8 @@ namespace Remotely.Desktop.Win Logger.Write($"Elevating process {filePath}."); var result = Win32Interop.OpenInteractiveProcess( filePath, + -1, + false, "default", false, out var procInfo); diff --git a/Shared/Win32/Shlwapi.cs b/Shared/Win32/Shlwapi.cs new file mode 100644 index 00000000..1e4c5275 --- /dev/null +++ b/Shared/Win32/Shlwapi.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace Remotely.Shared.Win32 +{ + // https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-isos + public class Shlwapi + { + [DllImport("shlwapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsOS(OsType osType); + } + + public enum OsType + { + OS_WINDOWS = 0, + OS_NT = 1, + OS_WIN95ORGREATER = 2, + OS_NT4ORGREATER = 3, + OS_WIN98ORGREATER = 5, + OS_WIN98_GOLD = 6, + OS_WIN2000ORGREATER = 7, + OS_WIN2000PRO = 8, + OS_WIN2000SERVER = 9, + OS_WIN2000ADVSERVER = 10, + OS_WIN2000DATACENTER = 11, + OS_WIN2000TERMINAL = 12, + OS_EMBEDDED = 13, + OS_TERMINALCLIENT = 14, + OS_TERMINALREMOTEADMIN = 15, + OS_WIN95_GOLD = 16, + OS_MEORGREATER = 17, + OS_XPORGREATER = 18, + OS_HOME = 19, + OS_PROFESSIONAL = 20, + OS_DATACENTER = 21, + OS_ADVSERVER = 22, + OS_SERVER = 23, + OS_TERMINALSERVER = 24, + OS_PERSONALTERMINALSERVER = 25, + OS_FASTUSERSWITCHING = 26, + OS_WELCOMELOGONUI = 27, + OS_DOMAINMEMBER = 28, + OS_ANYSERVER = 29, + OS_WOW6432 = 30, + OS_WEBSERVER = 31, + OS_SMALLBUSINESSSERVER = 32, + OS_TABLETPC = 33, + OS_SERVERADMINUI = 34, + OS_MEDIACENTER = 35, + OS_APPLIANCE = 36, + } +} diff --git a/Shared/Win32/Win32Interop.cs b/Shared/Win32/Win32Interop.cs index 2c8984a0..52ac8bf8 100644 --- a/Shared/Win32/Win32Interop.cs +++ b/Shared/Win32/Win32Interop.cs @@ -98,15 +98,33 @@ namespace Remotely.Shared.Win32 { return User32.OpenInputDesktop(0, true, ACCESS_MASK.GENERIC_ALL); } - public static bool OpenInteractiveProcess(string applicationName, string desktopName, bool hiddenWindow, out PROCESS_INFORMATION procInfo) + + public static bool OpenInteractiveProcess(string applicationName, + int targetSessionId, + bool forceConsoleSession, + string desktopName, + bool hiddenWindow, + out PROCESS_INFORMATION procInfo) { uint winlogonPid = 0; IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; procInfo = new PROCESS_INFORMATION(); - // Check for RDP session. If active, use that session ID instead. - var activeSessions = GetActiveSessions(); - var dwSessionId = activeSessions.Last().ID; + // 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; + } + } // Obtain the process ID of the winlogon process that is running within the currently active session. Process[] processes = Process.GetProcessesByName("winlogon");