Sign in to follow this  
Followers 0
KaFu

UAC Elevate and DeElevate Scripts

13 posts in this topic

#1 ·  Posted (edited)

Hiho Forum,

for a long time I just ignored the existence of UAC, in fact that's one of the first things to deactivate on a fresh Win7 install :x. But lately I received some complains about my programs regarding UAC, that's why I started to deal with it.

Here's an example of how to elevate and de-elevate a compiled script. Sadly it needs the script to restart, but I've heard that someone's been working on a solution based on AutoItObject to do this in runtime :P.

The example is based on the ShellExecute verb "runas" as pointed out by trancexx and the excellent by Ascend4nt. For your convenience I included the functions in the example below. The latest updates on this UDF will be available on his page.

This script of course needs Vista+ and runs only compiled.

Edit:

Added a checkbox to "Auto-Elevate script on Start". Checking this box will add an "Application Compatibility Flag" to the registry at "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", adding the executable URL as the Key with the "REG_SZ" value "RUNASADMIN". Before moving or deleting the script make sure that the checkbox is unchecked (the registry key is deleted) to not produce an orphaned RegKey.

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#region ;**** Directives created by AutoIt3Wrapper_GUI ****s
#include <GUIButton.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

$sTitle = "UAC Elevate and DeElevate Example"

If StringRegExp(@OSVersion, "_(XP|200(0|3))") Then
    MsgBox(16 + 262144, $sTitle, "Example only works for Vista+ OSs")
    Exit
ElseIf Not @Compiled Then
    MsgBox(16 + 262144, $sTitle, "Example only works compiled")
    Exit
EndIf

$hGui = GUICreate($sTitle, 340, 90, Default,Default,Default, $WS_EX_TOPMOST)

If IsAdmin() Then
    GUICtrlCreateLabel("Script is running in elevated mode (with admin rights)", 10, 10, 320, 20, $SS_CENTER)
Else
    GUICtrlCreateLabel("Script is not running in elevated mode (with standard user rights)", 10, 10, 320, 20, $SS_CENTER)
EndIf

$c_Btn_Elevate = GUICtrlCreateButton("Elevate Script", 25, 30, 130, 30)
If IsAdmin() Then GUICtrlSetState(-1, $GUI_DISABLE)
_GUICtrlButton_SetShield(GUICtrlGetHandle($c_Btn_Elevate))

$c_Btn_DeElevate = GUICtrlCreateButton("Remove Elevation", 165, 30, 130, 30)
If Not IsAdmin() Then GUICtrlSetState(-1, $GUI_DISABLE)

$c_ChkB_Elavate_Always = GUICtrlCreateCheckbox("Auto-Elevate script on Start", 25, 65)
GUICtrlSetTip(-1, "Checking this box will add an ""Application Compatibility Flag"" to the registry at" & @CRLF & @CRLF & _
        "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" & @CRLF & @CRLF & _
        ",adding the executable URL as the Key with the value RUNASADMIN." & @CRLF & @CRLF & _
        "Before moving or deleting the script make sure that the checkbox is unchecked (the registry" & @CRLF & _
        "key is deleted) to not produce an orphaned RegKey.", "Auto-Elevate", 1, 1)
If Not IsAdmin() Then
    GUICtrlSetState(-1, $GUI_DISABLE)
Else
    If RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", @ScriptFullPath) = "RUNASADMIN" Then GUICtrlSetState(-1, $GUI_CHECKED)
EndIf

GUISetState(@SW_SHOW)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $c_Btn_Elevate
            If ShellExecute(@ScriptName, "", "", "runas") Then
                Exit
            Else
                MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong, you canceled the UAC prompt?")
            EndIf

        Case $c_Btn_DeElevate
            $iPID = _RunWithReducedPrivileges(@ScriptName, "", @ScriptDir)
            $iError = @error
            If ProcessExists($iPID) Then
                Exit
            Else
                MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong..." & @CRLF & "Error code: " & $iError)
            EndIf

        Case $c_ChkB_Elavate_Always
            $sRegString = "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
            Switch GUICtrlRead($c_ChkB_Elavate_Always)
                Case 1
                    If Not RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", @ScriptFullPath, "REG_SZ", "RUNASADMIN") Then
                        MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong, could not write AppCompatFlag to Registry.")
                        GUICtrlSetState($c_ChkB_Elavate_Always, $GUI_UNCHECKED)
                    Else
                        MsgBox(16 + 262144, $sTitle, "RUNASADMIN added.")
                    EndIf

                Case Else
                    If Not RegDelete("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", @ScriptFullPath) Then
                        MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong, could not write AppCompatFlag to Registry.")
                        GUICtrlSetState($c_ChkB_Elavate_Always, $GUI_UNCHECKED)
                    Else
                        MsgBox(16 + 262144, $sTitle & " - Error", "RUNASADMIN removed.")
                    EndIf

            EndSwitch

    EndSwitch
WEnd

Exit

; ===============================================================================================================================
; <_RunWithReducedPrivileges.au3>
;
; Function to run a program with reduced privileges.
;   Useful when running in a higher privilege mode, but need to start a program with reduced privileges.
;   - A common problem this fixes is drag-and-drop not working, and misc functions (sendmessage, etc) not working.
;
; Functions:
;   _RunWithReducedPrivileges()     ; runs a process with reduced privileges if currently running in a higher privilege mode
;
; INTERNAL Functions:
;   _RWRPCleanup()      ; Helper function for the above
;
; Reference:
;   See 'Creating a process with Medium Integration Level from the process with High Integration Level in Vista'
;       @ http://www.codeproject.com/KB/vista-security/createprocessexplorerleve.aspx
;     See Elmue's comment 'Here the cleaned and bugfixed code'
;   Also see: 'High elevation can be bad for your application: How to start a non-elevated process at the end of the installation'
;       @ http://www.codeproject.com/KB/vista-security/RunNonElevated.aspx
;     (Elmue has the same code here too in his response to FaxedHead's comment ('Another alternative to this method'))
;   Another alternative using COM methods:
;     'Getting the shell to run an application for you - Part 2:How | BrandonLive'
;       @ http://brandonlive.com/2008/04/27/getting-the-shell-to-run-an-application-for-you-part-2-how/
;
; Author: Ascend4nt, based on code by Elmue's fixed version of Alexey Gavrilov's code
; ===============================================================================================================================

; ===================================================================================================================
; Func _RunWithReducedPrivileges($sPath,$sCmd='',$sFolder='',$iShowFlag=@SW_SHOWNORMAL,$bWait=False)
;
; Function to run a program with reduced privileges.
;   Useful when running in a higher privilege mode, but need to start a program with reduced privileges.
;   - A common problem this fixes is drag-and-drop not working, and misc functions (sendmessage, etc) not working.
;
; $sPath = Path to executable
; $sCmd = Command-line (optional)
; $sFolder = Folder to start in (optional)
; $iShowFlag = how the program should appear on startup. Default is @SW_SHOWNORMAL.
;   All the regular @SW_SHOW* macros should work here
; $bWait = If True, waits for the process to finish before returning with an exit code
;   If False, it returns without waiting for the process to finish, with the process ID #
;
; Returns:
;   Success: If $bWait=True, the exit code of the Process. If $bWait=False, then the Process ID # of the process
;   Failure: 0, with @error set:
;       @error = 2 = DLLCall error. @extended contains the DLLCall error code (see AutoIt Help)
;       @error = 3 = API returned failure. Call 'GetLastError' API function to get more info.
;
; Author: Ascend4nt, based on code by Elmue's fixed version of Alexey Gavrilov's code
; ===================================================================================================================

Func _RunWithReducedPrivileges($sPath, $sCmd = '', $sFolder = '', $iShowFlag = @SW_SHOWNORMAL, $bWait = False)
    Local $aRet, $iErr, $iRet = 1, $hProcess, $hToken, $hDupToken, $stStartupInfo, $stProcInfo
    Local $sCmdType = "wstr", $sFolderType = "wstr"

;~  Run normally if not in an elevated state, or if pre-Vista O/S
    If Not IsAdmin() Or StringRegExp(@OSVersion, "_(XP|200(0|3))") Then ; XP, XPe, 2000, or 2003?
        If $bWait Then Return RunWait($sPath & ' ' & $sCmd, $sFolder)
        Return Run($sPath & ' ' & $sCmd, $sFolder)
    EndIf

;~  Check Parameters and adjust DLLCall types accordingly
    If Not IsString($sCmd) Or $sCmd = '' Then
        $sCmdType = "ptr"
        $sCmd = 0
    EndIf
    If Not IsString($sFolder) Or $sFolder = '' Then
        $sFolderType = "ptr"
        $sFolder = 0
    EndIf
    #cs
        ; STARTUPINFOW struct: cb,lpReserved,lpDesktop,lpTitle,dwX,dwY,dwXSize,dwYSize,dwXCountChars,dwYCountChars,dwFillAttribute,
        ;   dwFlags,wShowWindow,cbReserved2,lpReserved2,hStdInput,hStdOutput,hStdError
        ;   NOTE: This is for process creation info. Also, not sure if the Std I/O can be redirected..?
    #ce
    $stStartupInfo = DllStructCreate("dword;ptr[3];dword[7];dword;word;word;ptr;handle[3]")
    DllStructSetData($stStartupInfo, 1, DllStructGetSize($stStartupInfo))
    DllStructSetData($stStartupInfo, 4, 1) ; STARTF_USESHOWWINDOW
    DllStructSetData($stStartupInfo, 5, $iShowFlag)

    ; PROCESS_INFORMATION struct: hProcess, hThread, dwProcessId, dwThreadId
    ;   This is for *receiving* info
    $stProcInfo = DllStructCreate("handle;handle;dword;dword")

;~  Open a handle to the Process
    ; Explorer runs under a lower privilege, so it is the basis for our security info.
    ;   Open the process with PROCESS_QUERY_INFORMATION (0x0400) access
    $aRet = DllCall("kernel32.dll", "handle", "OpenProcess", "dword", 0x0400, "bool", False, "dword", ProcessExists("explorer.exe"))
    If @error Then Return SetError(2, @error, 0)
    If Not $aRet[0] Then Return SetError(3, 0, 0)
    $hProcess = $aRet[0]

;~  Open a handle to the Process's token (for duplication)
    ; TOKEN_DUPLICATE = 0x0002
    $aRet = DllCall("advapi32.dll", "bool", "OpenProcessToken", "handle", $hProcess, "dword", 2, "handle*", 0)
    If @error Then Return SetError(_RWRPCleanup($hProcess, 0, 0, 2, @error), @extended, 0)
    If $aRet[0] = 0 Then Return SetError(_RWRPCleanup($hProcess, 0, 0, 3), @extended, 0)
    $hToken = $aRet[3]

;~  Duplicate the token handle
    ; TOKEN_ALL_ACCESS = 0xF01FF, SecurityImpersonation = 2, TokenPrimary = 1,
    $aRet = DllCall("advapi32.dll", "bool", "DuplicateTokenEx", "handle", $hToken, "dword", 0xF01FF, "ptr", 0, "int", 2, "int", 1, "handle*", 0)
    If @error Then Return SetError(_RWRPCleanup($hProcess, $hToken, 0, 2, @error), @extended, 0)
    If Not $aRet[0] Then Return SetError(_RWRPCleanup($hProcess, $hToken, 0, 3), @extended, 0)
    $hDupToken = $aRet[6]

;~  Create the process using 'CreateProcessWithTokenW' (Vista+ O/S function)
    $aRet = DllCall("advapi32.dll", "bool", "CreateProcessWithTokenW", "handle", $hDupToken, "dword", 0, "wstr", $sPath, $sCmdType, $sCmd, _
            "dword", 0, "ptr", 0, $sFolderType, $sFolder, "ptr", DllStructGetPtr($stStartupInfo), "ptr", DllStructGetPtr($stProcInfo))
    $iErr = @error
    _RWRPCleanup($hProcess, $hToken, $hDupToken, 2, @error)
    If $iErr Then Return SetError(2, $iErr, 0)
    If Not $aRet[0] Then Return SetError(3, 0, 0)

;~  MsgBox(0,"Info","Process info data: Process handle:"&DllStructGetData($stProcInfo,1)&", Thread handle:"&DllStructGetData($stProcInfo,2)& _
;~      ", Process ID:"&DllStructGetData($stProcInfo,3)&", Thread ID:"&DllStructGetData($stProcInfo,4)&@CRLF)

    $iRet = DllStructGetData($stProcInfo, 3) ; Process ID

;~  If called in 'RunWait' style, wait for the process to close
    If $bWait Then
        ProcessWaitClose($iRet)
        $iRet = @extended ; Exit code
    EndIf

;~  Close Thread and then Process handles (order here is important):
    _RWRPCleanup(0, DllStructGetData($stProcInfo, 2), DllStructGetData($stProcInfo, 1), 0)

    Return $iRet
EndFunc   ;==>_RunWithReducedPrivileges

; ===================================================================================================================
; Func _RWRPCleanup($hProcess,$hToken,$hDupToken,$iErr=0,$iExt=0)
;
; INTERNAL: Helper function for _RunWithReducedPrivileges()
;
; Author: Ascend4nt
; ===================================================================================================================

Func _RWRPCleanup($hProcess, $hToken, $hDupToken, $iErr = 0, $iExt = 0)
    Local $aHandles[3] = [$hToken, $hDupToken, $hProcess] ; order is important
    For $i = 0 To 2
        If $aHandles[$i] <> 0 Then DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $aHandles[$i])
    Next
    Return SetExtended($iExt, $iErr)
EndFunc   ;==>_RWRPCleanup

Enjoy and Best Regards

Edited by KaFu

Share this post


Link to post
Share on other sites



This is great! :x

I just now had a script that needs to do this and like magic this appeared.

Pity it has to restart the app but thats still workable. I just write the variables i'm currently using to a file and have the script look for the file on next start. Picks up right where it left off.

Thanks KaFu

Share this post


Link to post
Share on other sites

Hello! I am here to run DeElevate wrong.

Can you help me? Thank you.

my system:Win7Sp1 X86 Ultimate

post-52920-0-64074900-1305797622_thumb.j

Share this post


Link to post
Share on other sites

The error-code 3 comes from the _RunWithReducedPrivileges UDF by Ascend4nt.

"@error = 3 = API returned failure. Call 'GetLastError' API function to get more info."

I added this line:

If $iError Then $iError &= @CRLF & _WinAPI_GetLastError() & @CRLF & _WinAPI_GetLastErrorMessage()

Check the extended error message and ask Ascend4nt in the _RunWithReducedPrivileges() post mentioned above :unsure:...

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_res_requestedExecutionLevel=asInvoker
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****s
#include <GUIButton.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Winapi.au3>

$sTitle = "UAC Elevate and DeElevate Example"

If StringRegExp(@OSVersion, "_(XP|200(0|3))") Then
    MsgBox(16 + 262144, $sTitle, "Example only works for Vista+ OSs")
    Exit
ElseIf Not @Compiled Then
    MsgBox(16 + 262144, $sTitle, "Example only works compiled")
    Exit
EndIf

$hGui = GUICreate($sTitle, 340, 90, Default, Default, Default, $WS_EX_TOPMOST)

If IsAdmin() Then
    GUICtrlCreateLabel("Script is running in elevated mode (with admin rights)", 10, 10, 320, 20, $SS_CENTER)
Else
    GUICtrlCreateLabel("Script is not running in elevated mode (with standard user rights)", 10, 10, 320, 20, $SS_CENTER)
EndIf

$c_Btn_Elevate = GUICtrlCreateButton("Elevate Script", 25, 30, 130, 30)
If IsAdmin() Then GUICtrlSetState(-1, $GUI_DISABLE)
_GUICtrlButton_SetShield(GUICtrlGetHandle($c_Btn_Elevate))

$c_Btn_DeElevate = GUICtrlCreateButton("Remove Elevation", 165, 30, 130, 30)
If Not IsAdmin() Then GUICtrlSetState(-1, $GUI_DISABLE)

$c_ChkB_Elavate_Always = GUICtrlCreateCheckbox("Auto-Elevate script on Start", 25, 65)
GUICtrlSetTip(-1, "Checking this box will add an ""Application Compatibility Flag"" to the registry at" & @CRLF & @CRLF & _
        "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" & @CRLF & @CRLF & _
        ",adding the executable URL as the Key with the value RUNASADMIN." & @CRLF & @CRLF & _
        "Before moving or deleting the script make sure that the checkbox is unchecked (the registry" & @CRLF & _
        "key is deleted) to not produce an orphaned RegKey.", "Auto-Elevate", 1, 1)
If Not IsAdmin() Then
    GUICtrlSetState(-1, $GUI_DISABLE)
Else
    If RegRead("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", @ScriptFullPath) = "RUNASADMIN" Then GUICtrlSetState(-1, $GUI_CHECKED)
EndIf

GUISetState(@SW_SHOW)

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $c_Btn_Elevate
            If ShellExecute(@ScriptName, "", "", "runas") Then
                Exit
            Else
                MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong, you canceled the UAC prompt?")
            EndIf

        Case $c_Btn_DeElevate
            $iPID = _RunWithReducedPrivileges(@ScriptName, "", @ScriptDir)
            $iError = @error
            If $iError Then $iError &= @CRLF & _WinAPI_GetLastError() & @CRLF & _WinAPI_GetLastErrorMessage()
            If ProcessExists($iPID) Then
                Exit
            Else
                MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong..." & @CRLF & "Error code: " & $iError)
            EndIf

        Case $c_ChkB_Elavate_Always
            $sRegString = "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
            Switch GUICtrlRead($c_ChkB_Elavate_Always)
                Case 1
                    If Not RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", @ScriptFullPath, "REG_SZ", "RUNASADMIN") Then
                        MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong, could not write AppCompatFlag to Registry.")
                        GUICtrlSetState($c_ChkB_Elavate_Always, $GUI_UNCHECKED)
                    Else
                        MsgBox(16 + 262144, $sTitle, "RUNASADMIN added.")
                    EndIf

                Case Else
                    If Not RegDelete("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers", @ScriptFullPath) Then
                        MsgBox(16 + 262144, $sTitle & " - Error", "Something went wrong, could not write AppCompatFlag to Registry.")
                        GUICtrlSetState($c_ChkB_Elavate_Always, $GUI_UNCHECKED)
                    Else
                        MsgBox(16 + 262144, $sTitle & " - Error", "RUNASADMIN removed.")
                    EndIf

            EndSwitch

    EndSwitch
WEnd

Exit

; ===============================================================================================================================
; <_RunWithReducedPrivileges.au3>
;
; Function to run a program with reduced privileges.
;   Useful when running in a higher privilege mode, but need to start a program with reduced privileges.
;   - A common problem this fixes is drag-and-drop not working, and misc functions (sendmessage, etc) not working.
;
; Functions:
;   _RunWithReducedPrivileges()     ; runs a process with reduced privileges if currently running in a higher privilege mode
;
; INTERNAL Functions:
;   _RWRPCleanup()      ; Helper function for the above
;
; Reference:
;   See 'Creating a process with Medium Integration Level from the process with High Integration Level in Vista'
;       @ http://www.codeproject.com/KB/vista-security/createprocessexplorerleve.aspx
;     See Elmue's comment 'Here the cleaned and bugfixed code'
;   Also see: 'High elevation can be bad for your application: How to start a non-elevated process at the end of the installation'
;       @ http://www.codeproject.com/KB/vista-security/RunNonElevated.aspx
;     (Elmue has the same code here too in his response to FaxedHead's comment ('Another alternative to this method'))
;   Another alternative using COM methods:
;     'Getting the shell to run an application for you - Part 2:How | BrandonLive'
;       @ http://brandonlive.com/2008/04/27/gettin...o-run-an-application-for-you-p
;
; Author: Ascend4nt, based on code by Elmue's fixed version of Alexey Gavrilov's code
; ===============================================================================================================================

; ===================================================================================================================
; Func _RunWithReducedPrivileges($sPath,$sCmd='',$sFolder='',$iShowFlag=@SW_SHOWNORMAL,$bWait=False)
;
; Function to run a program with reduced privileges.
;   Useful when running in a higher privilege mode, but need to start a program with reduced privileges.
;   - A common problem this fixes is drag-and-drop not working, and misc functions (sendmessage, etc) not working.
;
; $sPath = Path to executable
; $sCmd = Command-line (optional)
; $sFolder = Folder to start in (optional)
; $iShowFlag = how the program should appear on startup. Default is @SW_SHOWNORMAL.
;   All the regular @SW_SHOW* macros should work here
; $bWait = If True, waits for the process to finish before returning with an exit code
;   If False, it returns without waiting for the process to finish, with the process ID #
;
; Returns:
;   Success: If $bWait=True, the exit code of the Process. If $bWait=False, then the Process ID # of the process
;   Failure: 0, with @error set:
;       @error = 2 = DLLCall error. @extended contains the DLLCall error code (see AutoIt Help)
;       @error = 3 = API returned failure. Call 'GetLastError' API function to get more info.
;
; Author: Ascend4nt, based on code by Elmue's fixed version of Alexey Gavrilov's code
; ===================================================================================================================

Func _RunWithReducedPrivileges($sPath, $sCmd = '', $sFolder = '', $iShowFlag = @SW_SHOWNORMAL, $bWait = False)
    Local $aRet, $iErr, $iRet = 1, $hProcess, $hToken, $hDupToken, $stStartupInfo, $stProcInfo
    Local $sCmdType = "wstr", $sFolderType = "wstr"

;~  Run normally if not in an elevated state, or if pre-Vista O/S
    If Not IsAdmin() Or StringRegExp(@OSVersion, "_(XP|200(0|3))") Then ; XP, XPe, 2000, or 2003?
        If $bWait Then Return RunWait($sPath & ' ' & $sCmd, $sFolder)
        Return Run($sPath & ' ' & $sCmd, $sFolder)
    EndIf

;~  Check Parameters and adjust DLLCall types accordingly
    If Not IsString($sCmd) Or $sCmd = '' Then
        $sCmdType = "ptr"
        $sCmd = 0
    EndIf
    If Not IsString($sFolder) Or $sFolder = '' Then
        $sFolderType = "ptr"
        $sFolder = 0
    EndIf
    #cs
        ; STARTUPINFOW struct: cb,lpReserved,lpDesktop,lpTitle,dwX,dwY,dwXSize,dwYSize,dwXCountChars,dwYCountChars,dwFillAttribute,
        ;   dwFlags,wShowWindow,cbReserved2,lpReserved2,hStdInput,hStdOutput,hStdError
        ;   NOTE: This is for process creation info. Also, not sure if the Std I/O can be redirected..?
    #ce
    $stStartupInfo = DllStructCreate("dword;ptr[3];dword[7];dword;word;word;ptr;handle[3]")
    DllStructSetData($stStartupInfo, 1, DllStructGetSize($stStartupInfo))
    DllStructSetData($stStartupInfo, 4, 1) ; STARTF_USESHOWWINDOW
    DllStructSetData($stStartupInfo, 5, $iShowFlag)

    ; PROCESS_INFORMATION struct: hProcess, hThread, dwProcessId, dwThreadId
    ;   This is for *receiving* info
    $stProcInfo = DllStructCreate("handle;handle;dword;dword")

;~  Open a handle to the Process
    ; Explorer runs under a lower privilege, so it is the basis for our security info.
    ;   Open the process with PROCESS_QUERY_INFORMATION (0x0400) access
    $aRet = DllCall("kernel32.dll", "handle", "OpenProcess", "dword", 0x0400, "bool", False, "dword", ProcessExists("explorer.exe"))
    If @error Then Return SetError(2, @error, 0)
    If Not $aRet[0] Then Return SetError(3, 0, 0)
    $hProcess = $aRet[0]

;~  Open a handle to the Process's token (for duplication)
    ; TOKEN_DUPLICATE = 0x0002
    $aRet = DllCall("advapi32.dll", "bool", "OpenProcessToken", "handle", $hProcess, "dword", 2, "handle*", 0)
    If @error Then Return SetError(_RWRPCleanup($hProcess, 0, 0, 2, @error), @extended, 0)
    If $aRet[0] = 0 Then Return SetError(_RWRPCleanup($hProcess, 0, 0, 3), @extended, 0)
    $hToken = $aRet[3]

;~  Duplicate the token handle
    ; TOKEN_ALL_ACCESS = 0xF01FF, SecurityImpersonation = 2, TokenPrimary = 1,
    $aRet = DllCall("advapi32.dll", "bool", "DuplicateTokenEx", "handle", $hToken, "dword", 0xF01FF, "ptr", 0, "int", 2, "int", 1, "handle*", 0)
    If @error Then Return SetError(_RWRPCleanup($hProcess, $hToken, 0, 2, @error), @extended, 0)
    If Not $aRet[0] Then Return SetError(_RWRPCleanup($hProcess, $hToken, 0, 3), @extended, 0)
    $hDupToken = $aRet[6]

;~  Create the process using 'CreateProcessWithTokenW' (Vista+ O/S function)
    $aRet = DllCall("advapi32.dll", "bool", "CreateProcessWithTokenW", "handle", $hDupToken, "dword", 0, "wstr", $sPath, $sCmdType, $sCmd, _
            "dword", 0, "ptr", 0, $sFolderType, $sFolder, "ptr", DllStructGetPtr($stStartupInfo), "ptr", DllStructGetPtr($stProcInfo))
    $iErr = @error
    _RWRPCleanup($hProcess, $hToken, $hDupToken, 2, @error)
    If $iErr Then Return SetError(2, $iErr, 0)
    If Not $aRet[0] Then Return SetError(3, 0, 0)

;~  MsgBox(0,"Info","Process info data: Process handle:"&DllStructGetData($stProcInfo,1)&", Thread handle:"&DllStructGetData($stProcInfo,2)& _
;~      ", Process ID:"&DllStructGetData($stProcInfo,3)&", Thread ID:"&DllStructGetData($stProcInfo,4)&@CRLF)

    $iRet = DllStructGetData($stProcInfo, 3) ; Process ID

;~  If called in 'RunWait' style, wait for the process to close
    If $bWait Then
        ProcessWaitClose($iRet)
        $iRet = @extended ; Exit code
    EndIf

;~  Close Thread and then Process handles (order here is important):
    _RWRPCleanup(0, DllStructGetData($stProcInfo, 2), DllStructGetData($stProcInfo, 1), 0)

    Return $iRet
EndFunc   ;==>_RunWithReducedPrivileges

; ===================================================================================================================
; Func _RWRPCleanup($hProcess,$hToken,$hDupToken,$iErr=0,$iExt=0)
;
; INTERNAL: Helper function for _RunWithReducedPrivileges()
;
; Author: Ascend4nt
; ===================================================================================================================

Func _RWRPCleanup($hProcess, $hToken, $hDupToken, $iErr = 0, $iExt = 0)
    Local $aHandles[3] = [$hToken, $hDupToken, $hProcess] ; order is important
    For $i = 0 To 2
        If $aHandles[$i] <> 0 Then DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $aHandles[$i])
    Next
    Return SetExtended($iExt, $iErr)
EndFunc   ;==>_RWRPCleanup

Share this post


Link to post
Share on other sites

Hello KaFu!

I'm sorry to bother you

I come from China

my English is poor, on the api do not know

Just run your script

the results are:

Something went wrong...

Error code: 3

1058

Can not start service, probably due to have been disabled or no enabled devices associated.

post-52920-0-75116200-1305807695_thumb.j

I found the problem here: (204 lines)

$aRet = DllCall("advapi32.dll", "bool", "CreateProcessWithTokenW", "handle", $hDupToken, "dword", 0, "wstr", $sPath, $sCmdType, $sCmd, _

"dword", 0, "ptr", 0, $sFolderType, $sFolder, "ptr", DllStructGetPtr($stStartupInfo), "ptr", DllStructGetPtr($stProcInfo))

>>$aRet[0]=0

Share this post


Link to post
Share on other sites

Hi wanghong,

your English is quite good :unsure:, no problem to understand you.

Googeling the error message brought me to this page:

http://powerpivotgeek.com/2010/10/24/snapshots-not-being-taken/

"The error 1058 can have as a root cause the fact the Windows service “Secondary Logon” is disabled.

The service as to be at least in manual (the service will be started by the call to CreateProcessWithToken if the permissions permit it)."

Please check if the "Secondary Logon" service is running on your computer.

Share this post


Link to post
Share on other sites

Really problem is the "Secondary Logon" services,

When turn on "Secondary Logon" service to normal.

In addition to gratitude, to you recommend:

http://www.shenyunperformingarts.org/?lang=en-us

http://www.shenyunperformingarts.org/reviews

If you where there, Be sure to see.

You will never regret it.

Share this post


Link to post
Share on other sites

Because of the restrictions enfored by that directive.

UAC Elevation GUI Triggered Works for NonAdmin  Can obtain Admin rights

requestedExecutionLevel=asAdmin     Yes                         Never               Always
requestedExecutionLevel=asInvoker   No                          Always              Never
Method above                        No - but can be triggered   Always              Always

Share this post


Link to post
Share on other sites

This will work like AsAdmin if your account has admin rights and AsInvoker if your account has no admin rights. So if your Admin it will always trigger UAC elevation, the same restrictions as described above are still in place, only that they are not linked to the program but to your account rights.

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

UAC Elevation GUI Triggered   Works for NonAdmin  Can obtain Admin rights

requestedExecutionLevel=asAdmin            Yes                           Never               Always
requestedExecutionLevel=asInvoker          No                            Always              Never
requestedExecutionLevel=highestAvailable   Yes - Admin, No - Limited     Always              Never
Method above                               No - but can be triggered     Always              Always

For example, "highestAvailable" uses a regedit32.exe. To obtain an Admin rights, you can always use "Run as administrator..." context menu.

Edited by Yashied

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

There are always good reasons to limit or expand what a script or program can do..

For example: An installer must be elevated, but should probably run the installed program at a lower privilege level. If not, the app won't be able to be interacted with from other lower-privilege level applications- not in full, anyway. Things like drag-and-drop will fail to work.

On the flip-side, a script or program might need to be able to run for both a regular user and an admin-level user, and only switch to an elevated mode when working with certain system elements (that a regular user shouldn't be allowed to work with). Then an elevation prompt can be provided, at which point the script/program can restart itself. For example, Task Manager will run unelevated and re-runs itself only when certain buttons are pressed ("Show processes from all users" for example). Note that, since taskmgr.exe is in the 'whitelist', you won't see a UAC prompt on the lower UAC settings in Windows 7. However, you can clearly see it is restarted.

*edit: clarification

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0