.NET Start Process具有更高的权限

我正在尝试通过C#应用程序执行具有管理员权限的程序,该应用程序仅使用用户权限进行调用。

ProcessStartInfo psi; try { psi = new ProcessStartInfo(@"WINZIP32.EXE"); psi.UseShellExecute = false; SecureString pw = new SecureString(); pw.AppendChar('p'); pw.AppendChar('a'); pw.AppendChar('s'); pw.AppendChar('s'); pw.AppendChar('w'); pw.AppendChar('o'); pw.AppendChar('r'); pw.AppendChar('d'); psi.Password = pw; psi.UserName = "administrator"; Process.Start(psi); } catch (Exception ex) { MessageBox.Show(ex.Message); } 

它确实启动winzip,但仅限用户权限。 有什么我做错了,或者甚至有可能开始一个更高权利的过程?

谢谢!

编辑:这是问题背后的原因,也许它有助于理解我真正需要的东西。

例如,我使用winzip来大致了解我的代码有什么不对。 实际问题是,我们公司使用2个版本的程序。 但在开始任何版本之前,您需要使用regsvr32(具有管理员权限)导入dll文件。 现在我想编写一个程序,让用户选择版本,导入dll并启动正确的应用程序。

您需要将ProcessStartInfo.UseShellExecute设置为true ,将ProcessStartInfo.Verb设置为runas

 Process process = null; ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.FileName = "WINZIP32.EXE"; processStartInfo.Verb = "runas"; processStartInfo.WindowStyle = ProcessWindowStyle.Normal; processStartInfo.UseShellExecute = true; process = Process.Start(processStartInfo); 

这将导致应用程序以管理员身份运行。 但是,UAC会提示用户确认。 如果这不可取,那么您需要添加清单以永久提升主机进程特权。

您可以使用CreateProcessAsUser函数 (Win32 API)以另一个用户(甚至管理员)身份运行进程。 CreateProcessAsUser接受用户令牌作为第一个参数,即模拟令牌。

您必须使用DLLImport从Windows DLL加载该函数。

看一下我在我的一个项目中使用的这个示例实现:

  [StructLayout(LayoutKind.Sequential)] internal struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } [StructLayout(LayoutKind.Sequential)] internal struct SECURITY_ATTRIBUTES { public uint nLength; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public uint 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; } internal enum SECURITY_IMPERSONATION_LEVEL { SecurityAnonymous, SecurityIdentification, SecurityImpersonation, SecurityDelegation } internal enum TOKEN_TYPE { TokenPrimary = 1, TokenImpersonation } public class ProcessAsUser { [DllImport("advapi32.dll", SetLastError = true)] private static extern bool CreateProcessAsUser( IntPtr hToken, string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx", SetLastError = true)] private static extern bool DuplicateTokenEx( IntPtr hExistingToken, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, Int32 ImpersonationLevel, Int32 dwTokenType, ref IntPtr phNewToken); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool OpenProcessToken( IntPtr ProcessHandle, UInt32 DesiredAccess, ref IntPtr TokenHandle); [DllImport("userenv.dll", SetLastError = true)] private static extern bool CreateEnvironmentBlock( ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit); [DllImport("userenv.dll", SetLastError = true)] private static extern bool DestroyEnvironmentBlock( IntPtr lpEnvironment); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle( IntPtr hObject); private const short SW_SHOW = 5; private const uint TOKEN_QUERY = 0x0008; private const uint TOKEN_DUPLICATE = 0x0002; private const uint TOKEN_ASSIGN_PRIMARY = 0x0001; private const int GENERIC_ALL_ACCESS = 0x10000000; private const int STARTF_USESHOWWINDOW = 0x00000001; private const int STARTF_FORCEONFEEDBACK = 0x00000040; private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400; private const int STARTF_RUNFULLSCREEN = 0x00000020; private static bool LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock) { bool result = false; PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); SECURITY_ATTRIBUTES saProcess = new SECURITY_ATTRIBUTES(); SECURITY_ATTRIBUTES saThread = new SECURITY_ATTRIBUTES(); saProcess.nLength = (uint)Marshal.SizeOf(saProcess); saThread.nLength = (uint)Marshal.SizeOf(saThread); STARTUPINFO si = new STARTUPINFO(); si.cb = (uint)Marshal.SizeOf(si); //if this member is NULL, the new process inherits the desktop //and window station of its parent process. If this member is //an empty string, the process does not inherit the desktop and //window station of its parent process; instead, the system //determines if a new desktop and window station need to be created. //If the impersonated user already has a desktop, the system uses the //existing desktop. si.lpDesktop = @"WinSta0\Default"; //Modify as needed si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK; si.wShowWindow = SW_SHOW; //Set other si properties as required. result = CreateProcessAsUser( token, null, cmdLine, ref saProcess, ref saThread, false, CREATE_UNICODE_ENVIRONMENT, envBlock, null, ref si, out pi); if (result == false) { int error = Marshal.GetLastWin32Error(); string message = String.Format("CreateProcessAsUser Error: {0}", error); Debug.WriteLine(message); } return result; } ///  /// LaunchProcess As User Overloaded for Window Mode ///  ///  ///  ///  ///  ///  private static bool LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock,uint WindowMode) { bool result = false; PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); SECURITY_ATTRIBUTES saProcess = new SECURITY_ATTRIBUTES(); SECURITY_ATTRIBUTES saThread = new SECURITY_ATTRIBUTES(); saProcess.nLength = (uint)Marshal.SizeOf(saProcess); saThread.nLength = (uint)Marshal.SizeOf(saThread); STARTUPINFO si = new STARTUPINFO(); si.cb = (uint)Marshal.SizeOf(si); //if this member is NULL, the new process inherits the desktop //and window station of its parent process. If this member is //an empty string, the process does not inherit the desktop and //window station of its parent process; instead, the system //determines if a new desktop and window station need to be created. //If the impersonated user already has a desktop, the system uses the //existing desktop. si.lpDesktop = @"WinSta0\Default"; //Default Vista/7 Desktop Session si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK; //Check the Startup Mode of the Process if (WindowMode == 1) si.wShowWindow = SW_SHOW; else if (WindowMode == 2) { //Do Nothing } else if (WindowMode == 3) si.wShowWindow = 0; //Hide Window else if (WindowMode == 4) si.wShowWindow = 3; //Maximize Window else if (WindowMode == 5) si.wShowWindow = 6; //Minimize Window else si.wShowWindow = SW_SHOW; //Set other si properties as required. result = CreateProcessAsUser( token, null, cmdLine, ref saProcess, ref saThread, false, CREATE_UNICODE_ENVIRONMENT, envBlock, null, ref si, out pi); if (result == false) { int error = Marshal.GetLastWin32Error(); string message = String.Format("CreateProcessAsUser Error: {0}", error); Debug.WriteLine(message); } return result; } private static IntPtr GetPrimaryToken(int processId) { IntPtr token = IntPtr.Zero; IntPtr primaryToken = IntPtr.Zero; bool retVal = false; Process p = null; try { p = Process.GetProcessById(processId); } catch (ArgumentException) { string details = String.Format("ProcessID {0} Not Available", processId); Debug.WriteLine(details); throw; } //Gets impersonation token retVal = OpenProcessToken(p.Handle, TOKEN_DUPLICATE, ref token); if (retVal == true) { SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.nLength = (uint)Marshal.SizeOf(sa); //Convert the impersonation token into Primary token retVal = DuplicateTokenEx( token, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref primaryToken); //Close the Token that was previously opened. CloseHandle(token); if (retVal == false) { string message = String.Format("DuplicateTokenEx Error: {0}", Marshal.GetLastWin32Error()); Debug.WriteLine(message); } } else { string message = String.Format("OpenProcessToken Error: {0}", Marshal.GetLastWin32Error()); Debug.WriteLine(message); } //We'll Close this token after it is used. return primaryToken; } private static IntPtr GetEnvironmentBlock(IntPtr token) { IntPtr envBlock = IntPtr.Zero; bool retVal = CreateEnvironmentBlock(ref envBlock, token, false); if (retVal == false) { //Environment Block, things like common paths to My Documents etc. //Will not be created if "false" //It should not adversley affect CreateProcessAsUser. string message = String.Format("CreateEnvironmentBlock Error: {0}", Marshal.GetLastWin32Error()); Debug.WriteLine(message); } return envBlock; } public static bool Launch(string appCmdLine /*,int processId*/) { bool ret = false; //Either specify the processID explicitly //Or try to get it from a process owned by the user. //In this case assuming there is only one explorer.exe Process[] ps = Process.GetProcessesByName("explorer"); int processId = -1;//=processId if (ps.Length > 0) { processId = ps[0].Id; } if (processId > 1) { IntPtr token = GetPrimaryToken(processId); if (token != IntPtr.Zero) { IntPtr envBlock = GetEnvironmentBlock(token); ret = LaunchProcessAsUser(appCmdLine, token, envBlock); if (envBlock != IntPtr.Zero) DestroyEnvironmentBlock(envBlock); CloseHandle(token); } } return ret; } 

参考:
如何在C#中以管理员模式启动进程
以编程方式提升进程权限?

  var psi = new ProcessStartInfo { FileName = "notepad", UserName = "admin", Domain = "", Password = pass, UseShellExecute = true, RedirectStandardOutput = true, RedirectStandardError = true, Verb = "runas"; }; Process.Start(psi); 

//

 var pass = new SecureString(); pass.AppendChar('s'); pass.AppendChar('e'); pass.AppendChar('c'); pass.AppendChar('r'); pass.AppendChar('e'); pass.AppendChar('t'); Process.Start("notepad", "admin", pass, ""); 

// Vista或更高的检查

 if (System.Environment.OSVersion.Version.Major >= 6) { p.StartInfo.Verb = "runas"; } 

参考: 如何使用管理员权限运行/启动新进程? ASP.net论坛

另一种方法是模拟管理员用户。 您可以通过调用登录function并模拟您将获得其令牌的用户来执行此操作。 要在代码中模拟用户,请查看: WindowsImpersonationContext类 。 使用检查http://www.csharpfriends.com/Forums/ShowPost.aspx?PostID=31611查看GetCurrentUser以查看模拟是否成功。

代码片段:

 System.Diagnostics.Process process = null; System.Diagnostics.ProcessStartInfo processStartInfo; processStartInfo = new System.Diagnostics.ProcessStartInfo(); processStartInfo.FileName = "regedit.exe"; if (System.Environment.OSVersion.Version.Major >= 6) // Windows Vista or higher { processStartInfo.Verb = "runas"; } else { // No need to prompt to run as admin } processStartInfo.Arguments = ""; processStartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; processStartInfo.UseShellExecute = true; try { process = System.Diagnostics.Process.Start(processStartInfo); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { if (process != null) { process.Dispose(); } } 

//尝试使用管理员登录,我还没有测试过..

 [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public extern static bool CloseHandle(IntPtr handle); // Test harness. // If you incorporate this code into a DLL, be sure to demand FullTrust. [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] private void button1_Click(object sender, EventArgs e) { SafeTokenHandle safeTokenHandle; const int LOGON32_PROVIDER_DEFAULT = 0; //This parameter causes LogonUser to create a primary token. const int LOGON32_LOGON_INTERACTIVE = 2; bool returnValue = LogonUser("administrator", "", "password", LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle); Console.WriteLine("LogonUser called."); if (false == returnValue) { int ret = Marshal.GetLastWin32Error(); Console.WriteLine("LogonUser failed with error code : {0}", ret); throw new System.ComponentModel.Win32Exception(ret); } using (safeTokenHandle) { Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No")); Console.WriteLine("Value of Windows NT token: " + safeTokenHandle); // Check the identity. Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name); // Use the token handle returned by LogonUser. WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()); using (WindowsImpersonationContext impersonatedUser = newId.Impersonate()) { System.Diagnostics.Process process = null; System.Diagnostics.ProcessStartInfo processStartInfo; processStartInfo = new System.Diagnostics.ProcessStartInfo(); processStartInfo.FileName = "regedit.exe"; //if (System.Environment.OSVersion.Version.Major >= 6) // Windows Vista or higher //{ // processStartInfo.Verb = "runas"; //} //else //{ // // No need to prompt to run as admin //} processStartInfo.Arguments = ""; processStartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal; processStartInfo.UseShellExecute = true; try { process = System.Diagnostics.Process.Start(processStartInfo); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { if (process != null) { process.Dispose(); } } // Check the identity. Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name); } // Releasing the context object stops the impersonation // Check the identity. Console.WriteLine("After closing the context: " + WindowsIdentity.GetCurrent().Name); } }