我正在尝试通过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并启动正确的应用程序。
答案 0 :(得分:10)
您需要将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会提示用户确认。如果这不合适,那么您需要添加manifest来永久提升主机进程权限。
答案 1 :(得分:3)
您可以使用CreateProcessAsUser function(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;
}
/// <summary>
/// LaunchProcess As User Overloaded for Window Mode
/// </summary>
/// <param name="cmdLine"></param>
/// <param name="token"></param>
/// <param name="envBlock"></param>
/// <param name="WindowMode"></param>
/// <returns></returns>
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;
}
答案 2 :(得分:0)
价:
How to start a Process as administrator mode in C#
Elevating process privilege programmatically?
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";
}
参考: How to run/start a new process with admin rights? ASP.net论坛
另一种方法是模拟管理员用户。你可以这样做 调用Logon函数并模拟其令牌的用户 会得到的。要在代码中模拟用户,请查看: WindowsImpersonationContext Class 。使用支票 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);
}
}