会话0隔离的启动过程

在Windows 8.1上,我有一个启动PowerShell脚本的服务。 该服务在Session 0 Isolation中作为“nt authority \ system”运行。 我从PowerShell中生成的任何进程在Session 0 Isolation中作为“nt authority \ system”运行。

我需要运行会话0之外的用户帐户下的脚本,而不是系统帐户。 我试过这个

Start-Process "$PsHome\PowerShell.exe" -Credential $pp -ArgumentList $script -wait 

和PsExec使用“-I 1”参数指定我想要的会话。

 & PsExec.exe "Install.bat" -i 1 -accepteula -u "domain\user" -p "awesomePassword" -w "startdir" -h 

我尝试过设置“允许服务与桌面交互”。

当我尝试从PowerShell或c#服务启动该过程时,我不断收到Access被拒绝的错误。

当我尝试使用服务上的c#进行转义时,这是一个示例exception。

 System.ComponentModel.Win32Exception (0x80004005): Access is denied at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo) 

如何逃离会话0?

我可以重新编写c#代码以在不同的用户下启动进程。 或者我可以重新编写调用的PowerShell脚本以作为用户启动另一个进程。 无论我尝试什么,我似乎都无法突破会话0。

使用我在代码项目中找到的示例,我获得了部分解决方案。 上面链接中的示例将以运行“winlogon”进程的用户身份启动进程。 为了以登录用户的身份启动流程,我只是改变了流程以寻找“资源管理器”。

这是原始代码的片段

 // obtain the process id of the winlogon process that is // running within the currently active session Process[] processes = Process.GetProcessesByName("winlogon"); 

我只是改变了寻找资源管理器的过程。

 Process[] processes = Process.GetProcessesByName("explorer"); 

现在,该过程作为用户而不是管理员在会话3中作为域/我启动。

这种方法必须存在问题,例如远程桌面,但是我想要的最终会做到这一点。

如果原始链接蒸发,这是完整性的最终代码。

以下是如何启动它

 // the name of the application to launch String applicationName = "cmd.exe"; // launch the application ApplicationLoader.PROCESS_INFORMATION procInfo; ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo); 

这是代码

 using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security; namespace SuperAwesomeNameSpaceOfJustice { ///  /// Class that allows running applications with full admin rights. In /// addition the application launched will bypass the Vista UAC prompt. ///  public class ApplicationLoader { #region Structures [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int Length; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public int cb; public String lpReserved; public String lpDesktop; public String lpTitle; public uint dwX; public uint dwY; public uint dwXSize; public uint dwYSize; public uint dwXCountChars; public uint dwYCountChars; public uint dwFillAttribute; public uint dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } #endregion #region Enumerations enum TOKEN_TYPE : int { TokenPrimary = 1, TokenImpersonation = 2 } enum SECURITY_IMPERSONATION_LEVEL : int { SecurityAnonymous = 0, SecurityIdentification = 1, SecurityImpersonation = 2, SecurityDelegation = 3, } #endregion #region Constants public const int TOKEN_DUPLICATE = 0x0002; public const uint MAXIMUM_ALLOWED = 0x2000000; public const int CREATE_NEW_CONSOLE = 0x00000010; public const int IDLE_PRIORITY_CLASS = 0x40; public const int NORMAL_PRIORITY_CLASS = 0x20; public const int HIGH_PRIORITY_CLASS = 0x80; public const int REALTIME_PRIORITY_CLASS = 0x100; #endregion #region Win32 API Imports [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hSnapshot); [DllImport("kernel32.dll")] static extern uint WTSGetActiveConsoleSessionId(); [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll")] static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId); [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")] public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); [DllImport("kernel32.dll")] static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurity] static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle); #endregion ///  /// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt ///  /// The name of the application to launch /// Process information regarding the launched application that gets returned to the caller ///  public static bool StartProcessAndBypassUAC(String applicationName, string startingDir, out PROCESS_INFORMATION procInfo) { uint winlogonPid = 0; IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; procInfo = new PROCESS_INFORMATION(); // obtain the currently active session id; every logged on user in the system has a unique session id uint dwSessionId = WTSGetActiveConsoleSessionId(); // obtain the process id of the winlogon process that is running within the currently active session // -- chaged by ty // Process[] processes = Process.GetProcessesByName("winlogon"); Process[] processes = Process.GetProcessesByName("explorer"); foreach (Process p in processes) { if ((uint)p.SessionId == dwSessionId) { winlogonPid = (uint)p.Id; } } // obtain a handle to the winlogon process hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); // obtain a handle to the access token of the winlogon process if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) { CloseHandle(hProcess); return false; } // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser // I would prefer to not have to use a security attribute variable and to just // simply pass null and inherit (by default) the security attributes // of the existing token. However, in C# structures are value types and therefore // cannot be assigned the null value. SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.Length = Marshal.SizeOf(sa); // copy the access token of the winlogon process; the newly created token will be a primary token if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) { CloseHandle(hProcess); CloseHandle(hPToken); return false; } // 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. STARTUPINFO si = new STARTUPINFO(); si.cb = (int)Marshal.SizeOf(si); si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop // flags that specify the priority and creation method of the process int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; // create a new process in the current user's logon session bool result = CreateProcessAsUser(hUserTokenDup, // client's access token null, // file to execute applicationName, // command line ref sa, // pointer to process SECURITY_ATTRIBUTES ref sa, // pointer to thread SECURITY_ATTRIBUTES false, // handles are not inheritable dwCreationFlags, // creation flags IntPtr.Zero, // pointer to new environment block startingDir, // name of current directory ref si, // pointer to STARTUPINFO structure out procInfo // receives information about new process ); // invalidate the handles CloseHandle(hProcess); CloseHandle(hPToken); CloseHandle(hUserTokenDup); return result; // return the result } } }