0

是否可以冒充管理员在代码中Vista/Windows 7设置用户名、登录名和密码?

我的场景:很多用户(没有本地管理员权限)将执行 C# 程序;C# 程序将文件复制到C:\Windows\. 我希望程序使用管理员的凭据进行复制,而不会收到“拒绝访问”消息,也不需要在 UAC 提示符中键入凭据。

我试过这两种方法:

  • 包括带有requireAdministratoror的清单highestAvailable。将提示用户输入凭据,因此这不起作用。
  • 冒充使用LogonUser来自advapi32.dll API. 我已经完成了它并且像一个魅力一样工作......但仅在 Windows XP 中。

这可能吗?

编辑

很多人对我为什么要做这么可怕的事情很感兴趣。我正在编辑以包含我的一些评论,解释我为什么需要这个。

我们无法在每台用户计算机上创建计划任务。这是一次性的事情:向所有用户发送一封电子邮件,要求他们执行网络文件夹中的 .exe 文件(或附加 .exe)。这就是重点:避免通过计算机进行计算机操作。

拜托了伙计们!我知道这不正确,但情况就是这样。正常和正确的方法需要我们在公司程序上花费 2 个月的时间。出于业务原因,总经理要求我们在一周内找到一种方法。这与某些病毒或攻击无关……这是一项愚蠢的任务,将过时的墙纸更换为具有全新销售“口头禅”的墙纸。

4

2 回答 2

3

您说您只是更改用户的墙纸,正确的方法是两步过程,完全可以通过组策略完成。

第 1 步每台机器有一个一次性启动脚本,将背景从网络共享复制到本地 windows 目录。

第 2 步将用户壁纸更新为新的公司壁纸。(您需要更新的 reg 密钥位于HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\,特别是WallpaperWallpaperStyle

如果新壁纸与旧壁纸同名,您可以删除第 2 步。


如果你真的必须按照自己的方式去做,这里有一个基于我用于我自己任务的这个问题的答案的解决方案。

将以下 NativeMethods 类添加到您的代码中。

using System;
using System.Runtime.InteropServices;

/// <summary>
/// Implements P/Invoke Interop calls to the operating system.
/// </summary>
internal static class NativeMethods
{
    /// <summary>
    /// The type of logon operation to perform.
    /// </summary>
    internal enum LogonType : int
    {
        /// <summary>
        /// This logon type is intended for users who will be interactively
        /// using the computer, such as a user being logged on by a
        /// terminal server, remote shell, or similar process.
        /// This logon type has the additional expense of caching logon
        /// information for disconnected operations; therefore, it is
        /// inappropriate for some client/server applications, such as a
        /// mail server.
        /// </summary>
        Interactive = 2,

        /// <summary>
        /// This logon type is intended for high performance servers to
        /// authenticate plaintext passwords.
        /// The LogonUser function does not cache credentials for this
        /// logon type.
        /// </summary>
        Network = 3,

        /// <summary>
        /// This logon type is intended for batch servers, where processes
        /// may be executing on behalf of a user without their direct
        /// intervention.  This type is also for higher performance servers
        /// that process many plaintext authentication attempts at a time,
        /// such as mail or Web servers.
        /// The LogonUser function does not cache credentials for this
        /// logon type.
        /// </summary>
        Batch = 4,

        /// <summary>
        /// Indicates a service-type logon.  The account provided must have
        /// the service privilege enabled.
        /// </summary>
        Service = 5,

        /// <summary>
        /// This logon type is for GINA DLLs that log on users who will be
        /// interactively using the computer.
        /// This logon type can generate a unique audit record that shows
        /// when the workstation was unlocked.
        /// </summary>
        Unlock = 7,

        /// <summary>
        /// This logon type preserves the name and password in the
        /// authentication package, which allows the server to make
        /// connections to other network servers while impersonating the
        /// client.  A server can accept plaintext credentials from a
        /// client, call LogonUser, verify that the user can access the
        /// system across the network, and still communicate with other
        /// servers.
        /// NOTE: Windows NT:  This value is not supported.
        /// </summary>
        NetworkCleartext = 8,

        /// <summary>
        /// This logon type allows the caller to clone its current token
        /// and specify new credentials for outbound connections.  The new
        /// logon session has the same local identifier but uses different
        /// credentials for other network connections.
        /// NOTE: This logon type is supported only by the
        /// LOGON32_PROVIDER_WINNT50 logon provider.
        /// NOTE: Windows NT:  This value is not supported.
        /// </summary>
        NewCredentials = 9
    }

    /// <summary>
    /// Specifies the logon provider.
    /// </summary>
    internal enum LogonProvider : int
    {
        /// <summary>
        /// Use the standard logon provider for the system.
        /// The default security provider is negotiate, unless you pass
        /// NULL for the domain name and the user name is not in UPN format.
        /// In this case, the default provider is NTLM.
        /// NOTE: Windows 2000/NT:   The default security provider is NTLM.
        /// </summary>
        Default = 0,

        /// <summary>
        /// Use this provider if you'll be authenticating against a Windows
        /// NT 3.51 domain controller (uses the NT 3.51 logon provider).
        /// </summary>
        WinNT35 = 1,

        /// <summary>
        /// Use the NTLM logon provider.
        /// </summary>
        WinNT40 = 2,

        /// <summary>
        /// Use the negotiate logon provider.
        /// </summary>
        WinNT50 = 3
    }

    /// <summary>
    /// The type of logon operation to perform.
    /// </summary>
    internal enum SecurityImpersonationLevel : int
    {
        /// <summary>
        /// The server process cannot obtain identification information
        /// about the client, and it cannot impersonate the client.  It is
        /// defined with no value given, and thus, by ANSI C rules,
        /// defaults to a value of zero.
        /// </summary>
        Anonymous = 0,

        /// <summary>
        /// The server process can obtain information about the client,
        /// such as security identifiers and privileges, but it cannot
        /// impersonate the client.  This is useful for servers that export
        /// their own objects, for example, database products that export
        /// tables and views.  Using the retrieved client-security
        /// information, the server can make access-validation decisions
        /// without being able to use other services that are using the
        /// client's security context.
        /// </summary>
        Identification = 1,

        /// <summary>
        /// The server process can impersonate the client's security
        /// context on its local system.  The server cannot impersonate the
        /// client on remote systems.
        /// </summary>
        Impersonation = 2,

        /// <summary>
        /// The server process can impersonate the client's security
        /// context on remote systems.
        /// NOTE: Windows NT:  This impersonation level is not supported.
        /// </summary>
        Delegation = 3
    }

    /// <summary>
    /// Logs on the user.
    /// </summary>
    /// <param name="userName">Name of the user.</param>
    /// <param name="domain">The domain.</param>
    /// <param name="password">The password.</param>
    /// <param name="logonType">Type of the logon.</param>
    /// <param name="logonProvider">The logon provider.</param>
    /// <param name="token">The token.</param>
    /// <returns>True if the function succeeds, false if the function fails.
    /// To get extended error information, call GetLastError.</returns>
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool LogonUser(
        string userName,
        string domain,
        string password,
        LogonType logonType,
        LogonProvider logonProvider,
        out IntPtr token);

    /// <summary>
    /// Duplicates the token.
    /// </summary>
    /// <param name="existingTokenHandle">The existing token
    /// handle.</param>
    /// <param name="securityImpersonationLevel">The security impersonation
    /// level.</param>
    /// <param name="duplicateTokenHandle">The duplicate token
    /// handle.</param>
    /// <returns>True if the function succeeds, false if the function fails.
    /// To get extended error information, call GetLastError.</returns>
    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool DuplicateToken(
        IntPtr existingTokenHandle,
        SecurityImpersonationLevel securityImpersonationLevel,
        out IntPtr duplicateTokenHandle);

    /// <summary>
    /// Closes the handle.
    /// </summary>
    /// <param name="handle">The handle.</param>
    /// <returns>True if the function succeeds, false if the function fails.
    /// To get extended error information, call GetLastError.</returns>
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool CloseHandle(IntPtr handle);
}

这是要在代码中使用的实现。

    IntPtr token;

    if (!NativeMethods.LogonUser(
        this.userName,
        this.domain,
        this.password,
        NativeMethods.LogonType.NewCredentials,
        NativeMethods.LogonProvider.Default,
        out token))
    {
        throw new Win32Exception();
    }

    try
    {
        IntPtr tokenDuplicate;

        if (!NativeMethods.DuplicateToken(
            token,
            NativeMethods.SecurityImpersonationLevel.Impersonation,
            out tokenDuplicate))
        {
            throw new Win32Exception();
        }

        try
        {
            using (WindowsImpersonationContext impersonationContext =
                new WindowsIdentity(tokenDuplicate).Impersonate())
            {
                //Copy your file to the windows directory here.

                impersonationContext.Undo();
                return;
            }
        }
        finally
        {
            if (tokenDuplicate != IntPtr.Zero)
            {
                if (!NativeMethods.CloseHandle(tokenDuplicate))
                {
                    // Uncomment if you need to know this case.
                    ////throw new Win32Exception();
                }
            }
        }
    }
    finally
    {
        if (token != IntPtr.Zero)
        {
            if (!NativeMethods.CloseHandle(token))
            {
                // Uncomment if you need to know this case.
                ////throw new Win32Exception();
            }
        }
    }
于 2013-05-20T20:51:14.353 回答
3

正如其他人所说,您的解决方法破坏了几个最佳实践,并且“只需要现在就完成它”是破坏最佳实践的糟糕时机,正如历史所表明的那样。因此,您应该首先提出一些建议:

  • 为此创建一个全新的帐户
  • 为该帐户提供所需的最低权限
  • 给该帐户一个非常短(< 1 周)的超时时间

这至少可以保证一年后某人不会偶然发现该程序并在任何地方拥有管理员权限。现在使用这样的程序可能只需要一天的时间,但已经指出这样的安全性是徒劳的。

鉴于此,我发现了一篇关于 LogonUser 的重大变化的帖子。它要求DllImport从以下位置更改您的代码:

[DllImport("advapi32.dll", SetLastError = true)]
private extern static bool LogonUser(
    string pszUsername, string pszDomain, string pszPassword,
    int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

至:

[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);

看看这是否能够解决您的“仅适用于 Windows XP”的问题。

既然您已经为编程问题找到了解决方案,那么您确实需要与您的公司讨论,以弄清楚为什么您的公司政策已经使您的 IT 部门无法使用,以至于部署新墙纸需要 2 个月的时间。这类问题可能会恶化到无法再修复不良做法的地步,因为这样做的时间线太长了。(哦,那个服务帐户有一个三年前的密码,并且是域管理员,修复它需要大量的文书工作......)

于 2013-05-20T20:51:52.133 回答