Results 1 to 19 of 19

Thread: Process which is elevated as administrator, run things as non elevated, how?

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Process which is elevated as administrator, run things as non elevated, how?

    I have a problem, my cybercoffe app runs as elevated allways forcefully, and it is all fine, but if it needs run using SHELL command thirds vendor apps, and those apps don't behave well in elevated mode, like STEAM by example, steam running in elevated mode inserts lots of extra things, like file check, forcefuly updates, etc.

    Others Games others platforms seems to run slowly in elevated mode, unknow why, so I needs it to be able to run things in non elevated mode.

    Is there a way to do non elevated executions?

  2. #2

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    investigating I thinks CreateProcessWithTokenW is what I needs... but how to get the token ID?. Anyone did use of such function?

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    well, this is .NET but it is very straight forwared to pass it as VB6....


    Code:
    Imports System.Runtime.InteropServices
    
    Public Class ChangeProcessToken
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
        End Function
    
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Public Shared Function GetTokenInformation(ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS, _
        ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32, _
        ByRef ReturnLength As System.UInt32) As Boolean
        End Function
    
        <DllImport("User32.dll", SetLastError:=True)> _
        Public Shared Function GetShellWindow() As IntPtr
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr, _
                              ByRef lpdwProcessId As IntPtr) As Integer
        End Function
    
        <DllImport("kernel32.dll")> _
        Private Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
        End Function
    
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function DuplicateTokenEx( _
        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
        End Function
    
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function LookupPrivilegeValue(lpSystemName As String, _
       lpName As String, ByRef lpLuid As LUID) As Boolean
        End Function
    
        ' Use this signature if you want the previous state information returned
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function AdjustTokenPrivileges( _
        ByVal TokenHandle As IntPtr, _
        ByVal DisableAllPrivileges As Boolean, _
        ByRef NewState As TOKEN_PRIVILEGES, _
        ByVal BufferLengthInBytes As Integer, _
        ByRef PreviousState As TOKEN_PRIVILEGES, _
        ByRef ReturnLengthInBytes As Integer _
      ) As Boolean
        End Function
    
        <DllImport("advapi32", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function CreateProcessWithTokenW(hToken As IntPtr, dwLogonFlags As Integer, lpApplicationName As String, lpCommandLine As String, dwCreationFlags As Integer, lpEnvironment As IntPtr, lpCurrentDirectory As IntPtr, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
        End Function
    
        <StructLayout(LayoutKind.Sequential)> _
        Structure SECURITY_ATTRIBUTES
            Public nLength As Integer
            Public lpSecurityDescriptor As IntPtr
            Public bInheritHandle As Integer
        End Structure
    
        Public Enum TOKEN_INFORMATION_CLASS
            TokenUser = 1
            TokenGroups
            TokenPrivileges
            TokenOwner
            TokenPrimaryGroup
            TokenDefaultDacl
            TokenSource
            TokenType
            TokenImpersonationLevel
            TokenStatistics
            TokenRestrictedSids
            TokenSessionId
            TokenGroupsAndPrivileges
            TokenSessionReference
            TokenSandBoxInert
            TokenAuditPolicy
            TokenOrigin
            TokenElevationType
            TokenLinkedToken
            TokenElevation
            TokenHasRestrictions
            TokenAccessInformation
            TokenVirtualizationAllowed
            TokenVirtualizationEnabled
            TokenIntegrityLevel
            TokenUIAccess
            TokenMandatoryPolicy
            TokenLogonSid
            MaxTokenInfoClass
        End Enum
    
        Structure TOKEN_PRIVILEGES
            Public PrivilegeCount As Integer
            Public TheLuid As LUID
            Public Attributes As Integer
        End Structure
    
        Structure LUID
            Public LowPart As UInt32
            Public HighPart As UInt32
        End Structure
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
        Structure STARTUPINFO
            Public cb As Integer
            Public lpReserved As String
            Public lpDesktop As String
            Public lpTitle As String
            Public dwX As Integer
            Public dwY As Integer
            Public dwXSize As Integer
            Public dwYSize As Integer
            Public dwXCountChars As Integer
            Public dwYCountChars As Integer
            Public dwFillAttribute As Integer
            Public dwFlags As Integer
            Public wShowWindow As Short
            Public cbReserved2 As Short
            Public lpReserved2 As Integer
            Public hStdInput As Integer
            Public hStdOutput As Integer
            Public hStdError As Integer
        End Structure
    
        Structure PROCESS_INFORMATION
            Public hProcess As IntPtr
            Public hThread As IntPtr
            Public dwProcessId As Integer
            Public dwThreadId As Integer
        End Structure
    
        Public Const SE_PRIVILEGE_ENABLED = &H2L
        Public Const PROCESS_QUERY_INFORMATION = &H400
        Public Const TOKEN_ASSIGN_PRIMARY = &H1
        Public Const TOKEN_DUPLICATE = &H2
        Public Const TOKEN_IMPERSONATE = &H4
        Public Const TOKEN_QUERY = &H8
        Public Const TOKEN_QUERY_SOURCE = &H10
        Public Const TOKEN_ADJUST_PRIVILEGES = &H20
        Public Const TOKEN_ADJUST_GROUPS = &H40
        Public Const TOKEN_ADJUST_DEFAULT = &H80
        Public Const TOKEN_ADJUST_SESSIONID = &H100
        Public Const SecurityImpersonation = 2
        Public Const TokenPrimary = 1
        Public Const SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"
    
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            Dim currentProcess As Process = Process.GetCurrentProcess
            'Enable SeIncreaseQuotaPrivilege in this process.  (This requires administrative privileges.)
            Dim hProcessToken As IntPtr = Nothing
            OpenProcessToken(currentProcess.Handle, TOKEN_ADJUST_PRIVILEGES, hProcessToken)
            Dim tkp As TOKEN_PRIVILEGES
            tkp.PrivilegeCount = 1
            LookupPrivilegeValue(Nothing, SE_INCREASE_QUOTA_NAME, tkp.TheLuid)
            tkp.Attributes = SE_PRIVILEGE_ENABLED
    
            AdjustTokenPrivileges(hProcessToken, False, tkp, 0, Nothing, Nothing)
    
            'Get window handle representing the desktop shell.  This might not work if there is no shell window, or when
            'using a custom shell.  Also note that we're assuming that the shell is not running elevated.
            Dim hShellWnd As IntPtr = GetShellWindow()
    
            'Get the ID of the desktop shell process.
            Dim dwShellPID As IntPtr
            GetWindowThreadProcessId(hShellWnd, dwShellPID)
    
            'Open the desktop shell process in order to get the process token.
            Dim hShellProcess As IntPtr = OpenProcess(PROCESS_QUERY_INFORMATION, False, dwShellPID)
            Dim hShellProcessToken As IntPtr = Nothing
            Dim hPrimaryToken As IntPtr = Nothing
    
            'Get the process token of the desktop shell.
            OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, hShellProcessToken)
    
            'Duplicate the shell's process token to get a primary token.
            Dim dwTokenRights As Integer = TOKEN_QUERY Or TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_ADJUST_DEFAULT Or TOKEN_ADJUST_SESSIONID
            DuplicateTokenEx(hShellProcessToken, dwTokenRights, Nothing, SecurityImpersonation, TokenPrimary, hPrimaryToken)
    
            Dim si As STARTUPINFO = Nothing
            Dim pi As PROCESS_INFORMATION = Nothing
    
            si.cb = Marshal.SizeOf(si)
            CreateProcessWithTokenW(hPrimaryToken, 0, "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe", " E:\Projects\WinApp-NetWork\WinApp-NetWork.sln", 0, Nothing, Nothing, si, pi)
            Console.WriteLine(pi.dwProcessId)
        End Sub
    
        <DllImport("kernel32.dll")> _
        Shared Function CreateProcess(lpApplicationName As IntPtr, _
       lpCommandLine As IntPtr, ByRef lpProcessAttributes As SECURITY_ATTRIBUTES, _
       ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, bInheritHandles As Boolean, _
       dwCreationFlags As UInt32, lpEnvironment As IntPtr, lpCurrentDirectory As String, _
       <[In]()> ByRef lpStartupInfo As STARTUPINFO, _
       <[Out]()> ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
        End Function
    
        Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
            Dim p As Process = New Process
            p.StartInfo.FileName = "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe"
            p.StartInfo.Arguments = "E:\Projects\WinApp-NetWork\WinApp-NetWork.sln"
            p.Start()
            Console.WriteLine(p.Id)
        End Sub
    End Class

  4. #4
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    759

    Re: Process which is elevated as administrator, run things as non elevated, how?

    > "I have a problem, my cybercoffe app runs as elevated allways forcefully, and it is all fine ..."

    I disagree.

    Requiring any application to run permanently elevated is just plain wrong in this day and age. Many users are unable to run such applications because their machines are locked down to the point where they cannot get past the UAC challenge. Way to decimate your potential client base.

    Unless you're Microsoft and can, therefore, ignore you own Rules as and when you feel like it, try to work with UAC instead of trying to fight against it.

    If part of your application need to run elevated, then install it as a Window Service.

    Regards, Phill W.

  5. #5
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Code:
    
    Option Explicit
    
    Private Type PROCESS_INFORMATION
        hProcess As Long
        hThread As Long
        dwProcessId As Long
        dwThreadId As Long
    End Type
    
    Private Type STARTUPINFO
        cb As Long
        lpReserved As Long
        lpDesktop As Long
        lpTitle As Long
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Byte
        hStdInput As Long
        hStdOutput As Long
        hStdError As Long
    End Type
    
    Private Enum TOKEN_TYPE
        TokenPrimary = 1
        TokenImpersonation
    End Enum
    
    Private Enum SECURITY_IMPERSONATION_LEVEL
        SecurityAnonymous
        SecurityIdentification
        SecurityImpersonation
        SecurityDelegation
    End Enum
    
    Private Type TOKEN_PRIVILEGES
        PrivilegeCount  As Long
        LuidLowPart     As Long
        LuidHighPart    As Long
        Attributes      As Long
    End Type
    
    Private Declare Function GetWindowThreadProcessId Lib "User32.dll" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
    Private Declare Function LookupPrivilegeValue Lib "Advapi32.dll" Alias "LookupPrivilegeValueW" (ByVal lpSystemName As Long, ByVal lpName As Long, lpLuid As Long) As Long
    Private Declare Function OpenProcessToken Lib "Advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
    Private Declare Function OpenThreadToken Lib "Advapi32.dll" (ByVal ThreadHandle As Long, ByVal DesiredAccess As Long, ByVal OpenAsSelf As Long, TokenHandle As Long) As Long
    Private Declare Function AdjustTokenPrivileges Lib "Advapi32.dll" (ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, ByVal PreviousState As Long, ByVal ReturnLength As Long) As Long
    Private Declare Function CommandLineToArgvW Lib "shell32.dll" (ByVal lpCmdLine As Long, pNumArgs As Long) As Long
    Private Declare Function lstrlen Lib "kernel32.dll" Alias "lstrlenW" (ByVal lpString As Long) As Long
    Private Declare Function lstrcpyn Lib "kernel32.dll" Alias "lstrcpynW" (ByVal lpString1 As Long, ByVal lpString2 As Long, ByVal iMaxLength As Long) As Long
    Private Declare Function GetMem4 Lib "msvbvm60.dll" (Src As Any, Dst As Any) As Long
    Private Declare Function GlobalFree Lib "kernel32.dll" (ByVal hMem As Long) As Long
    Private Declare Function DuplicateTokenEx Lib "Advapi32.dll" (ByVal hExistingToken As Long, ByVal dwDesiredAccess As Long, ByVal lpTokenAttributes As Long, ByVal ImpersonationLevel As Long, ByVal TokenType As Long, phNewToken As Long) As Long
    Private Declare Function GetShellWindow Lib "User32.dll" () As Long
    Private Declare Function CreateProcessWithTokenW Lib "Advapi32.dll" (ByVal hToken As Long, ByVal dwLogonFlags As Long, ByVal lpApplicationName As Long, ByVal lpCommandLine As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, lpStartupInfo As STARTUPINFO, lpProcessInfo As PROCESS_INFORMATION) As Long
    Private Declare Sub GetStartupInfo Lib "kernel32.dll" Alias "GetStartupInfoW" (lpStartupInfo As STARTUPINFO)
    Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
    Private Declare Function GetCurrentThread Lib "kernel32.dll" () As Long
    Private Declare Function GetCurrentProcess Lib "kernel32.dll" () As Long
    Private Declare Function GetVersionEx Lib "kernel32.dll" Alias "GetVersionExW" (lpVersionInformation As Any) As Long
    
    Private si As STARTUPINFO
    Private pi As PROCESS_INFORMATION
    
    Private Sub Form_Load()
        ProcessRunUnelevated "cmd.exe"
    End Sub
    
    Private Function ProcessRunUnelevated( _
                                ByVal FileName As String, _
                                Optional ByVal CommandLine As String, _
                                Optional ByVal CurrentDirectory As String = vbNullString, _
                                Optional WindowStyle As Long = 1&, _
                                Optional CloseHandles As Boolean = False)
    
        On Error GoTo ErrorHandler:
    
        Const STARTF_USESHOWWINDOW      As Long = 1&
        Const TOKEN_QUERY               As Long = 8&
        Const TOKEN_ASSIGN_PRIMARY      As Long = 1&
        Const TOKEN_DUPLICATE           As Long = 2&
        Const TOKEN_ADJUST_DEFAULT      As Long = &H80&
        Const TOKEN_ADJUST_SESSIONID    As Long = &H100&
        Const PROCESS_QUERY_INFORMATION As Long = 1024&
        Const PROCESS_QUERY_LIMITED_INFORMATION As Long = &H1000&
    
        Const TOKEN_RIGHTS As Long = TOKEN_QUERY Or TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_ADJUST_DEFAULT Or TOKEN_ADJUST_SESSIONID
    
        Dim hShellProcessToken As Long
        Dim hPrimaryToken As Long
        Dim lShellPID   As Long
        Dim hWndShell   As Long
        Dim hProcShell  As Long
        Dim n           As Long
        Dim lr          As Long
        Dim CMDLine     As String
        Dim argc        As Long
        Dim argv()      As String
        Dim bVista      As Boolean
    
        Dim inf(68) As Long
        inf(0) = 276: GetVersionEx inf(0): bVista = (inf(1) >= 6)
    
        CMDLine = """" & FileName & """"                    ' Èìÿ ôàéëà â êàâû÷êè 
    
        If CommandLine <> vbNullString Then                 ' Åñëè åñòü àðãóìåíòû, èõ òîæå äîáàâëÿåì â êàâû÷êàõ 
    
            ParseCommandLine CommandLine, argc, argv        ' Ðàçáèâàåì àðãóìåíòû êîìàíäíîé ñòðîêè íà ñîñòàâëÿþùèå 
            For n = 1 To argc
                CMDLine = CMDLine & " """ & argv(n) & """"
            Next
        End If
    
        'åñëè êîìàíäíàÿ ñòðîêà ïîäãîòîâëåíà äëÿ cmd.exe, íå òðîãàåì àðãóìåíòû 
        If StrComp(FileName, Environ("ComSpec"), 1) = 0 Or StrComp(FileName, "schtasks.exe", 1) = 0 Then
            CMDLine = """" & FileName & """" & " " & CommandLine
        End If
    
        si.cb = Len(si)
        GetStartupInfo si                                   ' êëîíèðóåì ñòðóêòóðó òåêóùåãî ïðîöåññà 
        si.dwFlags = STARTF_USESHOWWINDOW
        si.wShowWindow = WindowStyle                        ' Ñòèëü îêíà 
    
        SetCurrentProcessPrivileges "SeIncreaseQuotaPrivilege"  'CreateProcessWithTokenW 
        SetCurrentProcessPrivileges "SeImpersonatePrivilege"    'CreateProcessWithTokenW 
    
    '    If Not OSver.IsElevated Then 
    '        ProcessRunUnelevated = ProcessRun(FileName, CommandLine, CurrentDirectory, WindowStyle, CloseHandles) 
    '        Exit Function 
    '    End If 
    
    '    If Not ProcessExist("explorer.exe", True) Then 
    '        Debug.Print "ProcessRunUnelevated. No explorer process found." 
    '        Exit Function 
    '    End If 
    
        hWndShell = GetShellWindow()
    
        If hWndShell <> 0 Then
            GetWindowThreadProcessId hWndShell, lShellPID
    
            If lShellPID <> 0 Then
    
                hProcShell = OpenProcess(IIf(bVista, PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_QUERY_INFORMATION), _
                    False, lShellPID)
    
                If hProcShell <> 0 Then
    
                    If OpenProcessToken(hProcShell, TOKEN_DUPLICATE, hShellProcessToken) Then
    
                        If DuplicateTokenEx(hShellProcessToken, TOKEN_RIGHTS, 0&, SecurityImpersonation, TokenPrimary, hPrimaryToken) Then
    
                            lr = CreateProcessWithTokenW(hPrimaryToken, 0&, _
                                ByVal 0&, _
                                StrPtr(CMDLine), _
                                ByVal 0&, _
                                ByVal 0&, _
                                StrPtr(CurrentDirectory), _
                                si, _
                                pi)
    
                            CloseHandle hPrimaryToken
                        End If
                        CloseHandle hShellProcessToken
                    End If
                    CloseHandle hProcShell
                End If
            End If
        End If
    
        ProcessRunUnelevated = lr    ' not 0 is SUCCESS 
    
        If CloseHandles Then
            If pi.hProcess <> 0 Then CloseHandle pi.hProcess
            If pi.hThread <> 0 Then CloseHandle pi.hThread
        End If
    
        Exit Function
    ErrorHandler:
    '    ErrorMsg Err, "clsProcess_ProcessRunUnelevated", "FileName:", FileName, "CommandLine:", CommandLine 
    '    If inIDE Then Stop: Resume Next 
    End Function
    
    Private Function SetCurrentProcessPrivileges(PrivilegeName As String) As Boolean
    
        Const TOKEN_ADJUST_PRIVILEGES As Long = &H20
        Const SE_PRIVILEGE_ENABLED    As Long = 2&
        Const TOKEN_QUERY             As Long = &H8&
        Const ERROR_NO_TOKEN          As Long = 1008&
    
        Dim tp As TOKEN_PRIVILEGES, hToken&
    
        If LookupPrivilegeValue(0&, StrPtr(PrivilegeName), tp.LuidLowPart) Then   'i.e. "SeDebugPrivilege" 
    
            If 0 = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, 1&, hToken) Then
    
                If Err.LastDllError = ERROR_NO_TOKEN Then
    
                    If 0 = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, hToken) Then
                        Exit Function
                    End If
                Else
                    Exit Function
                End If
            End If
    
            tp.PrivilegeCount = 1
            tp.Attributes = SE_PRIVILEGE_ENABLED
            SetCurrentProcessPrivileges = AdjustTokenPrivileges(hToken, 0&, tp, 0&, 0&, 0&)
            CloseHandle hToken
        End If
    End Function
    
    Private Sub ParseCommandLine(Line As String, argc As Long, argv() As String)
        On Error GoTo ErrorHandler:
    
        Dim ptr     As Long
        Dim Index   As Long
        Dim strLen  As Long
        Dim strAdr  As Long
    
        ptr = CommandLineToArgvW(StrPtr(Line), argc)
        ReDim argv(argc)
        argv(0) = App.Path & "\" & App.EXEName & ".exe"
        If argc = 0 Then Exit Sub
    
        For Index = 1 To argc
            GetMem4 ByVal ptr + (Index - 1) * 4, strAdr
            strLen = lstrlen(strAdr)
            argv(Index) = Space$(strLen)
            lstrcpyn StrPtr(argv(Index)), strAdr, strLen + 1
        Next
        GlobalFree ptr
        Exit Sub
    ErrorHandler:
    '    ErrorMsg Err, "clsProcess_ParseCommandLine", "Line:", Line 
    '    If inIDE Then Stop: Resume Next 
    End Sub
    
    
    P.S. Code will not work if process 'explorer.exe' is not launched or launched with elevated token.
    See also: https://stackoverflow.com/questions/...vate-a-process and comments.
    Last edited by Dragokas; Feb 26th, 2018 at 10:12 AM.
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  6. #6

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by Phill.W View Post
    > "I have a problem, my cybercoffe app runs as elevated allways forcefully, and it is all fine ..."

    I disagree.

    Requiring any application to run permanently elevated is just plain wrong in this day and age. Many users are unable to run such applications because their machines are locked down to the point where they cannot get past the UAC challenge. Way to decimate your potential client base.

    Unless you're Microsoft and can, therefore, ignore you own Rules as and when you feel like it, try to work with UAC instead of trying to fight against it.

    If part of your application need to run elevated, then install it as a Window Service.

    Regards, Phill W.
    1) A cybercoffe software is run elevated always bcause they needs to do so much others functions which require it.
    2) CyberCoffes don't follow microsoft rules. by example They do virtualization VHD, but not the Microsoft way, etc. UAC security is mostly disabled always, but there seems to be a performance penalty in most games if runs in elevated mode, unknow why..., but it is measurable.

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by Dragokas View Post
    Code:
    
    Option Explicit
    
    Private Type PROCESS_INFORMATION
        hProcess As Long
        hThread As Long
        dwProcessId As Long
        dwThreadId As Long
    End Type
    
    Private Type STARTUPINFO
        cb As Long
        lpReserved As Long
        lpDesktop As Long
        lpTitle As Long
        dwX As Long
        dwY As Long
        dwXSize As Long
        dwYSize As Long
        dwXCountChars As Long
        dwYCountChars As Long
        dwFillAttribute As Long
        dwFlags As Long
        wShowWindow As Integer
        cbReserved2 As Integer
        lpReserved2 As Byte
        hStdInput As Long
        hStdOutput As Long
        hStdError As Long
    End Type
    
    Private Enum TOKEN_TYPE
        TokenPrimary = 1
        TokenImpersonation
    End Enum
    
    Private Enum SECURITY_IMPERSONATION_LEVEL
        SecurityAnonymous
        SecurityIdentification
        SecurityImpersonation
        SecurityDelegation
    End Enum
    
    Private Type TOKEN_PRIVILEGES
        PrivilegeCount  As Long
        LuidLowPart     As Long
        LuidHighPart    As Long
        Attributes      As Long
    End Type
    
    Private Declare Function GetWindowThreadProcessId Lib "User32.dll" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
    Private Declare Function LookupPrivilegeValue Lib "Advapi32.dll" Alias "LookupPrivilegeValueW" (ByVal lpSystemName As Long, ByVal lpName As Long, lpLuid As Long) As Long
    Private Declare Function OpenProcessToken Lib "Advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
    Private Declare Function OpenThreadToken Lib "Advapi32.dll" (ByVal ThreadHandle As Long, ByVal DesiredAccess As Long, ByVal OpenAsSelf As Long, TokenHandle As Long) As Long
    Private Declare Function AdjustTokenPrivileges Lib "Advapi32.dll" (ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, ByVal PreviousState As Long, ByVal ReturnLength As Long) As Long
    Private Declare Function CommandLineToArgvW Lib "shell32.dll" (ByVal lpCmdLine As Long, pNumArgs As Long) As Long
    Private Declare Function lstrlen Lib "kernel32.dll" Alias "lstrlenW" (ByVal lpString As Long) As Long
    Private Declare Function lstrcpyn Lib "kernel32.dll" Alias "lstrcpynW" (ByVal lpString1 As Long, ByVal lpString2 As Long, ByVal iMaxLength As Long) As Long
    Private Declare Function GetMem4 Lib "msvbvm60.dll" (Src As Any, Dst As Any) As Long
    Private Declare Function GlobalFree Lib "kernel32.dll" (ByVal hMem As Long) As Long
    Private Declare Function DuplicateTokenEx Lib "Advapi32.dll" (ByVal hExistingToken As Long, ByVal dwDesiredAccess As Long, ByVal lpTokenAttributes As Long, ByVal ImpersonationLevel As Long, ByVal TokenType As Long, phNewToken As Long) As Long
    Private Declare Function GetShellWindow Lib "User32.dll" () As Long
    Private Declare Function CreateProcessWithTokenW Lib "Advapi32.dll" (ByVal hToken As Long, ByVal dwLogonFlags As Long, ByVal lpApplicationName As Long, ByVal lpCommandLine As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, lpStartupInfo As STARTUPINFO, lpProcessInfo As PROCESS_INFORMATION) As Long
    Private Declare Sub GetStartupInfo Lib "kernel32.dll" Alias "GetStartupInfoW" (lpStartupInfo As STARTUPINFO)
    Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
    Private Declare Function GetCurrentThread Lib "kernel32.dll" () As Long
    Private Declare Function GetCurrentProcess Lib "kernel32.dll" () As Long
    Private Declare Function GetVersionEx Lib "kernel32.dll" Alias "GetVersionExW" (lpVersionInformation As Any) As Long
    
    Private si As STARTUPINFO
    Private pi As PROCESS_INFORMATION
    
    Private Sub Form_Load()
        ProcessRunUnelevated "cmd.exe"
    End Sub
    
    Private Function ProcessRunUnelevated( _
                                ByVal FileName As String, _
                                Optional ByVal CommandLine As String, _
                                Optional ByVal CurrentDirectory As String = vbNullString, _
                                Optional WindowStyle As Long = 1&, _
                                Optional CloseHandles As Boolean = False)
    
        On Error GoTo ErrorHandler:
    
        Const STARTF_USESHOWWINDOW      As Long = 1&
        Const TOKEN_QUERY               As Long = 8&
        Const TOKEN_ASSIGN_PRIMARY      As Long = 1&
        Const TOKEN_DUPLICATE           As Long = 2&
        Const TOKEN_ADJUST_DEFAULT      As Long = &H80&
        Const TOKEN_ADJUST_SESSIONID    As Long = &H100&
        Const PROCESS_QUERY_INFORMATION As Long = 1024&
        Const PROCESS_QUERY_LIMITED_INFORMATION As Long = &H1000&
    
        Const TOKEN_RIGHTS As Long = TOKEN_QUERY Or TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_ADJUST_DEFAULT Or TOKEN_ADJUST_SESSIONID
    
        Dim hShellProcessToken As Long
        Dim hPrimaryToken As Long
        Dim lShellPID   As Long
        Dim hWndShell   As Long
        Dim hProcShell  As Long
        Dim n           As Long
        Dim lr          As Long
        Dim CMDLine     As String
        Dim argc        As Long
        Dim argv()      As String
        Dim bVista      As Boolean
    
        Dim inf(68) As Long
        inf(0) = 276: GetVersionEx inf(0): bVista = (inf(1) >= 6)
    
        CMDLine = """" & FileName & """"                    ' Èìÿ ôàéëà â êàâû÷êè 
    
        If CommandLine <> vbNullString Then                 ' Åñëè åñòü àðãóìåíòû, èõ òîæå äîáàâëÿåì â êàâû÷êàõ 
    
            ParseCommandLine CommandLine, argc, argv        ' Ðàçáèâàåì àðãóìåíòû êîìàíäíîé ñòðîêè íà ñîñòàâëÿþùèå 
            For n = 1 To argc
                CMDLine = CMDLine & " """ & argv(n) & """"
            Next
        End If
    
        'åñëè êîìàíäíàÿ ñòðîêà ïîäãîòîâëåíà äëÿ cmd.exe, íå òðîãàåì àðãóìåíòû 
        If StrComp(FileName, Environ("ComSpec"), 1) = 0 Or StrComp(FileName, "schtasks.exe", 1) = 0 Then
            CMDLine = """" & FileName & """" & " " & CommandLine
        End If
    
        si.cb = Len(si)
        GetStartupInfo si                                   ' êëîíèðóåì ñòðóêòóðó òåêóùåãî ïðîöåññà 
        si.dwFlags = STARTF_USESHOWWINDOW
        si.wShowWindow = WindowStyle                        ' Ñòèëü îêíà 
    
        SetCurrentProcessPrivileges "SeIncreaseQuotaPrivilege"  'CreateProcessWithTokenW 
        SetCurrentProcessPrivileges "SeImpersonatePrivilege"    'CreateProcessWithTokenW 
    
    '    If Not OSver.IsElevated Then 
    '        ProcessRunUnelevated = ProcessRun(FileName, CommandLine, CurrentDirectory, WindowStyle, CloseHandles) 
    '        Exit Function 
    '    End If 
    
    '    If Not ProcessExist("explorer.exe", True) Then 
    '        Debug.Print "ProcessRunUnelevated. No explorer process found." 
    '        Exit Function 
    '    End If 
    
        hWndShell = GetShellWindow()
    
        If hWndShell <> 0 Then
            GetWindowThreadProcessId hWndShell, lShellPID
    
            If lShellPID <> 0 Then
    
                hProcShell = OpenProcess(IIf(bVista, PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_QUERY_INFORMATION), _
                    False, lShellPID)
    
                If hProcShell <> 0 Then
    
                    If OpenProcessToken(hProcShell, TOKEN_DUPLICATE, hShellProcessToken) Then
    
                        If DuplicateTokenEx(hShellProcessToken, TOKEN_RIGHTS, 0&, SecurityImpersonation, TokenPrimary, hPrimaryToken) Then
    
                            lr = CreateProcessWithTokenW(hPrimaryToken, 0&, _
                                ByVal 0&, _
                                StrPtr(CMDLine), _
                                ByVal 0&, _
                                ByVal 0&, _
                                StrPtr(CurrentDirectory), _
                                si, _
                                pi)
    
                            CloseHandle hPrimaryToken
                        End If
                        CloseHandle hShellProcessToken
                    End If
                    CloseHandle hProcShell
                End If
            End If
        End If
    
        ProcessRunUnelevated = lr    ' not 0 is SUCCESS 
    
        If CloseHandles Then
            If pi.hProcess <> 0 Then CloseHandle pi.hProcess
            If pi.hThread <> 0 Then CloseHandle pi.hThread
        End If
    
        Exit Function
    ErrorHandler:
    '    ErrorMsg Err, "clsProcess_ProcessRunUnelevated", "FileName:", FileName, "CommandLine:", CommandLine 
    '    If inIDE Then Stop: Resume Next 
    End Function
    
    Private Function SetCurrentProcessPrivileges(PrivilegeName As String) As Boolean
    
        Const TOKEN_ADJUST_PRIVILEGES As Long = &H20
        Const SE_PRIVILEGE_ENABLED    As Long = 2&
        Const TOKEN_QUERY             As Long = &H8&
        Const ERROR_NO_TOKEN          As Long = 1008&
    
        Dim tp As TOKEN_PRIVILEGES, hToken&
    
        If LookupPrivilegeValue(0&, StrPtr(PrivilegeName), tp.LuidLowPart) Then   'i.e. "SeDebugPrivilege" 
    
            If 0 = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, 1&, hToken) Then
    
                If Err.LastDllError = ERROR_NO_TOKEN Then
    
                    If 0 = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, hToken) Then
                        Exit Function
                    End If
                Else
                    Exit Function
                End If
            End If
    
            tp.PrivilegeCount = 1
            tp.Attributes = SE_PRIVILEGE_ENABLED
            SetCurrentProcessPrivileges = AdjustTokenPrivileges(hToken, 0&, tp, 0&, 0&, 0&)
            CloseHandle hToken
        End If
    End Function
    
    Private Sub ParseCommandLine(Line As String, argc As Long, argv() As String)
        On Error GoTo ErrorHandler:
    
        Dim ptr     As Long
        Dim Index   As Long
        Dim strLen  As Long
        Dim strAdr  As Long
    
        ptr = CommandLineToArgvW(StrPtr(Line), argc)
        ReDim argv(argc)
        argv(0) = App.Path & "\" & App.EXEName & ".exe"
        If argc = 0 Then Exit Sub
    
        For Index = 1 To argc
            GetMem4 ByVal ptr + (Index - 1) * 4, strAdr
            strLen = lstrlen(strAdr)
            argv(Index) = Space$(strLen)
            lstrcpyn StrPtr(argv(Index)), strAdr, strLen + 1
        Next
        GlobalFree ptr
        Exit Sub
    ErrorHandler:
    '    ErrorMsg Err, "clsProcess_ParseCommandLine", "Line:", Line 
    '    If inIDE Then Stop: Resume Next 
    End Sub
    
    
    P.S. Code will not work if process 'explorer.exe' is not launched or launched with elevated token.
    See also: https://stackoverflow.com/questions/...vate-a-process and comments.
    about the code, I have question, why it splits command line arguments? if it is simple a whole string?.
    why it even reads the app.path / app.exename ??'

    I thinks it has extras I don't need.

  8. #8
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: Process which is elevated as administrator, run things as non elevated, how?

    why it splits command line arguments? if it is simple a whole string?.
    To meet quotation rules. It's not as easy as you think.
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    https://blogs.msdn.microsoft.com/twi...the-wrong-way/
    Above method is not perfect, but suitable for most cases.

    why it even reads the app.path / app.exename ??'
    To meet C++ argv[] entry point prototype analogue.

    I thinks it has extras I don't need.
    You are free to remove anything you want from my code, just don't sign it with my name in that case.
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by Dragokas View Post
    To meet quotation rules. It's not as easy as you think.
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    https://blogs.msdn.microsoft.com/twi...the-wrong-way/
    Above method is not perfect, but suitable for most cases.


    To meet C++ argv[] entry point prototype analogue.


    You are free to remove anything you want from my code, just don't sign it with my name in that case.
    But I mean it is inform as first argument the module name of the calling app.... not the called app, is that right?

  10. #10
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: Process which is elevated as administrator, run things as non elevated, how?

    I don't know what you mean "first argument".

    Quote Originally Posted by Dragokas
    For n = 1 To argc
    Where app.path is zero (first element) => argv(0).

    Your calling app is here:
    Quote Originally Posted by Dragokas
    CMDLine = """" & FileName & """"
    Program works correctly (tested in Win 7-10). Just run it and see "Elevation" column in Task manager, "Token" column on Process Hacker or whatever you use.
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by Dragokas View Post
    I don't know what you mean "first argument".


    Where app.path is zero (first element) => argv(0).

    Your calling app is here:

    Program works correctly (tested in Win 7-10). Just run it and see "Elevation" column in Task manager, "Token" column on Process Hacker or whatever you use.
    I already using it... the thing I can't specify the CurrentPath ... the third parameter. If there is no command line parameters , it will slide as command line parameter and by example executing chrome, will show the folder in view, instead the google.com (default website)

    Anyway as before was using the simple SHELL instruction, chdir & chdrv was already set in the EXE's location.
    Last edited by flyguille; Feb 27th, 2018 at 09:27 AM.

  12. #12
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Yea, I see. All my CHR extensions crashed and I unable to open any web-address (it is not a problem with working dir., it's something else).
    I don't know why and how to fix it.

    Maybe, try to port another codes by the link I provided earlier or create 2 copies of your application with interprocess communication, 1 - elevated, 2 - not.
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  13. #13
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Here's a simple and easy way of launching an unelevated process from an elevated process:

    Code:
    Private Declare Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As Long, ByRef pclsid As Any) As Long
    Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal cc As Long, ByVal vtReturn As Integer, ByVal cActuals As Long, ByRef prgvt As Integer, ByRef prgpvarg As Long, Optional ByRef pvargResult As Variant) As Long
    Private Declare Function IUnknown_QueryService Lib "shlwapi.dll" (ByVal pUnk As IUnknown, ByRef guidService As Any, ByRef riid As Any, ByRef ppvOut As Any) As Long
    
    Public Sub ShellExecute_via_Explorer(ByRef sFile As String, Optional ByVal vArgs As Variant, _
                                                                Optional ByVal vDir As Variant, _
                                                                Optional ByVal vOperation As Variant, _
                                                                Optional ByVal vShow As Variant)
        Const CC_STDCALL = 4&, QueryActiveShellView_Offset = 15& * 4&, GetItemObject_Offset = 15& * 4&
        Const NOERROR = 0&, S_OK = 0&, SVGIO_BACKGROUND = 0&, SWC_DESKTOP = 8&, SWFO_NEEDDISPATCH = 1&
    
        Dim IShellBrowser As IUnknown, IShellView As IUnknown, Obj As Object, ShellFolderView As Object
        Dim IID_IDispatch(3&) As Long, IID_IShellBrowser(3&) As Long, SID_STopLevelBrowser(3&) As Long
        Dim hWnd As Long, RV As Variant, V(2&) As Variant, VT(2&) As Integer, pV(2&) As Long
    
        Set Obj = CreateObject("Shell.Application").Windows.FindWindowSW(Empty, Empty, SWC_DESKTOP, hWnd, SWFO_NEEDDISPATCH)
        If CLSIDFromString(StrPtr("{4C96BE40-915C-11CF-99D3-00AA004AE837}"), SID_STopLevelBrowser(0&)) <> NOERROR Then Exit Sub
        If CLSIDFromString(StrPtr("{000214E2-0000-0000-C000-000000000046}"), IID_IShellBrowser(0&)) <> NOERROR Then Exit Sub
        If IUnknown_QueryService(Obj, SID_STopLevelBrowser(0&), IID_IShellBrowser(0&), IShellBrowser) <> S_OK Then Exit Sub
        If DispCallFunc(ObjPtr(IShellBrowser), QueryActiveShellView_Offset, CC_STDCALL, vbLong, 1&, vbLong, VarPtr(CVar(VarPtr(IShellView))), RV) <> S_OK Or RV <> S_OK Then Exit Sub
        If CLSIDFromString(StrPtr("{00020400-0000-0000-C000-000000000046}"), IID_IDispatch(0&)) <> NOERROR Then Exit Sub
    
        V(0&) = SVGIO_BACKGROUND:          VT(0&) = vbLong:  pV(0&) = VarPtr(V(0&))
        V(1&) = VarPtr(IID_IDispatch(0&)): VT(1&) = vbLong:  pV(1&) = VarPtr(V(1&))
        V(2&) = VarPtr(ShellFolderView):   VT(2&) = vbLong:  pV(2&) = VarPtr(V(2&))
    
        If DispCallFunc(ObjPtr(IShellView), GetItemObject_Offset, CC_STDCALL, vbLong, 3&, VT(0&), pV(0&), RV) <> S_OK Or RV <> S_OK Then Exit Sub
        ShellFolderView.Application.ShellExecute sFile, vArgs, vDir, vOperation, vShow
    End Sub
    Code:
    Option Explicit
    
    Private Sub Main()
        Const ARGS = "/C ECHO %CD%" & _
                     " & ECHO." & _
                     " & ECHO GROUP INFORMATION" & _
                     " & ECHO -----------------" & _
                     " & ECHO." & _
                     " & whoami /groups | find ""BUILTIN\Administrators""" & _
                     " & whoami /groups | find ""Mandatory Label""" & _
                     " & whoami /priv" & _
                     " & PAUSE > NUL"
    
        ShellExecute_via_Explorer "cmd", ARGS, App.Path
        ShellExecute_via_Explorer "cmd", ARGS, , "runas", vbMaximizedFocus
    End Sub
    The above code is based on the following C++ examples:


  14. #14

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by Victor Bravo VI View Post
    Here's a simple and easy way of launching an unelevated process from an elevated process:

    Code:
    Private Declare Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As Long, ByRef pclsid As Any) As Long
    Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal cc As Long, ByVal vtReturn As Integer, ByVal cActuals As Long, ByRef prgvt As Integer, ByRef prgpvarg As Long, Optional ByRef pvargResult As Variant) As Long
    Private Declare Function IUnknown_QueryService Lib "shlwapi.dll" (ByVal pUnk As IUnknown, ByRef guidService As Any, ByRef riid As Any, ByRef ppvOut As Any) As Long
    
    Public Sub ShellExecute_via_Explorer(ByRef sFile As String, Optional ByVal vArgs As Variant, _
                                                                Optional ByVal vDir As Variant, _
                                                                Optional ByVal vOperation As Variant, _
                                                                Optional ByVal vShow As Variant)
        Const CC_STDCALL = 4&, QueryActiveShellView_Offset = 15& * 4&, GetItemObject_Offset = 15& * 4&
        Const NOERROR = 0&, S_OK = 0&, SVGIO_BACKGROUND = 0&, SWC_DESKTOP = 8&, SWFO_NEEDDISPATCH = 1&
    
        Dim IShellBrowser As IUnknown, IShellView As IUnknown, Obj As Object, ShellFolderView As Object
        Dim IID_IDispatch(3&) As Long, IID_IShellBrowser(3&) As Long, SID_STopLevelBrowser(3&) As Long
        Dim hWnd As Long, RV As Variant, V(2&) As Variant, VT(2&) As Integer, pV(2&) As Long
    
        Set Obj = CreateObject("Shell.Application").Windows.FindWindowSW(Empty, Empty, SWC_DESKTOP, hWnd, SWFO_NEEDDISPATCH)
        If CLSIDFromString(StrPtr("{4C96BE40-915C-11CF-99D3-00AA004AE837}"), SID_STopLevelBrowser(0&)) <> NOERROR Then Exit Sub
        If CLSIDFromString(StrPtr("{000214E2-0000-0000-C000-000000000046}"), IID_IShellBrowser(0&)) <> NOERROR Then Exit Sub
        If IUnknown_QueryService(Obj, SID_STopLevelBrowser(0&), IID_IShellBrowser(0&), IShellBrowser) <> S_OK Then Exit Sub
        If DispCallFunc(ObjPtr(IShellBrowser), QueryActiveShellView_Offset, CC_STDCALL, vbLong, 1&, vbLong, VarPtr(CVar(VarPtr(IShellView))), RV) <> S_OK Or RV <> S_OK Then Exit Sub
        If CLSIDFromString(StrPtr("{00020400-0000-0000-C000-000000000046}"), IID_IDispatch(0&)) <> NOERROR Then Exit Sub
    
        V(0&) = SVGIO_BACKGROUND:          VT(0&) = vbLong:  pV(0&) = VarPtr(V(0&))
        V(1&) = VarPtr(IID_IDispatch(0&)): VT(1&) = vbLong:  pV(1&) = VarPtr(V(1&))
        V(2&) = VarPtr(ShellFolderView):   VT(2&) = vbLong:  pV(2&) = VarPtr(V(2&))
    
        If DispCallFunc(ObjPtr(IShellView), GetItemObject_Offset, CC_STDCALL, vbLong, 3&, VT(0&), pV(0&), RV) <> S_OK Or RV <> S_OK Then Exit Sub
        ShellFolderView.Application.ShellExecute sFile, vArgs, vDir, vOperation, vShow
    End Sub
    Code:
    Option Explicit
    
    Private Sub Main()
        Const ARGS = "/C ECHO %CD%" & _
                     " & ECHO." & _
                     " & ECHO GROUP INFORMATION" & _
                     " & ECHO -----------------" & _
                     " & ECHO." & _
                     " & whoami /groups | find ""BUILTIN\Administrators""" & _
                     " & whoami /groups | find ""Mandatory Label""" & _
                     " & whoami /priv" & _
                     " & PAUSE > NUL"
    
        ShellExecute_via_Explorer "cmd", ARGS, App.Path
        ShellExecute_via_Explorer "cmd", ARGS, , "runas", vbMaximizedFocus
    End Sub
    The above code is based on the following C++ examples:

    this last one looks great, it is like it grab the shell object and make a run like if that object was wanting to run the program? It is guarantee to work in all windows? It won't be seem like a hack of impersonating or so?

  15. #15
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by flyguille View Post
    ... it is like it grab the shell object and make a run like if that object was wanting to run the program?
    Yes. As explained in great detail in the links above, that code works by asking the Windows Explorer process (which is normally unelevated) to invoke a program on behalf of your elevated process. This approach is similar to the solutions above that are based on Aaron Margosis' method in that they both depend on the assumption that Windows Explorer is currently running and is unelevated. The difference of this approach to that of Aaron's is that the parent of the newly spawned process will be explorer.exe rather than your program's EXE, so if your program needs to pass some inheritable handles to its child process(es), this solution is probably not the best choice.

    Quote Originally Posted by flyguille View Post
    It is guarantee to work in all windows?
    I haven't verified it yet, but I believe it should work on XP and newer OSes. The COM interfaces and APIs used are all available and documented (i.e., their behavior is stable) on XP and beyond, so unless Microsoft breaks one or more interfaces/APIs in a future Windows release (highly unlikely), you don't really have anything to worry about.

    EDIT

    Additionally, as is evident in my links above, that solution is the one recommended by both Microsoft and Raymond Chen, so again, there is nothing to worry about.

    Quote Originally Posted by flyguille View Post
    It won't be seem like a hack of impersonating or so?
    That code doesn't do anything too hacky, except maybe for the DispCallFunc calls. However, I don't think Aaron Margosis' technique is hacky either. I've just tried uploading an EXE compiled from that code to VirusTotal and only one AV (Cylance) said it was "Unsafe".
    Last edited by Victor Bravo VI; Feb 28th, 2018 at 02:10 AM.

  16. #16
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Hi, Victor Bravo VI.
    Nice example, and thanks for explanation.
    It looks, your version launch chrome without problems.
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  17. #17

    Thread Starter
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    894

    Re: Process which is elevated as administrator, run things as non elevated, how?

    the only problem against the second example, if it fails, my vb code will not know.

    Other thing it looks like it finds the path of the program, like if you input "chrome.exe" without path, it finds it and run it....., hmmmm, I preffer it to fail than finding it.

  18. #18
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by flyguille
    the only problem against the second example, if it fails, my vb code will not know.
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    If the function succeeds, it returns a value greater than 32
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  19. #19
    Registered User
    Join Date
    Dec 2016
    Location
    Australia
    Posts
    56

    Re: Process which is elevated as administrator, run things as non elevated, how?

    Quote Originally Posted by Victor Bravo VI View Post
    Here's a simple and easy way of launching an unelevated process from an elevated process:

    Code:
    Private Declare Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As Long, ByRef pclsid As Any) As Long
    Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal cc As Long, ByVal vtReturn As Integer, ByVal cActuals As Long, ByRef prgvt As Integer, ByRef prgpvarg As Long, Optional ByRef pvargResult As Variant) As Long
    Private Declare Function IUnknown_QueryService Lib "shlwapi.dll" (ByVal pUnk As IUnknown, ByRef guidService As Any, ByRef riid As Any, ByRef ppvOut As Any) As Long
    
    Public Sub ShellExecute_via_Explorer(ByRef sFile As String, Optional ByVal vArgs As Variant, _
                                                                Optional ByVal vDir As Variant, _
                                                                Optional ByVal vOperation As Variant, _
                                                                Optional ByVal vShow As Variant)
        Const CC_STDCALL = 4&, QueryActiveShellView_Offset = 15& * 4&, GetItemObject_Offset = 15& * 4&
        Const NOERROR = 0&, S_OK = 0&, SVGIO_BACKGROUND = 0&, SWC_DESKTOP = 8&, SWFO_NEEDDISPATCH = 1&
    
        Dim IShellBrowser As IUnknown, IShellView As IUnknown, Obj As Object, ShellFolderView As Object
        Dim IID_IDispatch(3&) As Long, IID_IShellBrowser(3&) As Long, SID_STopLevelBrowser(3&) As Long
        Dim hWnd As Long, RV As Variant, V(2&) As Variant, VT(2&) As Integer, pV(2&) As Long
    
        Set Obj = CreateObject("Shell.Application").Windows.FindWindowSW(Empty, Empty, SWC_DESKTOP, hWnd, SWFO_NEEDDISPATCH)
        If CLSIDFromString(StrPtr("{4C96BE40-915C-11CF-99D3-00AA004AE837}"), SID_STopLevelBrowser(0&)) <> NOERROR Then Exit Sub
        If CLSIDFromString(StrPtr("{000214E2-0000-0000-C000-000000000046}"), IID_IShellBrowser(0&)) <> NOERROR Then Exit Sub
        If IUnknown_QueryService(Obj, SID_STopLevelBrowser(0&), IID_IShellBrowser(0&), IShellBrowser) <> S_OK Then Exit Sub
        If DispCallFunc(ObjPtr(IShellBrowser), QueryActiveShellView_Offset, CC_STDCALL, vbLong, 1&, vbLong, VarPtr(CVar(VarPtr(IShellView))), RV) <> S_OK Or RV <> S_OK Then Exit Sub
        If CLSIDFromString(StrPtr("{00020400-0000-0000-C000-000000000046}"), IID_IDispatch(0&)) <> NOERROR Then Exit Sub
    
        V(0&) = SVGIO_BACKGROUND:          VT(0&) = vbLong:  pV(0&) = VarPtr(V(0&))
        V(1&) = VarPtr(IID_IDispatch(0&)): VT(1&) = vbLong:  pV(1&) = VarPtr(V(1&))
        V(2&) = VarPtr(ShellFolderView):   VT(2&) = vbLong:  pV(2&) = VarPtr(V(2&))
    
        If DispCallFunc(ObjPtr(IShellView), GetItemObject_Offset, CC_STDCALL, vbLong, 3&, VT(0&), pV(0&), RV) <> S_OK Or RV <> S_OK Then Exit Sub
        ShellFolderView.Application.ShellExecute sFile, vArgs, vDir, vOperation, vShow
    End Sub
    Code:
    Option Explicit
    
    Private Sub Main()
        Const ARGS = "/C ECHO %CD%" & _
                     " & ECHO." & _
                     " & ECHO GROUP INFORMATION" & _
                     " & ECHO -----------------" & _
                     " & ECHO." & _
                     " & whoami /groups | find ""BUILTIN\Administrators""" & _
                     " & whoami /groups | find ""Mandatory Label""" & _
                     " & whoami /priv" & _
                     " & PAUSE > NUL"
    
        ShellExecute_via_Explorer "cmd", ARGS, App.Path
        ShellExecute_via_Explorer "cmd", ARGS, , "runas", vbMaximizedFocus
    End Sub
    The above code is based on the following C++ examples:

    Thanks for the idea!
    Of interest is the IShellView pointer in this line:
    Code:
    If DispCallFunc(ObjPtr(IShellBrowser), QueryActiveShellView_Offset, CC_STDCALL, vbLong, 1&, vbLong, VarPtr(CVar(VarPtr(IShellView))), RV
    This value is ByVal according to the function definition, and is initialised as a pointer to the first member in an unitialised struct by its Unknown type.
    In porting the code over to winapi, the idea here might be considered for the UNKNOWN type:
    Code:
    IUnknown *unk = (IUnknown *)((char*)GetWindowLong( pIShellFolder, GWL_USERDATA ) + 12);
    and for 64 bit:
    Code:
    IUnknown *unk = (IUnknown *)((char*)GetWindowLongPtr( pIShellFolder, GWLP_USERDATA ) + 12);
    although the offset value of 12 might want to be adjusted in the second instance. Here, pIShellFolder is the handle derived from SHGetDesktopFolder, but whether that takes us anywhere is another question entirely.
    The real struct for IShellView might be more something like this, so it's great to know VB6 and COM have taken a lot of the leg work out in the Invoke routine!
    Edit: As an afterthought, "all COM objects written in Visual Basic 6 implement IUnknown" and there's this from SO:
    All objects used by VB6 are COM objects. A COM object is essentially a variable length data structure whose variable length header contains any number of 32 bit pointers to VTables, successive bytes contain the instance data of the object.
    Thus, IUnknown only (early binding) and IDispatch (late binding) are the constituents of the well-known dual interface.
    Last edited by lmstearn; Jun 6th, 2020 at 09:00 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width