0

I am trying to use CreateProcessAsUser method. But I am getting Error code - 5

This is what I do .

  1. LoadUserProfile
  2. DuplicateToken
  3. ImpersonateUser
  4. CreateProcessAsUser - with duplicateToken

Can someone help me out

Regards

Code

# 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
}
}  
Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
ajax
  • 317
  • 8
  • 17

1 Answers1

0

Since you are also specifying the lpDesktop parameter in the StartupInfo, per the documentation for CreateProcessAsUser:

...you must change the discretionary access control list (DACL) of both the default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the user or the logon session represented by the hToken parameter.

My guess is that this is the cause of the Access Denied error.

However, also per the documentation for CreateProcessAsUser, the token passed must be a primary token. You are however creating the token using DuplicateToken which only creates impersonation tokens.

So you will need to create a primary token using DuplicateTokenEx, passing TokenPrimary (= 1) as the 5th parameter, and use this token in your CreateProcessAsUser call if this is to work even after setting the permissions on the Desktop and WindowStation.

Iridium
  • 23,323
  • 6
  • 52
  • 74
  • I changed the lpDesktop to null - and tried executing a command like powershell -Command mkdir C:\myTemp with user myUser - domain - password respectively But this fails as no folder is created – ajax Nov 08 '12 at 15:06
  • @ajax That's potentially a different issue. Does the CreateProcessAsUser call now succeed? Does the process get created? Does it attempt to create the directory and fail? – Iridium Nov 08 '12 at 15:25
  • Yes the CreateProcessAsUser succeeds but no folder is created. I am completely lost cos I folled msdn docu and still it not working. thanks for ur continuous support :-) – ajax Nov 08 '12 at 17:16