-
Feb 25th, 2018, 07:04 PM
#1
Thread Starter
Fanatic Member
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?
-
Feb 25th, 2018, 07:29 PM
#2
Thread Starter
Fanatic Member
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?
-
Feb 25th, 2018, 07:40 PM
#3
Thread Starter
Fanatic Member
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
-
Feb 26th, 2018, 07:11 AM
#4
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.
-
Feb 26th, 2018, 10:01 AM
#5
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.
-
Feb 26th, 2018, 02:26 PM
#6
Thread Starter
Fanatic Member
Re: Process which is elevated as administrator, run things as non elevated, how?
Originally Posted by Phill.W
> "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.
-
Feb 26th, 2018, 03:48 PM
#7
Thread Starter
Fanatic Member
Re: Process which is elevated as administrator, run things as non elevated, how?
Originally Posted by Dragokas
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.
-
Feb 26th, 2018, 04:04 PM
#8
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.
-
Feb 26th, 2018, 04:52 PM
#9
Thread Starter
Fanatic Member
Re: Process which is elevated as administrator, run things as non elevated, how?
Originally Posted by Dragokas
But I mean it is inform as first argument the module name of the calling app.... not the called app, is that right?
-
Feb 27th, 2018, 03:24 AM
#10
Re: Process which is elevated as administrator, run things as non elevated, how?
I don't know what you mean "first argument".
Originally Posted by Dragokas
For n = 1 To argc
Where app.path is zero (first element) => argv(0).
Your calling app is here:
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.
-
Feb 27th, 2018, 09:23 AM
#11
Thread Starter
Fanatic Member
Re: Process which is elevated as administrator, run things as non elevated, how?
Originally Posted by Dragokas
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.
-
Feb 27th, 2018, 09:43 AM
#12
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.
-
Feb 27th, 2018, 06:37 PM
#13
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:
-
Feb 27th, 2018, 07:13 PM
#14
Thread Starter
Fanatic Member
Re: Process which is elevated as administrator, run things as non elevated, how?
Originally Posted by Victor Bravo VI
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?
-
Feb 28th, 2018, 02:04 AM
#15
Re: Process which is elevated as administrator, run things as non elevated, how?
Originally Posted by flyguille
... 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.
Originally Posted by flyguille
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.
Originally Posted by flyguille
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.
-
Feb 28th, 2018, 06:26 AM
#16
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.
-
Feb 28th, 2018, 09:48 AM
#17
Thread Starter
Fanatic Member
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.
-
Mar 8th, 2018, 06:14 PM
#18
Re: Process which is elevated as administrator, run things as non elevated, how?
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
-
Jun 2nd, 2020, 10:48 AM
#19
Registered User
Re: Process which is elevated as administrator, run things as non elevated, how?
Originally Posted by Victor Bravo VI
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|