CreateProcessAsUser 错误代码 6

CreateProcessAsUser error code 6

我正在使用 LogonUser 获取主用户令牌,然后使用 CreateProcessAsUser API 来创建进程。但我收到错误代码 6。不确定是什么问题。下面是代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LogOnUserTestWindows
{
    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Principal;

    class Program
    {
        // Define the Windows LogonUser and CloseHandle functions.
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool LogonUser(String username, String domain, IntPtr password,
                int logonType, int logonProvider, ref IntPtr token);

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

        private enum SW
        {
            SW_HIDE = 0,
            SW_SHOWNORMAL = 1,
            SW_NORMAL = 1,
            SW_SHOWMINIMIZED = 2,
            SW_SHOWMAXIMIZED = 3,
            SW_MAXIMIZE = 3,
            SW_SHOWNOACTIVATE = 4,
            SW_SHOW = 5,
            SW_MINIMIZE = 6,
            SW_SHOWMINNOACTIVE = 7,
            SW_SHOWNA = 8,
            SW_RESTORE = 9,
            SW_SHOWDEFAULT = 10,
            SW_MAX = 10
        }


        [StructLayout(LayoutKind.Sequential)]
        private 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)]
        private struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public uint dwProcessId;
            public uint dwThreadId;
        }


        [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        private static extern bool CreateProcessAsUser(
                IntPtr hToken,
                String lpApplicationName,
                String lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandle,
                uint dwCreationFlags,
                IntPtr lpEnvironment,
                String lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);
        // Define the required LogonUser enumerations.
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;

        private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
        private const int CREATE_NO_WINDOW = 0x08000000;

        private const int CREATE_NEW_CONSOLE = 0x00000010;


        static void Main()
        {
            // Display the current user before impersonation.
            Console.WriteLine("Before impersonation: {0}",
                              WindowsIdentity.GetCurrent().Name);

            // Ask the user for a network domain.
            Console.Write("Please enter your domain: ");
            string domain = Console.ReadLine();

            // Ask the user for a user name.
            Console.Write("Please enter your user name: ");
            string username = Console.ReadLine();

            // Ask the user for a password.
            Console.Write("Please enter your password: ");
            SecureString passWord = GetPassword();

            // Impersonate the account provided by the user.
            try
            {
                //WindowsImpersonationContext userContext = ImpersonateUser(passWord, username, domain);
                IntPtr token = ImpersonateUser(passWord, username, domain);

                // Display the current user after impersonation.
                Console.WriteLine("After impersonation: {0}",
                                  WindowsIdentity.GetCurrent().Name);
            }
            catch (ArgumentException e)
            {
                Console.WriteLine("{0}: {1}", e.GetType().Name, e.Message);
            }
            catch (Win32Exception e)
            {
                Console.WriteLine("{0}: {1}", e.GetType().Name, e.Message);
            }
            finally
            {
                passWord.Dispose();
            }
        }

        public static SecureString GetPassword()
        {
            SecureString password = new SecureString();

            // get the first character of the password
            ConsoleKeyInfo nextKey = Console.ReadKey(true);

            while (nextKey.Key != ConsoleKey.Enter)
            {
                if (nextKey.Key == ConsoleKey.Backspace)
                {
                    if (password.Length > 0)
                    {
                        password.RemoveAt(password.Length - 1);

                        // erase the last * as well
                        Console.Write(nextKey.KeyChar);
                        Console.Write(" ");
                        Console.Write(nextKey.KeyChar);
                    }
                }
                else
                {
                    password.AppendChar(nextKey.KeyChar);
                    Console.Write("*");
                }

                nextKey = Console.ReadKey(true);
            }

            Console.WriteLine();

            // lock the password down
            password.MakeReadOnly();
            return password;
        }

        public static IntPtr ImpersonateUser(SecureString password, string userName, string domainName)
        {
            IntPtr tokenHandle = IntPtr.Zero;
            IntPtr passwordPtr = IntPtr.Zero;
            bool returnValue = false;
            int error = 0;

            // Marshal the SecureString to unmanaged memory.
            passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);

            // Pass LogonUser the unmanaged (and decrypted) copy of the password.
            returnValue = LogonUser(userName, domainName, passwordPtr,
                                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                                    ref tokenHandle);
            if (!returnValue && tokenHandle == IntPtr.Zero)
                error = Marshal.GetLastWin32Error();

            // Perform cleanup whether or not the call succeeded.
            // Zero-out and free the unmanaged string reference.
            Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);
            // Close the token handle.
            CloseHandle(tokenHandle);

            // Throw an exception if an error occurred.
            if (error != 0)
            {
                throw new System.ComponentModel.Win32Exception(error);
            }
            // The token that is passed to the following constructor must 
            // be a primary token in order to use it for impersonation.
            //WindowsIdentity newId = new WindowsIdentity(tokenHandle);

            //String workgroup;
            string cmdLine = null;
            string workDir = null;
            bool visible = true;
            var pEnv = IntPtr.Zero;
            var startInfo = new STARTUPINFO();
            var procInfo = new PROCESS_INFORMATION();
            int iResultOfCreateProcessAsUser;

            uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
            startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
            startInfo.lpDesktop = "winsta0\default";




            if (!CreateProcessAsUser(
                tokenHandle,
                "C:/Windows/System32/notepad.exe", // Application Name
                cmdLine, // Command Line
                IntPtr.Zero,
                IntPtr.Zero,
                false,
                dwCreationFlags,
                pEnv,
                workDir, // Working directory
                ref startInfo,
                out procInfo))
            {
                iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();

                throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -" + iResultOfCreateProcessAsUser);
            }
            return tokenHandle;
        }
    }
}

错误如下

System.Exception
  HResult=0x80131500
  Message=StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -6
  Source=LogOnUserTestWindows
  StackTrace:
   at LogOnUserTestWindows.Program.ImpersonateUser(SecureString password, String userName, String domainName) in C:\Users\santosh\source\repos\LogOnUserTestWindows\LogOnUserTestWindows\Program.cs:line 242
   at LogOnUserTestWindows.Program.Main() in C:\Users\santosh\source\repos\LogOnUserTestWindows\LogOnUserTestWindows\Program.cs:line 122

我无法为 logonUser 和 CreateProcessAsUser API 找到任何合适的文档。我正在尝试在我的机器上 运行 这段代码,它有多个用户。我从一个用户登录并尝试从另一个用户创建进程。如果有人可以向我指出适当的文档或示例,那就太好了。请帮忙。提前致谢。

请尝试使用 CreateProcessWithToken 代替,虽然我不知道为什么该函数返回错误代码 -6,但几天前我尝试使用指定的用户令牌启动应用程序,但 CreateProcessAsUser 没有工作,但是CreateProcessWithToken 做到了。也许它对你也有用,祝你好运。

您在将 tokenHandle 传递给 CreateProcessAsUser 之前关闭了它。

结果:ERROR_INVALID_HANDLE (= 6).