代码之家  ›  专栏  ›  技术社区  ›  Noldorin

从C调用CreateProcessAsUser#

  •  13
  • Noldorin  · 技术社区  · 16 年前

    CreateProcessAsUser

        private void StartProcess()
        {
            bool retValue;
    
            // Create startup info for new console process.
            var startupInfo = new STARTUPINFO();
            startupInfo.cb = Marshal.SizeOf(startupInfo);
            startupInfo.dwFlags = StartFlags.STARTF_USESHOWWINDOW;
            startupInfo.wShowWindow = _consoleVisible ? WindowShowStyle.Show : WindowShowStyle.Hide;
            startupInfo.lpTitle = this.ConsoleTitle ?? "Console";
    
            var procAttrs = new SECURITY_ATTRIBUTES();
            var threadAttrs = new SECURITY_ATTRIBUTES();
            procAttrs.nLength = Marshal.SizeOf(procAttrs);
            threadAttrs.nLength = Marshal.SizeOf(threadAttrs);
    
            // Log on user temporarily in order to start console process in its security context.
            var hUserToken = IntPtr.Zero;
            var hUserTokenDuplicate = IntPtr.Zero;
            var pEnvironmentBlock = IntPtr.Zero;
            var pNewEnvironmentBlock = IntPtr.Zero;
    
            if (!WinApi.LogonUser("UserName", null, "Password",
                LogonType.Interactive, LogonProvider.Default, out hUserToken))
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Error logging on user.");
    
            var duplicateTokenAttrs = new SECURITY_ATTRIBUTES();
            duplicateTokenAttrs.nLength = Marshal.SizeOf(duplicateTokenAttrs);
            if (!WinApi.DuplicateTokenEx(hUserToken, 0, ref duplicateTokenAttrs,
                SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary,
                out hUserTokenDuplicate))
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Error duplicating user token.");
    
            try
            {
                // Get block of environment vars for logged on user.
                if (!WinApi.CreateEnvironmentBlock(out pEnvironmentBlock, hUserToken, false))
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Error getting block of environment variables for user.");
    
                // Read block as array of strings, one per variable.
                var envVars = ReadEnvironmentVariables(pEnvironmentBlock);
    
                // Append custom environment variables to list.
                foreach (var var in this.EnvironmentVariables)
                    envVars.Add(var.Key + "=" + var.Value);
    
                // Recreate environment block from array of variables.
                var newEnvironmentBlock = string.Join("\0", envVars.ToArray()) + "\0";
                pNewEnvironmentBlock = Marshal.StringToHGlobalUni(newEnvironmentBlock);
    
                // Start new console process.
                retValue = WinApi.CreateProcessAsUser(hUserTokenDuplicate, null, this.CommandLine,
                    ref procAttrs, ref threadAttrs, false, CreationFlags.CREATE_NEW_CONSOLE |
                    CreationFlags.CREATE_SUSPENDED | CreationFlags.CREATE_UNICODE_ENVIRONMENT,
                    pNewEnvironmentBlock, null, ref startupInfo, out _processInfo);
                if (!retValue) throw new Win32Exception(Marshal.GetLastWin32Error(),
                    "Unable to create new console process.");
            }
            catch
            {
                // Catch any exception thrown here so as to prevent any malicious program operating
                // within the security context of the logged in user.
    
                // Clean up.
                if (hUserToken != IntPtr.Zero)
                {
                    WinApi.CloseHandle(hUserToken);
                    hUserToken = IntPtr.Zero;
                }
    
                if (hUserTokenDuplicate != IntPtr.Zero)
                {
                    WinApi.CloseHandle(hUserTokenDuplicate);
                    hUserTokenDuplicate = IntPtr.Zero;
                }
    
                if (pEnvironmentBlock != IntPtr.Zero)
                {
                    WinApi.DestroyEnvironmentBlock(pEnvironmentBlock);
                    pEnvironmentBlock = IntPtr.Zero;
                }
    
                if (pNewEnvironmentBlock != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pNewEnvironmentBlock);
                    pNewEnvironmentBlock = IntPtr.Zero;
                }
    
                throw;
            }
            finally
            {
                // Clean up.
                if (hUserToken != IntPtr.Zero)
                    WinApi.CloseHandle(hUserToken);
    
                if (hUserTokenDuplicate != IntPtr.Zero)
                    WinApi.CloseHandle(hUserTokenDuplicate);
    
                if (pEnvironmentBlock != IntPtr.Zero)
                    WinApi.DestroyEnvironmentBlock(pEnvironmentBlock);
    
                if (pNewEnvironmentBlock != IntPtr.Zero)
                    Marshal.FreeHGlobal(pNewEnvironmentBlock);
            }
    
            _process = Process.GetProcessById(_processInfo.dwProcessId);
        }
    

    现在,我得到的错误如下(在调用后的行中抛出 CreateProcessAsUSer

    CreateProcess .

    PInvoke.net

    编辑

    之前的通话

    retValue = WinApi.CreateProcessWithTokenW(hUserToken, LogonFlags.WithProfile, null,
        this.CommandLine, CreationFlags.CREATE_NEW_CONSOLE |
        CreationFlags.CREATE_SUSPENDED | CreationFlags.CREATE_UNICODE_ENVIRONMENT,
        pNewEnvironmentBlock, null, ref startupInfo, out _processInfo);
    

    请注意,正如MSDN文档所建议的那样,此代码不再使用重复的令牌,而是使用原始令牌。

    CreateProcessWithLogonW

    retValue = WinApi.CreateProcessWithLogonW("Alex", null, "password",
        LogonFlags.WithProfile, null, this.CommandLine,
        CreationFlags.CREATE_NEW_CONSOLE | CreationFlags.CREATE_SUSPENDED |
        CreationFlags.CREATE_UNICODE_ENVIRONMENT, pNewEnvironmentBlock,
        null, ref startupInfo, out _processInfo);
    

    3 回复  |  直到 15 年前
        1
  •  9
  •   Noldorin    16 年前

    不管怎样,我所需要做的就是向指定函数的DllImport属性添加一个参数 CharSet = CharSet.Unicode CreateProcessWithLogonW CreateProcessWithTokenW 功能。我想我终于意识到,函数名的W后缀引用了Unicode,我需要在C#中明确指定这一点!这里是 正确的

    [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CreateProcessWithLogonW(string principal, string authority,
        string password, LogonFlags logonFlags, string appName, string cmdLine,
        CreationFlags creationFlags, IntPtr environmentBlock, string currentDirectory,
        ref STARTUPINFO startupInfo, out PROCESS_INFORMATION processInfo);
    
    [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CreateProcessWithTokenW(IntPtr hToken, LogonFlags dwLogonFlags,
        string lpApplicationName, string lpCommandLine, CreationFlags dwCreationFlags,
        IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo,
        out PROCESS_INFORMATION lpProcessInformation);
    
        2
  •  6
  •   Mitch Wheat    16 年前

    here :

    SE_INCREASE_QUOTA_NAME特权。如果 相反。CreateProcessWithLogonW 不需要特权,但是 一般来说,最好使用

    How to call CreateProcessWithLogonW & CreateProcessAsUser in .NET