【问题标题】:C#: Start process as the "real" administrator with hard coded privilegesC#:以具有硬编码权限的“真正”管理员身份启动进程
【发布时间】:2012-06-29 18:28:27
【问题描述】:

我需要以管理员权限静默安装不同的设置。 我必须对权限进行硬编码,因为用户不知道用户名和密码来自行安装设置。

我尝试了两种不同的方法。

  1. ProcessStartInfo 的用户名、密码和 UseShellExecute = false。
  2. 用户模拟

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LogonUser(...);
    

在这两种情况下windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator) 返回 false 由于权限不足,我的设置无法运行。

奇怪的行为:LogonUser 总是返回 true,即使凭据无效。

这是模拟类:

namespace BlackBlade.Utilities
{
    /// <summary>
    /// Quelle: http://www.blackbladeinc.com/en-us/community/blogs/archive/2009/08/10/runas-in-c.aspx
    /// </summary>
    public class SecurityUtilities
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

        public delegate void RunAsDelegate();

        public static void RunAs(RunAsDelegate methodToRunAs, string username, string password)
        {
            string userName;

            string domain;
            if (username.IndexOf('\\') > 0)
            {
                //a domain name was supplied
                string[] usernameArray = username.Split('\\');
                userName = usernameArray[1];
                domain = usernameArray[0];
            }
            else
            {
                //there was no domain name supplied
                userName = username;
                domain = ".";
            }
            RunAs(methodToRunAs, userName, password, domain);
        }

        public static void RunAs(RunAsDelegate methodToRunAs, string username, string password, string domain)
        {
            IntPtr userToken;
            WindowsIdentity adminIdentity = null;
            WindowsImpersonationContext adminImpersonationContext = null;

            try
            {
                if (LogonUser(username, string.IsNullOrEmpty(domain) ? "." : domain, password, 9, 0, out userToken))
                {
                    //the impersonation suceeded
                    adminIdentity = new WindowsIdentity(userToken);
                    adminImpersonationContext = adminIdentity.Impersonate();

                    // todo: Entfernen.
                    WindowsPrincipal p = new WindowsPrincipal(adminIdentity);
                    MessageBox.Show(p.IsInRole(WindowsBuiltInRole.Administrator).ToString());

                    //run the delegate method
                    //methodToRunAs();
                }
                else
                    throw new Exception(string.Format("Could not impersonate user {0} in domain {1} with the specified password.", username, domain));
            }
            catch (Exception se)
            {
                int ret = Marshal.GetLastWin32Error();
                if (adminImpersonationContext != null)
                    adminImpersonationContext.Undo();
                throw new Exception("Error code: " + ret.ToString(), se);
            }
            finally
            {
                //revert to self
                if (adminImpersonationContext != null)
                    adminImpersonationContext.Undo();
            }
        }
    }
}

【问题讨论】:

  • 请给你的问题一个更有意义的标题!
  • 感谢您让 SO 变得更好 :)
  • LogonUser 是正确的,即使对于无效凭据也返回 true,因为使用 NEW_CREDENTIALS 登录类型它实际上并没有登录提供的用户!它只是将凭据存储在调用用户令牌的副本中以用于网络操作(想想net use /U)。如果要将用户登录到本地计算机,请使用 rdkleine 建议的 INTERACTIVE 登录类型。
  • 根据您的 cmets,我必须对这个问题投反对票。你没有和用户详细说明情况。
  • 但我描述了我想要的,但似乎没有人关心,并且描述了其他方式。我知道安全问题,但这是实际设置。

标签: c# .net impersonation runas


【解决方案1】:

Add a manifest 到您开始使用 RunAs 请求提升的进程。

编辑:首先,使用您已知的管理员凭据启动一个进程,可以使用 LogonUser/CreateProcessAsUser 或 CreateProcessWithLogon。然后检查真正的管理员权限(可能 UAC 已关闭),如有必要,让此进程(以非提升管理员身份运行)使用ShellExecuteEx using the runas verb 启动另一个自身副本。这是the only way。 UAC 被明确设计为在未经用户确认的情况下禁止提升。

用户必须确认海拔高度,除非 UAC 已关闭。为了获得更好的用户体验(不那么可怕的消息框),请获取代码签名证书并签署此可执行文件。

【讨论】:

  • 没有选项。用户没有管理员权限,也无法访问任何管理员帐户。我必须以编程方式“提升”它。
  • 如果没有用户确认(UAC 提示),您无法以编程方式提升。这就是 UAC 的用途。任何解决方法都是安全漏洞,Microsoft 会尽快修补。
  • 所以您说可以使用您提到的技术实现完全的管理员提升?
  • “使用 runas 动词用 ShellExecuteEx 开始另一个自身的副本” - 但这会弹出要求提升的 UAC 窗口,对吗?因此,如果用户没有管理员权限,则必须再次输入用户名和密码,如果有管理员权限,只需单击“是”。它是否正确?所以它与应用清单文件的行为相同。
  • 你必须尝试一下。由于调用 ShellExecuteEx 的进程将以(非提升的)管理员身份运行,因此用户可能不必输入凭据。
【解决方案2】:

使用组策略推出 MSI 或 EXE 安装程序。

或者使用任务计划程序以本地系统帐户运行安装程序。

【讨论】:

  • 不可能。这些设备是无域的。第二个建议也是不可能的。我们将向我们的用户发送一个 U 盘,它应该像“单击我们的 setup.exe”一样简单。
  • 那么谁拥有管理员登录权限?用户?你?用户的系统管理员?正确的答案是将您的设置标记为需要管理员权限,然后让用户的系统管理员来处理。
  • 换句话说:不要那样做。您基本上是在要求您的用户关闭安全性。拇指驱动器的任何接收者都将获得他们机器的管理员密码。是的,安全是一种痛苦。
  • 我无法改变它。情况如上所述。
  • "保存它的代码将被混淆":对......就像 ever 一样有效。如果奖品物有所值,足够一个人破解它,然后谷歌会照顾每个人找出如何做到这一点。安全必须做好。您要求尖叫“恶意软件”和“骗局”。
【解决方案3】:

您是否尝试将 dwLogonType 设置为 2 而不是 9?

http://msdn.microsoft.com/en-us/library/windows/desktop/bb540756(v=vs.85).aspx

这是一个适合我的代码示例:

    public const int LOGON32_LOGON_INTERACTIVE = 2;
    public const int LOGON32_PROVIDER_DEFAULT = 0;

    WindowsImpersonationContext impersonationContext;

    [DllImport("advapi32.dll")]
    public static extern int LogonUserA(String lpszUserName,
        String lpszDomain,
        String lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int DuplicateToken(IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool RevertToSelf();

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern bool CloseHandle(IntPtr handle);

        WindowsIdentity tempWindowsIdentity;
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;

        if (RevertToSelf())
        {
            if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                LOGON32_PROVIDER_DEFAULT, ref token) != 0)
            {
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    impersonationContext = tempWindowsIdentity.Impersonate();
                    if (impersonationContext != null)
                    {
                        CloseHandle(token);
                        CloseHandle(tokenDuplicate);
                        return true;
                    }
                }
            }
        }
        if (token != IntPtr.Zero)
            CloseHandle(token);
        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);

【讨论】:

  • 如果你检查windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator)会发生什么?
  • 除非UAC关闭,否则为假。
猜你喜欢
  • 2016-09-29
  • 2011-05-05
  • 2013-09-18
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多