Createprocessasuser error 1314

I want create a process under another user. So I use LogonUser and CreateProcessAsUser. But my problem is, that CreatePtocessAsUser always returns the errorcode 1314, which means "A required privil...

I want create a process under another user. So I use LogonUser and CreateProcessAsUser. But my problem is, that CreatePtocessAsUser always returns the errorcode 1314, which means «A required privilige is not held by the client». So my question is, what I am doing wrong? Or how can i give the priviliges to the handle? (I think the handle should have the privileges, or I am wrong?) Sorry for my english mistakes, but my english knowledge isn’t the best :)

Plesase help if anyone knows how to correct my application.

This a part of my code.

STARTUPINFO StartInfo;
PROCESS_INFORMATION ProcInfo;
TOKEN_PRIVILEGES tp;
memset(&ProcInfo, 0, sizeof(ProcInfo));
memset(&StartInfo, 0 , sizeof(StartInfo)); 
StartInfo.cb = sizeof(StartInfo); 
HANDLE handle = NULL;

if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ALL_ACCESS, &handle)) printf("nOpenProcessError");

if (!LookupPrivilegeValue(NULL,SE_TCB_NAME,
//SE_TCB_NAME,
&tp.Privileges[0].Luid)) {
printf("nLookupPriv error");
}

tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes =
SE_PRIVILEGE_ENABLED;//SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(handle, FALSE, &tp, 0, NULL, 0)) {
printf("nAdjustToken error");
}

i = LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &handle);
printf("nLogonUser return  : %d",i);
i = GetLastError();
printf("nLogonUser getlast : %d",i);
if (! ImpersonateLoggedOnUser(handle) ) printf("nImpLoggedOnUser!");

i = CreateProcessAsUser(handle, "c:\windows\system32\notepad.exe",NULL, NULL, NULL, true, 
CREATE_UNICODE_ENVIRONMENT |NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, NULL, 
&StartInfo, &ProcInfo);    
printf("nCreateProcessAsUser return  : %d",i);
i = GetLastError();
printf("nCreateProcessAsUser getlast : %d",i);

CloseHandle(handle); 
CloseHandle(ProcInfo.hProcess); 
CloseHandle(ProcInfo.hThread); 

Thanks in advance!

  • Remove From My Forums
  • Question

  • Hi,
      I have this service running under a non-administrative user which will call CreateProcessAsUser to create another process. This new process needs to be created with elevated token.

    In the service i have code like this to call CreateProcessAsUser. As you can see i have hardcoded the username and password for now. But that is ok.

    public static void CreateMyProcess() {
    
                const int LOGON32_PROVIDER_DEFAULT = 0;
                const int LOGON32_LOGON_INTERACTIVE = 2;
                const int LOGON32_LOGON_BATCH = 4;
    
                string domainName = "."; // local computer
                string userName = "adminuser"; //administrative user
                string password = "password";
    
                IntPtr tokenHandle = IntPtr.Zero;
    
                bool returnValue = LogonUser(
                       userName,
                       domainName,
                       password,
                       LOGON32_LOGON_BATCH,
                       LOGON32_PROVIDER_DEFAULT,
                       ref tokenHandle);
    
                PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
    
                SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
                sa.Length = Marshal.SizeOf(sa);
    
    
                STARTUPINFO si = new STARTUPINFO();
                si.cb = Marshal.SizeOf(si);
                si.lpDesktop = String.Empty;
    
                returnValue = CreateProcessAsUser(
                               tokenHandle,
                               @"c:windowssystem32calc.exe",
                               String.Empty,
                               ref sa, ref sa,
                               false, 0, IntPtr.Zero,
                               @"C:", ref si, ref pi
                         );
    
                
                int errCode = Marshal.GetLastWin32Error();
    
            }
    

    However, after the call to CreateProcessAsUser i get the error 1314 : «A required privilege is not held by client». I read in the same forumn from other users that 1314 means SeTCBPrivilege. Any idea how this issue can be resolved? How do i give the SeTCBPrivilege to the nonAdminUser ?

    Note that, if the Service is run as an Administrative user, the call succeeds.

    Thanks
    Santhosh

  • Remove From My Forums
  • Question

  • Hello Forum

    I have a server where some processes require xp_cmdShell.  This feature is enabled and I have created the xp_cmdShell proxy credential.  The proxy credential is using the same credentials as the SQL Server Services; these crededentials have full
    domain admin rights and SQ Server SysAdmin rights however we are getting the error above.

    OS is Windows Server 2003, SQL Server is 2005 Standard SP4.


    Please click «Mark As Answer» if my post helped. Tony C.

Answers

  • https://msdn.microsoft.com/en-us/library/windows/desktop/ms682429%28v=vs.85%29.aspx
    says:

    Typically, the process that calls the CreateProcessAsUser function must have the SE_INCREASE_QUOTA_NAME privilege and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege if the token is not assignable. If this function fails with ERROR_PRIVILEGE_NOT_HELD
    (1314),

    So talk with your Windows admin and make sure that the service account for SQL Server has these permissions. (My guess it is that this happens when SQL Server tries to create the process with ProxyUser.)

    What permissions that are assigned inside SQL Server are of course entirely irrelevant, as this is a Windows issue.


    Erland Sommarskog, SQL Server MVP, esquel@sommarskog.se

    • Marked as answer by

      Friday, May 15, 2015 9:12 AM

  • Sorry, I said Agent, when I meant the db engine. If you changes the account for the db engine using the wrong tool, then the db engine won’t have the required priviliges for this operation (see the other posts). You can try to change to sometihing else as
    a test (for instance Network Service) using SQL Server Configuration Manager and see if it works. And then change back (again, using the proper tool). That should give you further insight into the situation.

    The reason it worked while you are sa is that as sysadmin, SQL Server won’t start thet process as somebody else — i.e., that privilege wan’t required.


    Tibor Karaszi, SQL Server MVP |
    web | blog

    • Marked as answer by
      Lydia ZhangMicrosoft contingent staff
      Friday, May 15, 2015 9:12 AM

  • Combining the responses by Tibor and Erland, it seems the SQL Server service account was changed at some point such that all of the advanced rights needed for non-sysadmin xp_cmdshell were not assigned. Note that these are advanced rights that
    even domain and local admins do not have by default.  The SQL Server installer assigns the needed permissions during install and the Configuration Manager post-install.

    Although you could have your sysadmins assign the necessary rights manually, I suggest you use SQL Server configuration Manager as Tibor suggested unless you have a reason to do it the hard way.


    Dan Guzman, SQL Server MVP, http://www.dbdelta.com

    • Marked as answer by
      Lydia ZhangMicrosoft contingent staff
      Friday, May 15, 2015 9:12 AM

Я хочу создать процесс под другим пользователем. Поэтому я использую LogonUser и CreateProcessAsUser. Но моя проблема в том, что CreatePtocessAsUser всегда возвращает код ошибки 1314, что означает «Клиент не имеет необходимых привилегий». Итак, мой вопрос: что я делаю не так? Или как я могу дать ручке привилегии? (Я думаю, что у дескриптора должны быть привилегии, или я ошибаюсь?) Извините за мои ошибки в английском, но мои знания английского не самые лучшие :)

Пожалуйста, помогите, если кто знает, как исправить мою заявку.

Это часть моего кода.

STARTUPINFO StartInfo;
PROCESS_INFORMATION ProcInfo;
TOKEN_PRIVILEGES tp;
memset(&ProcInfo, 0, sizeof(ProcInfo));
memset(&StartInfo, 0 , sizeof(StartInfo)); 
StartInfo.cb = sizeof(StartInfo); 
HANDLE handle = NULL;

if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ALL_ACCESS, &handle)) printf("nOpenProcessError");

if (!LookupPrivilegeValue(NULL,SE_TCB_NAME,
//SE_TCB_NAME,
&tp.Privileges[0].Luid)) {
printf("nLookupPriv error");
}

tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes =
SE_PRIVILEGE_ENABLED;//SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(handle, FALSE, &tp, 0, NULL, 0)) {
printf("nAdjustToken error");
}

i = LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &handle);
printf("nLogonUser return  : %d",i);
i = GetLastError();
printf("nLogonUser getlast : %d",i);
if (! ImpersonateLoggedOnUser(handle) ) printf("nImpLoggedOnUser!");

i = CreateProcessAsUser(handle, "c:\windows\system32\notepad.exe",NULL, NULL, NULL, true, 
CREATE_UNICODE_ENVIRONMENT |NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, NULL, 
&StartInfo, &ProcInfo);    
printf("nCreateProcessAsUser return  : %d",i);
i = GetLastError();
printf("nCreateProcessAsUser getlast : %d",i);

CloseHandle(handle); 
CloseHandle(ProcInfo.hProcess); 
CloseHandle(ProcInfo.hThread); 

Заранее спасибо!

  • Home
  • VBForums
  • Visual Basic
  • Visual Basic .NET
  • [RESOLVED] VB.Net CreateProcessAsUser API

  1. Jun 1st, 2010, 01:20 PM


    #1

    taigon is offline

    Thread Starter


    Addicted Member


    Resolved [RESOLVED] VB.Net CreateProcessAsUser API

    Can anyone tell me why the following code is giving me error 1314 with CreateProcessAsUser where as the code at the URL http://www.eggheadcafe.com/community…nt-servic.aspx works perfectly fine to run the process as the current user?


  2. Jun 1st, 2010, 01:21 PM


    #2

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Code:

    Option Strict On
    Option Explicit On
    
    Imports System
    Imports System.Runtime.InteropServices
    Imports System.Security.Principal
    Imports System.Security.Permissions
    Imports System.Threading
    Imports System.Text
    
    Module raex
    
    #Region "Const"
    
        Const WINSTA_ALL_ACCESS As Integer = &H37F
        Const LOGON_NETCREDENTIALS_ONLY As Integer = &H1&
        Const CREATE_DEFAULT_ERROR_MODE As Integer = &H4000000
        Private Const CREATE_UNICODE_ENVIRONMENT As Integer = 1024
    
        'Constants for adjusting token privileges.
    
        Const ANYSIZE_ARRAY As Integer = 1
    
        Const TOKEN_QUERY As Integer = &H8
        Const TOKEN_DUPLICATE As Integer = &H2
        Const TOKEN_ASSIGN_PRIMARY As Integer = &H1
        Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20
    
        Const SE_RESTORE_NAME As String = "SeRestorePrivilege"
        Const SE_BACKUP_NAME As String = "SeBackupPrivilege"
        Const SE_TCB_NAME As String = "SeTcbPrivilege"
        Const SE_ASSIGNPRIMARYTOKEN_NAME As String = "SeAssignPrimaryTokenPrivilege"
        Const SE_INCREASE_QUOTA_NAME As String = "SeIncreaseQuotaPrivilege"
        Const SE_PRIVILEGE_ENABLED As Integer = &H2
    
        'Process Startup
        Const SW_HIDE As Integer = 0
        Const SW_NORMAL As Integer = 1
        Const SW_SHOWMINIMIZED As Integer = 2
        Const SW_SHOWMAXIMIZED As Integer = 3
        Const SW_SHOWNOACTIVATE As Integer = 4
        Const SW_SHOW As Integer = 5
        Const SW_MINIMIZE As Integer = 6
        Const SW_SHOWMINNOACTIVE As Integer = 7
        Const SW_SHOWNA As Integer = 8
        Const SW_RESTORE As Integer = 9
        Const SW_SHOWDEFAULT As Integer = 10
    
        Const STARTF_FORCEONFEEDBACK As Integer = &H40
        Const STARTF_FORCEOFFFEEDBACK As Integer = &H80
        Const STARTF_PREVENTPINNING As Integer = &H2000
        Const STARTF_RUNFULLSCREEN As Integer = &H20
        Const STARTF_TITLEISAPPID As Integer = &H1000
        Const STARTF_TITLEISLINKNAME As Integer = &H800
        Const STARTF_USECOUNTCHARS As Integer = &H8
        Const STARTF_USEFILLATTRIBUTE As Integer = &H10
        Const STARTF_USEHOTKEY As Integer = &H200
        Const STARTF_USEPOSITION As Integer = &H4
        Const STARTF_USESHOWWINDOW As Integer = &H1
        Const STARTF_USESIZE As Integer = &H2
        Const STARTF_USESTDHANDLES As Integer = &H100
    
    #End Region
    
    #Region "Enums"
    
        Private Enum Logon32Type
            Interactive = 2
            Network = 3
            Batch = 4
            Service = 5
            Unlock = 7
            NetworkClearText = 8
            NewCredentials = 9
        End Enum
    
        Private Enum Logon32Provider
            [Default] = 0
            WinNT40 = 2
            WinNT50 = 3
        End Enum
    
        Public Enum NERR
            NERR_Success = 0
            NERR_InvalidComputer = 2351
            NERR_NotPrimary = 2226
            NERR_SpeGroupOp = 2234
            NERR_LastAdmin = 2452
            NERR_BadPassword = 2203
            NERR_PasswordTooShort = 2245
            NERR_UserNotFound = 2221
        End Enum
    
        Friend Enum SECURITY_IMPERSONATION_LEVEL
            SecurityAnonymous = 0
            SecurityIdentification = 1
            SecurityImpersonation = 2
            SecurityDelegation = 3
        End Enum
    
        Friend Enum TOKEN_TYPE
            TokenPrimary = 1
            TokenImpersonation = 2
        End Enum
    
    #End Region
    
    #Region "Structures"
    
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure PROCESS_INFORMATION
            Public hProcess As IntPtr
            Public hThread As IntPtr
            Public dwProcessId As System.UInt32
            Public dwThreadId As System.UInt32
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure SECURITY_ATTRIBUTES
            Public nLength As System.UInt32
            Public lpSecurityDescriptor As IntPtr
            Public bInheritHandle As Boolean
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure STARTUPINFO
            Public cb As System.UInt32
            Public lpReserved As String
            Public lpDesktop As String
            Public lpTitle As String
            Public dwX As System.UInt32
            Public dwY As System.UInt32
            Public dwXSize As System.UInt32
            Public dwYSize As System.UInt32
            Public dwXCountChars As System.UInt32
            Public dwYCountChars As System.UInt32
            Public dwFillAttribute As System.UInt32
            Public dwFlags As System.UInt32
            Public wShowWindow As Short
            Public cbReserved2 As Short
            Public lpReserved2 As IntPtr
            Public hStdInput As IntPtr
            Public hStdOutput As IntPtr
            Public hStdError As IntPtr
        End Structure
    
        Private Structure PROFILEINFO
            Public dwSize As Integer
            Public dwFlags As Integer
            Public lpUserName As String
            Public lpProfilePath As String
            Public lpDefaultPath As String
            Public lpServerName As String
            Public lpPolicyPath As String
            Public hProfile As IntPtr
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> Public Structure USER_INFO_3
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_name As String
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_password As String
            Public usri3_password_age As Integer
            Public usri3_priv As Integer
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_home_dir As String
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_comment As String
            Public usri3_flags As Integer
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_script_path As String
            Public usri3_auth_flags As Integer
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_full_name As String
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_usr_comment As String
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_parms As String
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_workstations As String
            Public usri3_last_logon As Integer
            Public usri3_last_logoff As Integer
            Public usri3_acct_expires As Integer
            Public usri3_max_storage As Integer
            Public usri3_units_per_week As Integer
            <MarshalAs(UnmanagedType.U1)> Public usri3_logon_hours As Byte
            Public usri3_bad_pw_count As Integer
            Public usri3_num_logons As Integer
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_logon_server As String
            Public usri3_country_code As Integer
            Public usri3_code_page As Integer
            Public usri3_user_id As Integer
            Public usri3_primary_group_id As Integer
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_profile As String
            <MarshalAs(UnmanagedType.LPWStr)> Public usri3_home_dir_drive As String
            Public usri3_password_expired As Integer
        End Structure
    
        'Structures to adjust token privileges
        Public Structure LUID
            Private lowPart As UInt32
            Private highPart As Int32
        End Structure
    
        Public Structure LUID_AND_ATTRIBUTES
            Public luid As LUID
            Public attributes As UInt32
        End Structure
    
        Structure TOKEN_PRIVILEGES
            Public PrivilegeCount As Integer
            Public Privileges As LUID_AND_ATTRIBUTES
            Public Function Size() As Integer
                Return System.Runtime.InteropServices.Marshal.SizeOf(Me)
            End Function
        End Structure
    
    #End Region


  3. Jun 1st, 2010, 01:22 PM


    #3

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Code:

    #Region "API"
        Private Declare Auto Function LogonUserEx Lib "advapi32.dll" (ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, <Out()> ByRef hToken As IntPtr, ByVal pLogonSid As IntPtr, ByVal pProfileBuffer As IntPtr, ByVal pdwProfileLength As IntPtr, ByVal pQuotaLimits As IntPtr) As Integer
        Private Declare Auto Function ImpersonateLoggedOnUser Lib "advapi32" (ByVal hToken As IntPtr) As Integer
        Private Declare Auto Function CreateEnvironmentBlock Lib "userenv" (ByRef lpEnvironment As IntPtr, ByVal hToken As IntPtr, ByVal bInherit As Boolean) As Boolean
        Private Declare Auto Function GetUserProfileDirectory Lib "userenv" (ByVal hToken As IntPtr, ByVal lpProfileDir As String, ByRef lpcchSize As Integer) As Boolean
        Private Declare Ansi Function LoadUserProfile Lib "userenv" Alias "LoadUserProfileA" (ByVal hToken As IntPtr, ByRef lpProfileInfo As PROFILEINFO) As Boolean
        Private Declare Auto Function DestroyEnvironmentBlock Lib "userenv" (ByVal lpEnvironment As IntPtr) As Boolean
        Private Declare Auto Function UnloadUserProfile Lib "userenv" (ByVal hToken As IntPtr, ByVal hProfile As IntPtr) As Boolean
        Private Declare Auto Function RevertToSelf Lib "advapi32" () As Integer
        Private Declare Auto Function CloseHandle Lib "kernel32" (ByVal hObject As IntPtr) As Integer
        Private Declare Unicode Function NetUserGetInfo Lib "netapi32" (<MarshalAs(UnmanagedType.LPWStr)> ByVal servername As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal username As String, ByVal level As Integer, ByRef bufptr As IntPtr) As Integer
        Private Declare Function NetApiBufferFree Lib "netapi32" (ByVal Buffer As IntPtr) As Integer
        Private Declare Auto Function CreateProcessAsUser Lib "advapi32" (ByVal hToken As IntPtr, ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByRef lpProcessAttributes As SECURITY_ATTRIBUTES, ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Boolean, ByVal dwCreationFlags As Integer, ByVal lpEnvironment As IntPtr, ByVal lpCurrentDirectory As String, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
    
        'API to adjust token privileges
        Declare Function LookupPrivilegeValueA Lib "advapi32.dll" (ByVal lpSystemName As String, ByVal lpName As String, ByRef lpLuid As LUID) As Boolean
        Declare Function AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Int32, ByVal PreviousState As IntPtr, ByVal ReturnLength As IntPtr) As Boolean
    
        Declare Auto Function DuplicateTokenEx Lib "advapi32.dll" (ByVal ExistingTokenHandle As IntPtr, ByVal dwDesiredAccess As UInt32, ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal ImpersonationLevel As Integer, ByVal TokenType As Integer, ByRef DuplicateTokenHandle As System.IntPtr) As Boolean
        Declare Function OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
    
    #End Region
    
        Public Sub CreateProcess(ByVal Username As String, ByVal Domain As String, ByVal Password As String, ByVal Executable As String)
            Dim p_token As IntPtr = IntPtr.Zero
            Dim p_env As IntPtr = IntPtr.Zero
            Dim UserProfile As New PROFILEINFO
    
            StartImpersonation(Username, Domain, Password, p_token, p_env, UserProfile)
    
            Dim DupedToken As IntPtr = IntPtr.Zero
    
            Dim sa As SECURITY_ATTRIBUTES = New SECURITY_ATTRIBUTES
            sa.nLength = Convert.ToUInt32(Marshal.SizeOf(sa))
    
            If DuplicateTokenEx(p_token, Convert.ToUInt32(TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_QUERY), sa, CType(SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Integer), CType(TOKEN_TYPE.TokenPrimary, Integer), DupedToken) = False Then
                myLog.Write("DuplicateTokenEx Failed: " & Marshal.GetLastWin32Error.ToString)
            End If
    
            If Not (DupedToken.Equals(IntPtr.Zero)) Then
                Dim result As Boolean = False
                Dim pi As PROCESS_INFORMATION = New PROCESS_INFORMATION
                Dim saProcess As SECURITY_ATTRIBUTES = New SECURITY_ATTRIBUTES
                Dim saThread As SECURITY_ATTRIBUTES = New SECURITY_ATTRIBUTES
                saProcess.nLength = Convert.ToUInt32(Marshal.SizeOf(saProcess))
                saProcess.bInheritHandle = True
                saThread.nLength = Convert.ToUInt32(Marshal.SizeOf(saThread))
                saThread.bInheritHandle = True
                Dim si As STARTUPINFO = New STARTUPINFO
                si.cb = Convert.ToUInt32(Marshal.SizeOf(si))
                si.lpDesktop = "WinSta0Default"
                si.dwFlags = Convert.ToUInt32(STARTF_USESHOWWINDOW Or STARTF_FORCEONFEEDBACK)
                si.wShowWindow = SW_SHOW
                If CreateProcessAsUser(DupedToken, Nothing, "cmd", saProcess, saThread, True, CREATE_UNICODE_ENVIRONMENT, p_env, Nothing, si, pi) = False Then
                    myLog.Write("CreateProcessAsUser Failed: " & Marshal.GetLastWin32Error.ToString)
                End If
            End If
    
            StopImpersonation(p_env, p_token, UserProfile)
            myLog.Write("User impersonation complete")
        End Sub


  4. Jun 1st, 2010, 01:23 PM


    #4

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Code:

        Private Function StartImpersonation(ByVal UserName As String, ByVal Domain As String, ByVal Password As String, ByRef p_token As IntPtr, ByRef p_env As IntPtr, ByRef UserProfile As PROFILEINFO) As Boolean
            Dim s_ProfileDir As String = New String(CChar("0"), 255)
            Dim p_RoamingProfile As IntPtr = IntPtr.Zero
            Dim NetUserInfo As New USER_INFO_3
    
            If LogonUserEx(UserName, Domain, Password, Logon32Type.Interactive, Logon32Provider.Default, p_token, Nothing, Nothing, Nothing, Nothing) = 0 Then
                myLog.Write("LogonUserEx Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("LogonUserEx Success!")
            End If
    
            If AcquireLoadUserProfilePriveleges(p_token) = False Then
                myLog.Write("Unable to set required access privileges for logon.")
                Exit Function
            End If
    
            If CreateEnvironmentBlock(p_env, p_token, True) = False Then
                myLog.Write("CreateEnvironmentBlock Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("CreateEnvironmentBlock Success!")
            End If
    
            If GetUserProfileDirectory(p_token, s_ProfileDir, 255) = False Then
                myLog.Write("GetUserProfileDirectory Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("GetUserProfileDirectory Success!")
            End If
    
            If NetUserGetInfo(Domain, UserName, 3, p_RoamingProfile) <> NERR.NERR_Success Then
                myLog.Write("NetUserGetInfo Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("NetUserGetInfo Success!")
                NetUserInfo = CType(Marshal.PtrToStructure(p_RoamingProfile, GetType(USER_INFO_3)), USER_INFO_3)
                NetApiBufferFree(p_RoamingProfile)
            End If
    
            UserProfile.lpUserName = UserName
            UserProfile.lpProfilePath = NetUserInfo.usri3_profile
            UserProfile.dwFlags = &H1
            UserProfile.dwSize = Marshal.SizeOf(UserProfile)
    
            If LoadUserProfile(p_token, UserProfile) = False Then
                myLog.Write("LoadUserProfile Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("LoadUserProfile Success! Marshal Returned: " & Marshal.GetLastWin32Error.ToString)
            End If
    
            If ImpersonateLoggedOnUser(p_token) = 0 Then
                myLog.Write("ImpersonateLoggedOnUser Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("ImpersonateLoggedOnUser Success!")
            End If
        End Function
    
        Private Function StopImpersonation(ByRef p_env As IntPtr, ByRef p_token As IntPtr, ByRef UserProfile As PROFILEINFO) As Boolean
            If DestroyEnvironmentBlock(p_env) = False Then
                myLog.Write("DestroyEnvironmentBlock Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("DestroyEnvironmentBlock Success!")
            End If
    
            If RevertToSelf = 0 Then
                myLog.Write("RevertToSelf Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("RevertToSelf Success!")
            End If
    
            If UnloadUserProfile(p_token, UserProfile.hProfile) = False Then
                myLog.Write("UnloadUserProfile Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("UnloadUserProfile Success!")
            End If
    
            If CloseHandle(p_token) = 0 Then
                myLog.Write("CloseHandle(p_token) Error: " & Marshal.GetLastWin32Error.ToString)
            Else
                myLog.Write("CloseHandle Success!")
            End If
    
        End Function
    
        Public Function AcquireLoadUserProfilePriveleges(ByRef hToken As IntPtr) As Boolean
    
            Dim lastWin32Error As Integer = 0
    
            'Get the LUID that corresponds to the backup and restore privileges, if it exists.
            Dim luid_Backup As New LUID
            Dim luid_Restore As New LUID
            Dim luid_TCB As New LUID
            Dim luid_AssignPrimaryToken As New LUID
            Dim luid_IncreaseQuota As New LUID
    
    
            If Not LookupPrivilegeValueA(Nothing, SE_BACKUP_NAME, luid_Backup) Then
                lastWin32Error = Marshal.GetLastWin32Error()
                Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                 "LookupPrivilegeValue failed with error " & lastWin32Error.ToString & ".")
            End If
    
            If Not LookupPrivilegeValueA(Nothing, SE_RESTORE_NAME, luid_Restore) Then
                lastWin32Error = Marshal.GetLastWin32Error()
                Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                 "LookupPrivilegeValue failed with error " & lastWin32Error.ToString & ".")
            End If
    
            If Not LookupPrivilegeValueA(Nothing, SE_TCB_NAME, luid_TCB) Then
                lastWin32Error = Marshal.GetLastWin32Error()
                Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                 "LookupPrivilegeValue failed with error " & lastWin32Error.ToString & ".")
            End If
    
            If Not LookupPrivilegeValueA(Nothing, SE_ASSIGNPRIMARYTOKEN_NAME, luid_AssignPrimaryToken) Then
                lastWin32Error = Marshal.GetLastWin32Error()
                Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                 "LookupPrivilegeValue failed with error " & lastWin32Error.ToString & ".")
            End If
    
            If Not LookupPrivilegeValueA(Nothing, SE_INCREASE_QUOTA_NAME, luid_IncreaseQuota) Then
                lastWin32Error = Marshal.GetLastWin32Error()
                Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                 "LookupPrivilegeValue failed with error " & lastWin32Error.ToString & ".")
            End If
    
            Try
                'Set up a LUID_AND_ATTRIBUTES structure containing the backup and restore privileges, marked as enabled.
                Dim luaAttrBackup As New LUID_AND_ATTRIBUTES
                luaAttrBackup.luid = luid_Backup
                luaAttrBackup.attributes = SE_PRIVILEGE_ENABLED
    
                Dim luaAttrRestore As New LUID_AND_ATTRIBUTES
                luaAttrRestore.luid = luid_Restore
                luaAttrRestore.attributes = SE_PRIVILEGE_ENABLED
    
                Dim luaAttrTCB As New LUID_AND_ATTRIBUTES
                luaAttrTCB.luid = luid_TCB
                luaAttrTCB.attributes = SE_PRIVILEGE_ENABLED
    
                Dim luaAttrAssignPrimaryToken As New LUID_AND_ATTRIBUTES
                luaAttrAssignPrimaryToken.luid = luid_AssignPrimaryToken
                luaAttrAssignPrimaryToken.attributes = SE_PRIVILEGE_ENABLED
    
                Dim luaAttrIncreaseQuota As New LUID_AND_ATTRIBUTES
                luaAttrIncreaseQuota.luid = luid_IncreaseQuota
                luaAttrIncreaseQuota.attributes = SE_PRIVILEGE_ENABLED
    
                'Set up a TOKEN_PRIVILEGES structure containing the backup and restore privileges.
                Dim newState As New TOKEN_PRIVILEGES
                newState.PrivilegeCount = 1
                newState.Privileges = luaAttrBackup
    
                If Not AdjustTokenPrivileges(hToken, False, newState, newState.Size, IntPtr.Zero, IntPtr.Zero) Then
                    lastWin32Error = Marshal.GetLastWin32Error()
                    Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                     "AdjustTokenPrivileges failed with error " & lastWin32Error.ToString & ".")
                End If
    
                newState = New TOKEN_PRIVILEGES
                newState.PrivilegeCount = 1
                newState.Privileges = luaAttrRestore
    
                If Not AdjustTokenPrivileges(hToken, False, newState, newState.Size, IntPtr.Zero, IntPtr.Zero) Then
                    lastWin32Error = Marshal.GetLastWin32Error()
                    Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                     "AdjustTokenPrivileges failed with error " & lastWin32Error.ToString & ".")
                End If
    
                newState = New TOKEN_PRIVILEGES
                newState.PrivilegeCount = 1
                newState.Privileges = luaAttrTCB
    
                If Not AdjustTokenPrivileges(hToken, False, newState, newState.Size, IntPtr.Zero, IntPtr.Zero) Then
                    lastWin32Error = Marshal.GetLastWin32Error()
                    Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                     "AdjustTokenPrivileges failed with error " & lastWin32Error.ToString & ".")
                End If
    
                newState = New TOKEN_PRIVILEGES
                newState.PrivilegeCount = 1
                newState.Privileges = luaAttrAssignPrimaryToken
    
                If Not AdjustTokenPrivileges(hToken, False, newState, newState.Size, IntPtr.Zero, IntPtr.Zero) Then
                    lastWin32Error = Marshal.GetLastWin32Error()
                    Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                     "AdjustTokenPrivileges failed with error " & lastWin32Error.ToString & ".")
                End If
    
                newState = New TOKEN_PRIVILEGES
                newState.PrivilegeCount = 1
                newState.Privileges = luaAttrIncreaseQuota
    
                If Not AdjustTokenPrivileges(hToken, False, newState, newState.Size, IntPtr.Zero, IntPtr.Zero) Then
                    lastWin32Error = Marshal.GetLastWin32Error()
                    Throw New System.ComponentModel.Win32Exception(lastWin32Error, _
                     "AdjustTokenPrivileges failed with error " & lastWin32Error.ToString & ".")
                End If
    
            Catch ex As Exception
                myLog.Write(ex.Message)
                Return False
            End Try
    
            Return True
        End Function
    
    End Module


  5. Jun 1st, 2010, 01:23 PM


    #5

    Re: VB.Net CreateProcessAsUser API

    Is all this just to start a process as a different user? I’m sure there is a much simpler way in .NET that takes about 5 lines… let me have a look


  6. Jun 1st, 2010, 01:32 PM


    #6

    Re: VB.Net CreateProcessAsUser API

    Here you go: http://blogs.msdn.com/b/shawnfa/arch…21/400088.aspx
    Admittedly it still does one call to a very simple Windows API but I think it is an awful lot simpler and more manageable than your current code.

    In fact you could also just use the CreateProcessWithLogonW Windows API and skip the whole process of having to log the user on and get a token etc. You simply pass in the username and password along with the program you want to execute (and a few other options) and it runs the process as the specified user http://msdn.microsoft.com/en-us/libr…31(VS.85).aspx

    Last edited by chris128; Jun 1st, 2010 at 01:38 PM.


  7. Jun 1st, 2010, 02:11 PM


    #7

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    I’ve tried a million and a half things to get this to work. I need my service running as SYSTEM to launch an application on the machine as the specified user. I will try this impersonation method but I doubt it’s going to work. I’ve tried CreateProcessWithLogonW but I think my API declartions were wrong and I’m starting to get tired of this. LoL. So from what you are saying, with that .NET impersonate function, I should be able to just obtain the token from LogonUserEx which I’m using now, and just pass the token to the WindowsIdentity.Impersonate and then just try to launch a process normally as if it were the SYSTEM account just starting a new process?


  8. Jun 1st, 2010, 03:01 PM


    #8

    Re: VB.Net CreateProcessAsUser API

    Well first thing I would ask is are you wanting the user to actually see this application on screen? because without marking the service as Interactive that cannot happen (which is discouraged in XP and doesnt really work at all in Vista/Win7).

    PS Why didnt you explain that in your original post?


  9. Jun 1st, 2010, 03:10 PM


    #9

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Yes, I definately want the user to be able to see the running application and interact with it. I’ve already ensured that the SYSTEM Service is set to Interactive mode.

    I was thinking of trying this because this person said it works. A little different but the strange thing is, I can get it to work perfectly fine if I use the code located at http://www.eggheadcafe.com/community…nt-servic.aspx but the problem is, it uses the token from the currently logged in user by using OpenProcessToken of the «Explorer» process. I would really like to know how to assign TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_QUERY to the users token instead of the process token.

    1. use WTSGetActiveConsoleSessionId to get the ID of the current active Windows session at the console (i.e. the machine keyboard and display, as opposed to WTS sessions).

    2. use WTSQueryUserToken to get the token for that session.

    3. use DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary, &hTokenDup) to duplicate that token.

    4. use CreateEnvironmentBlock to create an environment that you will be passing to the process.

    5. use CreateProcessAsUser with the duplicated token and the created environment. Actually, we use CreateProcessAsUserW, since the A version had some sort of bug on some older systems.

    6. Don’t forget to CloseHandle on the various tokens, etc, and to DestroyEnvironmentBlock the environment.


  10. Jun 1st, 2010, 03:27 PM


    #10

    Re: VB.Net CreateProcessAsUser API

    Quote Originally Posted by taigon
    View Post

    I’ve already ensured that the SYSTEM Service is set to Interactive mode.

    That doesnt really make sense, SYSTEM (aka Local System) is a user account not a service — you set individual services as Interactive, not user accounts… but perhaps I am just misunderstanding you.

    I would suggest you have a read of this as well: http://msdn.microsoft.com/en-us/libr…02(VS.85).aspx

    Specifically:

    Important Services cannot directly interact with a user as of Windows Vista. Therefore, the techniques mentioned in the section titled Using an Interactive Service should not be used in new code.

    Have you actually tried using CreateProcessWithLogonW yet as I still think that might be the best way to go?


  11. Jun 1st, 2010, 03:39 PM


    #11

    Re: VB.Net CreateProcessAsUser API

    Quote Originally Posted by chris128
    View Post

    Have you actually tried using CreateProcessWithLogonW yet as I still think that might be the best way to go?

    In fact, you dont even need to use CreateProcessWithLogonW from .NET code because Process.Start can do the same thing e.g:

    vb.net Code:

    1. Dim pass As New Security.SecureString

    2. pass.AppendChar("p"c)

    3. pass.AppendChar("a"c)

    4. pass.AppendChar("s"c)

    5. pass.AppendChar("s"c)

    6. pass.AppendChar("w"c)

    7. pass.AppendChar("o"c)

    8. pass.AppendChar("r"c)

    9. pass.AppendChar("d"c)

    10. Process.Start("C:SomeFile.exe", "myusername", pass, "mydomain")


  12. Jun 1st, 2010, 03:54 PM


    #12

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    So basically I create a new service using SC which runs as a SYSTEM account. I have configured the application to actually use a service base and accepts commands sent to it remotely. It obtains username/password/process info from a remote application. Then, I need this SERVICE running as the SYSTEM account with the «Allow service to interact with desktop» option selected in services.msc, to run the process as another user. I have already tried the process.start but it doesn’t work when the application runs as a Service however, it does work if it is launched from a domain admin account. So I scrapped that idea. From what I have read, CreateProcessWithLogonW will not work interactively from a service running under the SYSTEM account which I have indeed tried in the past without sucess.

    So this is where I’m stuck…..


  13. Jun 1st, 2010, 04:02 PM


    #13

    Re: VB.Net CreateProcessAsUser API

    Well I would recommend you scrap the idea of having the service being interactive (because for a start your service wont work properly on Vista/Win7/Server2008 like that) and do as the MSDN article suggests and have a separate front end application that communicates with the service via named pipes, TCP/IP, or even use WCF if you are familiar with that. Then you could just have this front end GUI application set to start automatically with Windows but hide itself or just sit in the system tray, waiting for a command from the service that tells it to either show itself on screen or start an external program etc — because that application will be running as the logged on user then you wont have any issues that you are having with the service.
    This is how MS recommends people create services now — a service EXE and a front end user interface EXE that both communicate with each other.


  14. Jun 2nd, 2010, 08:06 AM


    #14

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Ok, I didn’t realize that Windows 7 and up won’t allow for an interactive service. I already configured my client application to use named pipes to communicate with the service that is running on the remote machine. Basically I send it the authentication and process info through the named pipe and then the service is suppose to launch the process as the user specified. The client application that communicates these details first of all makes a copy of the service application to the remote machine, creates a services remotely, and then starts the service which then the named pipe starts listening for the commands. I have embedded the service application into the client as a resource and then I just writeallbytes to the remote machine.

    What would you suggest as an alternative to a service process? Use WMI to create a new interactive process as the admin using the client tool instead and then change the server application which is currently configured as a service base into a regular application with no GUI and then start using the named pipes to create the process as the user specified by the admin?


  15. Jun 2nd, 2010, 08:13 AM


    #15

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Actually, I have a good idea to test.

    I have sucessfully been able to launch a process using CreateProcessAsUser as long as I obtain the process token from «explorer.exe». i should create another executable that gets launched by the service as the currently logged in user and then run CreateProcessAsUser again from the new process to run whatever application I need as the user specified by the admin. I wonder if that will work properly.


  16. Jun 2nd, 2010, 10:56 AM


    #16

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Ok, there is something I’m not getting.

    Using

    CreateProcessAsUser(DupedToken, Nothing, «C:WindowsSystem32cmd.exe», saProcess, saThread, True, Nothing, p_env, «C:WindowsSystem32», si, pi)

    The process runs as the currently logged in user no problem………..
    So I created a new console application that does absolutely nothing but Console.Writeline(«Test») and then Console.ReadKey(). I can launch this executable from windows explorer perfectly fine, but as soon as I try to do CreateProcessAsUser(DupedToken, Nothing, «C:RunAs.exe», saProcess, saThread, True, Nothing, p_env, «C:», si, pi), just like any other application which works fine, it does nothing. I briefly see the process start and then disappear. Any ideas what might be happening? Is there some specific permissions that my newly compiled executable requires in order to be launched by CreateProcessAsUser? Doesn’t make sense why I can start any application on the entire machine without a problem but I can’t start this new executable.


  17. Jun 2nd, 2010, 11:05 AM


    #17

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    I just tried re-creating the entire project for the basic console application that just writes test and then readkey and then I got the following error when it was launched by CreateProcessAsUser

    C:WINDOWSMicrosoft.NETFrameworkv2.0.50727mscorwks.dll could not be loaded

    I then tried running it again and in the task manager I could see the application start and the exit without any message.


  18. Jun 2nd, 2010, 11:42 AM


    #18

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Ok, So, I have just been playin around now for a few hours and I can launch C:WindowsSystem32Runas.exe and then tell it to launch the program as another user but i don’t want the user to have to enter a password on the remote system so….Back to the drawing board. I basically now need to create a separate application that can mimic what the RunAs.exe does but so that a password does not have to be entered by the end user.


  19. Jun 2nd, 2010, 11:54 AM


    #19

    Re: VB.Net CreateProcessAsUser API

    Quote Originally Posted by taigon
    View Post

    I basically now need to create a separate application that can mimic what the RunAs.exe does but so that a password does not have to be entered by the end user.

    I thought that was exactly what you were trying to do anyway?


  20. Jun 2nd, 2010, 11:59 AM


    #20

    Re: VB.Net CreateProcessAsUser API

    Also, I’m totally lost as to what you are trying to do now…

    I dont understand why you cant do what I and MSDN suggested and have an application that runs when a user logs on that the service can communicate with. Then when the service wants to run a process as that logged on user it just communicates with the application (which is already running as that user) and the application starts whatever process you want.
    If you are saying you want to start a process as another user but not the currently logged on user but you dont want to have to specify a password — well there is no way that is ever going to work. How much of a massive security issue would that be if programs could just launch processes as any user without needing the user’s password…


  21. Jun 2nd, 2010, 01:02 PM


    #21

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Well I can’t do that because then this application would need to be installed on 32,000 plus PC’s which is not possible. I am trying to re-create PSEXEC. If this is not possible, then please explain how it is possible for PSEXEC to work.


  22. Jun 2nd, 2010, 01:04 PM


    #22

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Can you please explain to me also why for some reason, this simple console application is not launching??? Everything else I can launch no problem as the currently logged in user.


  23. Jun 2nd, 2010, 01:09 PM


    #23

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Just so you can see what I’ve done here,

    Code:

        Public Sub CreateProcess(ByVal Username As String, ByVal Domain As String, ByVal Password As String, ByVal Executable As String)
            Dim p_token As IntPtr = IntPtr.Zero
            Dim p_env As IntPtr = IntPtr.Zero
            Dim p_processtoken As IntPtr = IntPtr.Zero
            Dim UserProfile As New PROFILEINFO
    
            StartImpersonation(Username, Domain, Password, p_token, p_env, UserProfile)
    
            Dim ps As Process() = Process.GetProcessesByName("explorer")
            Dim p As Process = Process.GetProcessById(ps(0).Id)
    
            If OpenProcessToken(p.Handle, TOKEN_DUPLICATE, p_processtoken) = False Then
                myLog.Write("OpenProcessToken Failed: " & Marshal.GetLastWin32Error.ToString)
            End If
    
            Dim DupedToken As IntPtr = IntPtr.Zero
    
            Dim sa As SECURITY_ATTRIBUTES = New SECURITY_ATTRIBUTES
            sa.nLength = Convert.ToUInt32(Marshal.SizeOf(sa))
    
            If DuplicateTokenEx(p_processtoken, Convert.ToUInt32(TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_QUERY), sa, CType(SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, Integer), CType(TOKEN_TYPE.TokenPrimary, Integer), DupedToken) = False Then
                myLog.Write("DuplicateTokenEx Failed: " & Marshal.GetLastWin32Error.ToString)
            End If
    
            Dim result As Boolean = False
            Dim pi As PROCESS_INFORMATION = New PROCESS_INFORMATION
            Dim saProcess As SECURITY_ATTRIBUTES = New SECURITY_ATTRIBUTES
            Dim saThread As SECURITY_ATTRIBUTES = New SECURITY_ATTRIBUTES
            saProcess.nLength = Convert.ToUInt32(Marshal.SizeOf(saProcess))
            saProcess.bInheritHandle = True
            saThread.nLength = Convert.ToUInt32(Marshal.SizeOf(saThread))
            saThread.bInheritHandle = True
            Dim si As STARTUPINFO = New STARTUPINFO
            si.cb = Convert.ToUInt32(Marshal.SizeOf(si))
            si.dwFlags = Convert.ToUInt32(STARTF_USESHOWWINDOW Or STARTF_FORCEONFEEDBACK)
            si.wShowWindow = SW_SHOW
    
            If CreateProcessAsUser(DupedToken, Nothing, "C:RunAs.exe", saProcess, saThread, True, Nothing, p_env, "C:", si, pi) = False Then
                myLog.Write("CreateProcessAsUser Failed: " & Marshal.GetLastWin32Error.ToString)
            End If
    
            StopImpersonation(p_env, p_token, UserProfile)
            myLog.Write("User impersonation complete")
        End Sub

    This code works perfect even running as a system service without the interactive mode selected. It launches any program under the currently logged in users credentials, except C:RunAs.exe for some weird reason.

    C:RunAs.exe is as follows

    Module RunAs
    Sub Main()
    Console.WriteLine(«test»)
    Console.ReadKey()
    End Sub
    End Module


  24. Jun 2nd, 2010, 01:32 PM


    #24

    Re: VB.Net CreateProcessAsUser API

    Quote Originally Posted by taigon
    View Post

    Well I can’t do that because then this application would need to be installed on 32,000 plus PC’s which is not possible.

    How can that not be possible but installing this service to 32,000 PCs is possible? All you need to do is copy the application EXE to somewhere on the C drive just like you must be doing with the service EXE. Then write the relevant registry entry that tells it to launch this EXE when anyone logs on (which can be done remotely via code easily as long as the remote registry service is started, which it is by default on XP and you can make it start automatically in Win7 easily via group policy).

    I have no idea how PSEXEC works I’m afraid — it was written by someone who has an incredibly good knowledge of how the internals of windows work, so much so that he has written a 600 page book on it and wrote most of the
    Sysinternals apps including Process Monitor and Process Explorer (here’s his blog if you are interested: http://blogs.technet.com/b/markrussinovich/ ). If it was a simple case of calling a couple of APIs then I’m guessing it would have already been done by several other people before PSEXEC came along.


  25. Jun 2nd, 2010, 01:33 PM


    #25

    Re: VB.Net CreateProcessAsUser API

    Quote Originally Posted by taigon
    View Post

    This code works perfect even running as a system service without the interactive mode selected. It launches any program under the currently logged in users credentials, except C:RunAs.exe for some weird reason.

    C:RunAs.exe is as follows

    Module RunAs
    Sub Main()
    Console.WriteLine(«test»)
    Console.ReadKey()
    End Sub
    End Module

    Well it must be more than just that one EXE that does not work or you wouldn’t care. Is it just any .NET app that will not run?


  26. Jun 2nd, 2010, 02:09 PM


    #26

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    No, It seems that I can launch other .NET applications fine. I just tried using this code to launch a different .NET application that I created and it worked no problem. Very strange.


  27. Jun 2nd, 2010, 02:12 PM


    #27

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Quote Originally Posted by chris128
    View Post

    How can that not be possible but installing this service to 32,000 PCs is possible? All you need to do is copy the application EXE to somewhere on the C drive just like you must be doing with the service EXE. Then write the relevant registry entry that tells it to launch this EXE when anyone logs on (which can be done remotely via code easily as long as the remote registry service is started, which it is by default on XP and you can make it start automatically in Win7 easily via group policy).

    I have no idea how PSEXEC works I’m afraid — it was written by someone who has an incredibly good knowledge of how the internals of windows work, so much so that he has written a 600 page book on it and wrote most of the
    Sysinternals apps including Process Monitor and Process Explorer (here’s his blog if you are interested: http://blogs.technet.com/b/markrussinovich/ ). If it was a simple case of calling a couple of APIs then I’m guessing it would have already been done by several other people before PSEXEC came along.

    It’s not possible for me to have this running on every machine because I don’t have the proper authorization to have a constant running service here in this corporation. It seems to be very complicated the way PSEXEC is working but if I can somehow create another application to run CreateProcessWithLogonW, it might just let me launch the process as whatever user I specify from the currently logged on users account.


  28. Jun 2nd, 2010, 02:30 PM


    #28

    Re: VB.Net CreateProcessAsUser API

    You are still going to have to specify this other user’s password though — even PSEXEC will not let you launch a process as any user you want without specifying their password…


  29. Jun 2nd, 2010, 02:34 PM


    #29

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Well yes, definately you will have to specify the password but i didn’t want the end user to have to enter the password, I wanted it so that the admin using the client tool could enter a user/password and it would launch the process on the remote machine with those credentials. But guess what!!! I figured it out!! I can now launch any application on a remote machine either as the currently logged in user or with the secondary application that will be embedded as a resource into the service application, I can launch any application with alternate credentials while being interactive. I will post the code once I finish it up.


  30. Jun 2nd, 2010, 03:28 PM


    #30

    Re: VB.Net CreateProcessAsUser API

    Well yes, definately you will have to specify the password but i didn’t want the end user to have to enter the password, I wanted it so that the admin using the client tool could enter a user/password and it would launch the process on the remote machine with those credentials.

    Ahhh I see, sorry I misunderstood then

    But guess what!!! I figured it out!! I can now launch any application on a remote machine either as the currently logged in user or with the secondary application that will be embedded as a resource into the service application, I can launch any application with alternate credentials while being interactive.

    Nice one, I’m impressed and yeah it would be great if you could post the code (perhaps in the codebank rather than just in this thread?) for others to learn from, including myself


  31. Jun 2nd, 2010, 03:35 PM


    #31

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Most definately I will post the code afterwards! It has been over a month of constantly researching to figure this out. I just need to finish configuring the named pipes and embed the executable into the remote service application as a resource. In the end I will have the ability to chose whether I want to launch the application remotely as the SYSTEM account, the currently logged in user, or any id specified by the admin using the client tool. I’m not going to post the client tool as it is a part of a much larger program but based on the server side code, you can figure out that the client is just copying the service to the remote machine, starting it, and sending it configuration commands. Eventually I want to be able to used the named pipe to communicate the stdErr, stdOut, and stdIn to the client machine so that I can run commands like the command prompt or ipconfig and see it locally.

    I must note though, I do not have any other test environment other than windows xp pro which has a customized image for the company I work at. So if it doesn’t work on Windows 7, I’ll have to figure it out later when they finally role it out.


  32. Jun 2nd, 2010, 03:37 PM


    #32

    Re: VB.Net CreateProcessAsUser API

    Yeah that sounds cool I’m guessing you already know how to redirect the standard input, output and error streams? If not its pretty easy to do and there are several examples on this forum alone.


  33. Jun 2nd, 2010, 05:05 PM


    #33

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Yeah, I do know how to do it to an extent but at least I know how to research, lol.


  34. Jun 4th, 2010, 02:57 PM


    #34

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Ok, well, I’ve finally completed a basic design that allows you to launch a process remotely under the SYSTEM account using a service base application. The service contains a second embedded exe file that is saved dynamically to the local drive and then executed by the service. A named pipe provides the username/password/domain/executable to the embedded program and then it launches the program with CreateProcessWithLogon as the user specified. The service also can launch an interactive program as the currently logged in user, or the system account.

    The service is installed on the remote machine by a client application which I am not including because it is too large and has been designed for a company which I don’t think I’m permitted to name publicly. The client copies the service which I also embedded into the client to the remote machine, starts the service, sends a custom command to start a named pipe, the client connects to the named pipe on the remote system, sends it commands with u/p/d/e as noted above. Then through the PIPE I tell the service to launch the program. Once the program is launched the results are sent back to the client through the pipe. Then the client tells the service to shutdown and once it’s shutdown the client deletes the service and executable from the remote system.

    I will post the 2 separate projects to the codebank.


  35. Jun 4th, 2010, 03:25 PM


    #35

    Re: VB.Net CreateProcessAsUser API

    Sounds good I’m confused by one thing though — why does the service have to create another EXE to launch whatever process was specified? Why cant the service just launch the process itself using the exact same code that this embedded EXE uses?


  36. Jun 4th, 2010, 03:51 PM


    #36

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    The service is running under the SYSTEM account which for some reason won’t allow you to run CreateProcessWithLogonW as the user you have specified. I have no idea why this is the case but I have tried at least 30 different methods to try and get this to work. The service obtains the process token of EXPLORER.exe which gives you the credentials of the user currently logged in. Once you launch the secondary executable as the currently logged in user, then the CreateProcessWithLogonW works perfectly fine. The service can launch any executable as the currently logged in user directly from the service process. The SYSTEM account as long as the service is set to be interactive, will also launch on any XP machine interactively. The service does not need to be set to interactive to launch it as a user. It’s very strange but it works.


  37. Jun 4th, 2010, 03:54 PM


    #37

    Re: VB.Net CreateProcessAsUser API

    Oh right I see, yeah it is a bit odd but it sounds like you have tried pretty much all of the alternatives. I’m guessing this is not designed to work on a terminal server (well any 2003 or 2008 server actually, as even a server that is not a TS server can still have 3 sessions logged on at any one time) as there would be more than one instance of explorer.exe running


  38. Jun 4th, 2010, 04:02 PM


    #38

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    I have to run for my train right now but I will post the code later on….


  39. Jun 4th, 2010, 04:03 PM


    #39

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    No, I’m creating this just for all the users Windows XP machines in the company. I would have to look into what process I could obtain the currently logged in users token from. Could always use WMI on the client to see who is logged in and obtain any process running under that account to duplicate the token from.


  40. Jun 10th, 2010, 08:34 AM


    #40

    taigon is offline

    Thread Starter


    Addicted Member


    Re: VB.Net CreateProcessAsUser API

    Just for anyone attempting to create a tool to run an interactive or non interactive process on a remote XP machine either as another user other than the current user logged in. Follow these steps.

    Create a service on the remote machine with the local system account.

    1) To create a process as the system account — Obtain the process token from the currently running process and use CreateProcessAsUser to launch the process.

    2) To create a process as the currently logged in user — Obtain the process token from any process running as the currently logged in user. Usually «explorer» will work fine. Then use CreateProcessAsUser API once again.

    3) To run a process as any other user — Create a separate executable with code to run CreateProcessWithLogonW and use named pipes to communicate the username/password/domain/process from the service process. Obtain the process token of the currently logged in user in the service process and use CreateProcessAsUser to launch the second executable using the SW_HIDE flag for the process. Now the new process launched will be that of the user specified and will be interactive with the currently logged in users desktop.

    I have no idea if this will work on Windows 7 or not but it is working flawlessly on a Windows XP based network. I have also created API to detect if a user is currently logged into the machine, and if not, then interactive processes will be disabled, but can still launch a process as the system account or as another user. Time to start re-directing the standard output/input/error through the named pipe to the client application.


  • Home
  • VBForums
  • Visual Basic
  • Visual Basic .NET
  • [RESOLVED] VB.Net CreateProcessAsUser API


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
  • BB code is On
  • Smilies are On
  • [IMG] code is On
  • [VIDEO] code is On
  • HTML code is Off

Forum Rules


Click Here to Expand Forum to Full Width

I have a windows service created with Delphi 7, with StartType = stSystem.

Now I need to launch an application to make some things for me.
This application has a MainForm and other GDI resources.
The parameter passed to the application assigns values for some controls (like edits and memos) and then click at a button….

I’m trying this:

var
  token: cardinal;
  si: TStartupInfo;
  pi: TProcessInformation;
begin
  if not LogonUser('admintest', '', 'secret123', LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, token) then
    RaiseLastOSError;

  try
    if not ImpersonateLoggedOnUser(token) then
      RaiseLastOSError;

    fillchar(si, sizeof(si), 0);
    si.cb := sizeof(si);
    si.lpDesktop := PChar('winsta0default');
    if not CreateProcessAsUser(token, nil, '"c:...myapp.exe" -doCrazyThings', nil, nil, false, NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE, nil, nil, si, pi) then
      RaiseLastOSError;

    CloseHandle(pi.hThread);
    waitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
  finally
    CLoseHandle(token);
  end;
end;

When I run my service executable as a normal application (-noservice), it starts as a Forms.Application and creates a MainForm with a button «Start».
*The button runs the same code that service run, but it doesn’t works and it’s rasing the eror code 1314 at createprocessasuser.*

Why? What is the diference between SYSTEM service and a normal application launched by a administrator?

My environment is a Windows 7 Pro x64

What am I doing wrong?
How can I solve this?
Can someone post an example?

Понравилась статья? Поделить с друзьями:
  • Createprocess returned 2 как исправить
  • Createprocess failure error 123
  • Createprocess failed with error code 2 не удается найти указанный файл notepad
  • Createprocess error 740 запрошенная операция требует повышения
  • Createprocess error 740 the requested operation requires elevation