CreateProcessAsUser - 错误5

时间:2012-11-08 13:51:33

标签: c# powershell

我正在尝试使用CreateProcessAsUser方法。但我收到错误代码 - 5

这就是我的工作。

  1. LoadUserProfile
  2. DuplicateToken
  3. ImpersonateUser
  4. CreateProcessAsUser - with duplicateToken
  5. 有人可以帮助我吗

    此致

    代码

    # Start-of C# section
    $createPocess = @'
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using Microsoft.Win32;
    using System.IO;
    using System.Security.Principal;
    
    namespace CreateProcessUtility
    {
        class Win32
        {
        #region "CONTS"
        const UInt32 INFINITE = 0xFFFFFFFF;
        const UInt32 WAIT_FAILED = 0xFFFFFFFF;
    
    
        #endregion
    
        #region "ENUMS"
    
        [Flags]
        public enum LogonType
        {
            LOGON32_LOGON_INTERACTIVE = 2,
            LOGON32_LOGON_NETWORK = 3,
            LOGON32_LOGON_BATCH = 4,
            LOGON32_LOGON_SERVICE = 5,
            LOGON32_LOGON_UNLOCK = 7,
            LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
            LOGON32_LOGON_NEW_CREDENTIALS = 9
        }
    
        [Flags]
        public enum LogonProvider
        {
            LOGON32_PROVIDER_DEFAULT = 0,
            LOGON32_PROVIDER_WINNT35,
            LOGON32_PROVIDER_WINNT40,
            LOGON32_PROVIDER_WINNT50
        }
    
        #endregion
    
        #region "STRUCTS"
    
        [StructLayout(LayoutKind.Sequential)]
        public struct STARTUPINFO
        {
            public Int32 cb;
            public String lpReserved;
            public String lpDesktop;
            public String lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwYSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public Int32 dwProcessId;
            public Int32 dwThreadId;
        }
    
        #endregion
    
        #region "FUNCTIONS (P/INVOKE)"
    
        [StructLayout(LayoutKind.Sequential)]
        public struct ProfileInfo {
            public int dwSize; 
            public int dwFlags;
            public String lpUserName; 
            public String lpProfilePath; 
            public String lpDefaultPath; 
            public String lpServerName; 
            public String lpPolicyPath; 
            public IntPtr hProfile; 
        }
    
    
    
        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern Boolean LogonUser 
        (
            String lpszUserName,
            String lpszDomain,
            String lpszPassword,
            LogonType dwLogonType,
            LogonProvider dwLogonProvider,
            out IntPtr phToken
        );
    
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern Boolean CreateProcessAsUser 
        (
            IntPtr hToken,
            String lpApplicationName,
            String lpCommandLine,
            IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes,
            Boolean bInheritHandles,
            Int32 dwCreationFlags,
            IntPtr lpEnvironment,
            String lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation
        );
    
    
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern UInt32 WaitForSingleObject 
        (
            IntPtr hHandle,
            UInt32 dwMilliseconds
        );
    
        [DllImport("kernel32", SetLastError=true)]
        public static extern Boolean CloseHandle (IntPtr handle);
    
        [DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool LoadUserProfile(IntPtr hToken, ref ProfileInfo lpProfileInfo);
    
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
    
        #endregion
    
        #region "FUNCTIONS"
    
        public static void LaunchCommand2(string strCommand, string strDomain, string strName, string strPassword)
        {
            // Variables
            WindowsIdentity m_ImpersonatedUser;
            IntPtr tokenDuplicate = IntPtr.Zero;
            PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
            STARTUPINFO startInfo = new STARTUPINFO();
            Boolean bResult = false;
            IntPtr hToken = IntPtr.Zero;
            UInt32 uiResultWait = WAIT_FAILED;
            string executableFile = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
            const int SecurityImpersonation = 2;
    
    
            try 
            {
                // Logon user
                bResult = Win32.LogonUser(
                    strName,
                    strDomain,
                    strPassword,
                    Win32.LogonType.LOGON32_LOGON_INTERACTIVE,
                    Win32.LogonProvider.LOGON32_PROVIDER_DEFAULT,
                    out hToken
                );
                if (!bResult) { throw new Exception("Logon error #" + Marshal.GetLastWin32Error()); }
    
    
                 #region LoadUserProfile
                        ProfileInfo currentProfile = new ProfileInfo();
                        currentProfile.dwSize = Marshal.SizeOf(currentProfile);
                        currentProfile.lpUserName = strName;
                        currentProfile.dwFlags = 1;                        
                        Boolean bResult2 = LoadUserProfile(hToken, ref currentProfile);
                        Console.WriteLine(bResult2);
    
                        if (!bResult2) { throw new Exception("LoadUserProfile error #" + Marshal.GetLastWin32Error()); }
                       Console.WriteLine(currentProfile.hProfile + "----"+IntPtr.Zero);
    
    
                       if (currentProfile.hProfile == IntPtr.Zero){
                            Console.WriteLine("LoadUserProfile() failed - HKCU handle was not loaded. Error code: " +
                                Marshal.GetLastWin32Error());
                            throw new Exception("LoadUserProfile error #" + Marshal.GetLastWin32Error());
                        }
                 #endregion
    
    
                // Create process
                startInfo.cb = Marshal.SizeOf(startInfo);
                startInfo.lpDesktop = "winsta0\\default";
    
                Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name);
    
    
                if (DuplicateToken(hToken, SecurityImpersonation, ref tokenDuplicate) != 0){
                 m_ImpersonatedUser = new WindowsIdentity(tokenDuplicate);
    
                    if(m_ImpersonatedUser.Impersonate() != null){
                        Console.WriteLine("After Impersonation succeeded: " + Environment.NewLine +
                                                      "User Name: " +
                                                      WindowsIdentity.GetCurrent(TokenAccessLevels.MaximumAllowed).Name +
                                                      Environment.NewLine +
                                                      "SID: " +
                                                      WindowsIdentity.GetCurrent(TokenAccessLevels.MaximumAllowed).User.
                                                          Value);
                        Console.WriteLine(m_ImpersonatedUser);
                    }
    
    
                    bResult = Win32.CreateProcessAsUser(
                    tokenDuplicate, 
                    executableFile, 
                    strCommand, 
                    IntPtr.Zero,
                    IntPtr.Zero,
                    false,
                    0,
                    IntPtr.Zero,
                    null,
                    ref startInfo,
                    out processInfo
                );
                if (!bResult) { throw new Exception("CreateProcessAsUser error #" + Marshal.GetLastWin32Error()); }
    
            }
    
                // Wait for process to end
                uiResultWait = WaitForSingleObject(processInfo.hProcess, INFINITE);
                if (uiResultWait == WAIT_FAILED) { throw new Exception("WaitForSingleObject error #" + Marshal.GetLastWin32Error()); }
            }
            finally 
            {
                // Close all handles
                CloseHandle(hToken);
                CloseHandle(processInfo.hProcess);
                CloseHandle(processInfo.hThread);
            }
        }
    
        #endregion
    }
    // Interface between powershell and C#    
    public class CreateProcessCaller
    {
        public static void modifyEnvParamWrapper2(string strCommand, string strDomain, string strName, string strPassword)
        {
            Win32.LaunchCommand2(strCommand, strDomain, strName, strPassword);
        }
    }
    } 
    
    '@
    # End-of C# section
    
    
    Add-Type -TypeDefinition $createPocess -Language CSharp -IgnoreWarnings
    
    
    Function modifyEnvParamWOWindow([String]$command, [String]$strDomain, [String]$strName, [String]$strPassword) {
    
    try {
        [CreateProcessUtility.CreateProcessCaller]::modifyEnvParamWrapper2($command, $strDomain, $strName, $strPassword)
        return $True
    } catch {
        write-host "Unable to modify regestry entry: " $_
        return $False
    }
    }  
    

1 个答案:

答案 0 :(得分:0)

由于您还根据CreateProcessAsUser的文档指定了StartupInfo中的lpDesktop参数:

  

...您必须更改默认交互式窗口站和默认桌面的自主访问控制列表(DACL)。窗口站和桌面的DACL必须授予用户或hToken参数表示的登录会话的访问权限。

我的猜测是这是导致拒绝访问错误的原因。

但是,根据CreateProcessAsUser的文档,传递的令牌必须是主令牌。但是,您使用DuplicateToken创建令牌,该令牌仅创建模拟令牌。

因此,您需要使用DuplicateTokenEx创建主令牌,并将TokenPrimary(= 1)作为第5个参数,并在CreateProcessAsUser调用中使用此令牌(如果这是即使在桌面和WindowStation上设置权限后也能正常工作。