Пример #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="startInfo"></param>
        /// <returns></returns>
        internal static bool LaunchUriDeferred(WardenStartInfo startInfo)
        {
            var(fileName, arguments, workingDirectory) = ValidateUri(startInfo);
            if (startInfo.AsUser)
            {
                if (Api.StartProcessAndBypassUac(fileName, arguments, workingDirectory, out _))
                {
                    return(true);
                }

                throw new WardenLaunchException(string.Format(Resources.Exception_Process_Not_Start, startInfo.FileName, startInfo.Arguments));
            }

            var processStartInfo = new ProcessStartInfo
            {
                FileName         = fileName,
                Arguments        = arguments,
                WorkingDirectory = workingDirectory,
                UseShellExecute  = true
            };

            using (var process = Process.Start(processStartInfo))
            {
                if (process == null)
                {
                    throw new WardenLaunchException(string.Format(Resources.Exception_Process_Not_Start, startInfo.FileName, startInfo.Arguments));
                }
            }
            return(true);
        }
Пример #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="startInfo"></param>
        /// <returns></returns>
        internal static WardenProcess LaunchWin32App(WardenStartInfo startInfo)
        {
            if (!new FileInfo(startInfo.FileName).Exists)
            {
                throw new WardenLaunchException($"Unable to launch {startInfo.FileName} -- the file is missing.");
            }
            if (startInfo.AsUser)
            {
                if (!Api.StartProcessAndBypassUac(startInfo.FileName, startInfo.Arguments, startInfo.WorkingDirectory, out var procInfo))
                {
                    throw new WardenLaunchException(string.Format(Resources.Exception_Process_Not_Start, startInfo.FileName, startInfo.Arguments));
                }
                return(WardenProcess.GetProcessFromId((int)procInfo.dwProcessId, startInfo.Filters));
            }
            var processStartInfo = new ProcessStartInfo
            {
                FileName         = startInfo.FileName,
                Arguments        = startInfo.Arguments,
                WorkingDirectory = startInfo.WorkingDirectory,
                UseShellExecute  = true
            };

            using (var process = Process.Start(processStartInfo))
            {
                if (process == null)
                {
                    throw new WardenLaunchException(Resources.Exception_Process_Not_Launched_Unknown);
                }
                return(WardenProcess.GetProcessFromId(process.Id, startInfo.Filters));
            }
        }
Пример #3
0
        /// <summary>
        /// Combines the Package Family Name and Application ID into a valid AUMID string and then launches the app.
        /// </summary>
        /// <param name="startInfo"></param>
        /// <returns>If the app is launched successfully a WardenProcess is returned.</returns>
        internal static WardenProcess LaunchApp(WardenStartInfo startInfo)
        {
            var aumid     = $"{startInfo.PackageFamilyName}!{startInfo.ApplicationId}";
            var processId = Launch(aumid, startInfo.Arguments);

            if (processId <= 0)
            {
                throw new WardenLaunchException(string.Format(Resources.Exception_Could_Not_Find_Process_Id, aumid));
            }
            return(WardenProcess.GetProcessFromId(processId, startInfo.Filters));
        }
Пример #4
0
        /// <summary>
        /// Launches an application URI Scheme and waits for the target process to appear
        /// </summary>
        /// <param name="startInfo"></param>
        /// <param name="cancelToken">A cancellation token to configure how long Warden will wait.</param>
        /// <returns></returns>
        internal static async Task <bool> LaunchUri(WardenStartInfo startInfo, CancellationTokenSource cancelToken)
        {
            var(fileName, arguments, workingDirectory) = ValidateUri(startInfo);

            if (startInfo.AsUser)
            {
                if (!Api.StartProcessAndBypassUac(fileName, arguments, workingDirectory, out _))
                {
                    throw new WardenLaunchException(string.Format(Resources.Exception_Process_Not_Start, fileName, arguments));
                }
            }
            else
            {
                var processStartInfo = new ProcessStartInfo
                {
                    FileName         = fileName,
                    Arguments        = arguments,
                    WorkingDirectory = workingDirectory,
                    UseShellExecute  = true
                };
                using (var process = Process.Start(processStartInfo))
                {
                    if (process == null)
                    {
                        throw new WardenLaunchException(string.Format(Resources.Exception_Process_Not_Start, startInfo.FileName, startInfo.Arguments));
                    }
                }
            }
            while (!cancelToken.IsCancellationRequested)
            {
                using (var process = ProcessUtils.GetProcess(startInfo.TargetFileName))
                {
                    if (process != null)
                    {
                        return(true);
                    }
                }
                //aggressive poll
                await Task.Delay(TimeSpan.FromMilliseconds(100), cancelToken.Token);
            }
            return(false);
        }
Пример #5
0
 /// <summary>
 /// Attempts to create a process outside of session zero.
 /// </summary>
 /// <param name="startInfo"></param>
 /// <returns></returns>
 internal static WardenProcess CreateProcessAsUser(WardenStartInfo startInfo)
 {
     if (!new FileInfo(startInfo.FileName).Exists)
     {
         throw new WardenLaunchException($"Unable to launch {startInfo.FileName} -- the file is missing.");
     }
     if (startInfo.RaisePrivileges)
     {
         if (Api.StartProcessAsPrivilegedUser(startInfo.FileName, startInfo.Arguments, startInfo.WorkingDirectory, out var privInfo))
         {
             return(WardenProcess.GetProcessFromId(privInfo, startInfo.Filters, startInfo.Track));
         }
         throw new WardenLaunchException("Unable to start process as privileged user");
     }
     if (Api.StartProcessAsUser(startInfo.FileName, startInfo.Arguments, startInfo.WorkingDirectory, out var procInfo))
     {
         return(WardenProcess.GetProcessFromId(procInfo, startInfo.Filters, startInfo.Track));
     }
     throw new WardenLaunchException("Unable to start process as user");
 }
Пример #6
0
        /// <summary>
        ///     Creates a new process object the interactive desktop session.
        /// </summary>
        /// <param name="info">
        ///     The <see cref="WardenStartInfo"/> that contains the information that is used to start the process,
        ///     including the PackageFamilyName, ApplicationId, and any command-line arguments.
        /// </param>
        /// <returns>A <see cref="WardenProcess"/> instance that is associated with the created process.</returns>
        internal static WardenProcess?AsUser(WardenStartInfo info)
        {
            var environmentBlockHandle = IntPtr.Zero;
            var startInfo          = new StartupInfo();
            var processInformation = new ProcessInformation();

            startInfo.cb = Marshal.SizeOf <StartupInfo>();
            try
            {
                if (!TryGetInteractiveUserToken(out var sessionId, out var interactiveUserToken))
                {
                    throw new Win32Exception("GetSessionUserToken failed.");
                }

                // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
                // the window station has a desktop that is invisible and the process is incapable of receiving
                // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
                // interaction with the new process.
                startInfo.wShowWindow = (short)SW.SW_SHOW;
                startInfo.lpDesktop   = InteractiveWindowStation;


                using var registryHandle = LoadUserProfile((int)sessionId, interactiveUserToken, out _);
                if (registryHandle.IsInvalid)
                {
                    throw new Win32Exception("LoadUserProfile failed.");
                }

                // copy the users env block
                if (!CreateEnvironmentBlock(ref environmentBlockHandle, interactiveUserToken, false))
                {
                    throw new Win32Exception("CreateEnvironmentBlock failed.");
                }


                const int creationFlags = CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS;
                if (!CreateProcessAsUser(interactiveUserToken,
                                         info.FileName,
                                         info.Arguments,
                                         null,
                                         null,
                                         false,
                                         creationFlags,
                                         environmentBlockHandle,
                                         info.WorkingDirectory,
                                         ref startInfo,
                                         out processInformation))
                {
                    throw new Win32Exception("CreateProcessAsUser failed");
                }
                UnloadUserProfile(interactiveUserToken, registryHandle);
                return(WardenProcess.GetProcessById(processInformation.ProcessId, info.Track, info.FilteredImages));
            }
            finally
            {
                DestroyEnvironmentBlock(environmentBlockHandle);
                CloseHandle(processInformation.ThreadHandle);
                CloseHandle(processInformation.ProcessHandle);
                CloseHandle(startInfo.hStdError);
                CloseHandle(startInfo.hStdInput);
                CloseHandle(startInfo.hStdOutput);
                CloseHandle(startInfo.lpReserved2);
            }
        }
Пример #7
0
        /// <summary>
        ///     Creates a new process object with the privileges of LocalSystem in the interactive desktop session.
        /// </summary>
        /// <param name="info">
        ///     The <see cref="WardenStartInfo"/> that contains the information that is used to start the process,
        ///     including the PackageFamilyName, ApplicationId, and any command-line arguments.
        /// </param>
        /// <returns>A <see cref="WardenProcess"/> instance that is associated with the created process.</returns>
        internal static WardenProcess?AsLocalSystem(WardenStartInfo info)
        {
            var environmentBlockHandle = IntPtr.Zero;
            var startInfo          = new StartupInfo();
            var processInformation = new ProcessInformation();

            startInfo.cb = Marshal.SizeOf <StartupInfo>();
            try
            {
                if (!TryGetInteractiveUserToken(out var sessionId, out var interactiveUserToken))
                {
                    throw new Win32Exception("GetSessionUserToken failed.");
                }

                // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
                // the window station has a desktop that is invisible and the process is incapable of receiving
                // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
                // interaction with the new process.
                startInfo.wShowWindow = (short)SW.SW_SHOW;
                startInfo.lpDesktop   = InteractiveWindowStation;

                using var registryHandle = LoadUserProfile((int)sessionId, interactiveUserToken, out _);
                if (registryHandle.IsInvalid)
                {
                    throw new Win32Exception("LoadUserProfile failed.");
                }
                // copy the users env block
                if (!CreateEnvironmentBlock(ref environmentBlockHandle, interactiveUserToken, false))
                {
                    throw new Win32Exception("CreateEnvironmentBlock failed.");
                }

                var logonProcessId = GetWinLogonProcessId(sessionId);
                if (logonProcessId == 0)
                {
                    throw new Win32Exception($"Unable to find the WinLogon process ID for session '{sessionId}'.");
                }

                using var processHandle = ProcessNative.OpenProcessHandle(ProcessNative.ProcessAccessFlags.MaximumAllowed, logonProcessId);
                if (processHandle.IsInvalid)
                {
                    throw new Win32Exception("Unable to obtain a valid handle for winlogon.exe");
                }
                if (!ProcessNative.OpenProcessToken(processHandle, TOKEN_ALL_ACCESS, out var processToken))
                {
                    throw new Win32Exception("Unable to open the process token for winlogon.exe");
                }

                // ReSharper disable once UseObjectOrCollectionInitializer
                var securityAttributes = new SecurityAttributes();
                securityAttributes.Length = Marshal.SizeOf <SecurityAttributes>();


                // copy the access token of the explorer process; the newly created token will be a primary token
                if (!DuplicateTokenEx(processToken, MAXIMUM_ALLOWED, securityAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TokenType.Primary, out var winLogonToken))
                {
                    throw new Win32Exception("Unable to duplicate the winlogon.exe process token");
                }

                const int creationFlags = CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS;
                if (!CreateProcessAsUser(winLogonToken,
                                         info.FileName,
                                         info.Arguments,
                                         securityAttributes,
                                         securityAttributes,
                                         false,
                                         creationFlags,
                                         environmentBlockHandle,
                                         info.WorkingDirectory,
                                         ref startInfo,
                                         out processInformation))
                {
                    throw new Win32Exception($"CreateProcessAsUserW failed: {Marshal.GetLastWin32Error()}");
                }
                UnloadUserProfile(interactiveUserToken, registryHandle);
                return(WardenProcess.GetProcessById(processInformation.ProcessId, info.Track, info.FilteredImages));
            }
            finally
            {
                DestroyEnvironmentBlock(environmentBlockHandle);
                CloseHandle(processInformation.ThreadHandle);
                CloseHandle(processInformation.ProcessHandle);
                CloseHandle(startInfo.hStdError);
                CloseHandle(startInfo.hStdInput);
                CloseHandle(startInfo.hStdOutput);
                CloseHandle(startInfo.lpReserved2);
            }
        }
Пример #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="startInfo"></param>
        /// <returns></returns>
        private static (string FileName, string Arguments, string WorkingDirectory) ValidateUri(WardenStartInfo startInfo)
        {
            var unwrappedUri = UnwrapUri(startInfo.FileName, new[] { startInfo.Arguments });

            if (!unwrappedUri.HasValue)
            {
                throw new WardenLaunchException($"Unable to unwrap the following URI: {startInfo.FileName}");
            }

            var launcher = unwrappedUri.Value.LauncherFileName;

            if (string.IsNullOrWhiteSpace(launcher) || !new FileInfo(launcher).Exists)
            {
                throw new WardenLaunchException($"Unable to run the launcher for URI {startInfo.FileName} because it does not exist..");
            }
            var launcherArguments = unwrappedUri.Value.LauncherArguments;

            var launcherWorkingDir = PathUtils.GetDirectoryName(launcher);

            if (string.IsNullOrWhiteSpace(launcher) || !new DirectoryInfo(launcherWorkingDir).Exists)
            {
                throw new WardenLaunchException($"Unable to determine the working directory for the following URI: {startInfo.FileName}.");
            }

            if (string.IsNullOrWhiteSpace(startInfo.TargetFileName) || !new FileInfo(startInfo.TargetFileName).Exists)
            {
                throw new WardenLaunchException($"Unable to launch URI {startInfo.FileName} because target file {startInfo.TargetFileName} does not exist.");
            }
            return(launcher, launcherArguments, launcherWorkingDir);
        }
Пример #9
0
        /// <summary>
        ///   Starts a process using the operating system shell.
        /// </summary>
        /// <param name="startInfo">
        ///     The <see cref="WardenStartInfo"/> that contains the information that is used to start the process,
        ///     including the file name and any command-line arguments.
        /// </param>
        public static void Start(WardenStartInfo startInfo)
        {
            var    emptyObject          = new object();
            object shellWindows         = null;
            object desktopWindow        = null;
            object desktopBrowser       = null;
            object desktopView          = null;
            object backgroundFolderView = null;
            object applicationDispatch  = null;

            var shellWindowsType = Type.GetTypeFromCLSID(ShellWindowsServer, false);

            if (shellWindowsType == null)
            {
                throw new Exception("This operation is not available in this environment.");
            }

            try
            {
                shellWindows = Activator.CreateInstance(shellWindowsType);

                desktopWindow = ((IShellWindows)shellWindows).FindWindowSW(ref emptyObject,
                                                                           ref emptyObject,
                                                                           ShellWindowsClass.Desktop,
                                                                           out _,
                                                                           ShellWindowsFindOptions.NeedDispatch);

                ((IServiceProvider)desktopWindow).QueryService(TopLevelBrowser,
                                                               typeof(IShellBrowser).GUID,
                                                               out desktopBrowser);

                ((IShellBrowser)desktopBrowser).QueryActiveShellView(out desktopView);

                ((IShellView)desktopView).GetItemObject(ShellViewGetItemObject.Background,
                                                        typeof(IDispatch).GUID,
                                                        out backgroundFolderView);

                applicationDispatch = ((IShellFolderViewDual)backgroundFolderView).Application;

                var showFlags = new object();

                switch (startInfo.WindowStyle)
                {
                case WindowStyle.Normal:
                    showFlags = ShellDispatchExecuteShowFlags.Normal;

                    break;

                case WindowStyle.Hidden:
                    showFlags = ShellDispatchExecuteShowFlags.Hidden;

                    break;

                case WindowStyle.Minimized:
                    showFlags = ShellDispatchExecuteShowFlags.Minimized;

                    break;

                case WindowStyle.Maximized:
                    showFlags = ShellDispatchExecuteShowFlags.Maximized;
                    break;
                }

                ((IShellDispatch2)applicationDispatch).ShellExecute(startInfo.FileName,
                                                                    startInfo.Arguments,
                                                                    startInfo.WorkingDirectory,
                                                                    startInfo.RaisePrivileges ? "runas" : "open",
                                                                    showFlags);
            }
            catch (Exception e)
            {
                throw new Exception("Failed to start application.", e);
            }
            finally
            {
                if (applicationDispatch != null)
                {
                    Marshal.ReleaseComObject(applicationDispatch);
                }

                if (backgroundFolderView != null)
                {
                    Marshal.ReleaseComObject(backgroundFolderView);
                }

                if (desktopView != null)
                {
                    Marshal.ReleaseComObject(desktopView);
                }

                if (desktopBrowser != null)
                {
                    Marshal.ReleaseComObject(desktopBrowser);
                }

                if (desktopWindow != null)
                {
                    Marshal.ReleaseComObject(desktopWindow);
                }

                if (shellWindows != null)
                {
                    Marshal.ReleaseComObject(shellWindows);
                }
            }
        }