wanghong01 发表于 2011-5-19 09:57:32

Win7 UAC 提权 和 降权 的问题【已解决】

本帖最后由 wanghong01 于 2011-5-19 23:37 编辑

大家好!!{:face (396):}
我有一个问题,就是当我的脚本在win7提权运行后就无法降权了,比如我的脚本要重启资源管理器,可资源管理器也同时具有了管理员权限,这不是我要的。以前我也询问过,得到的回答都是采用与RANAS类似的方式。可是Win7UAC提权并没有使用另外的用户运行程序啊。那种方式是不行的。在Autoit官方论坛找到了一个Win7提权和降权的脚本,可是在我的Win7SP1运行降权出错,谁能帮帮我吗?谢谢。



#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/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;dword;dword;word;word;ptr;handle")
    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 Then Return SetError(3, 0, 0)
    $hProcess = $aRet

;~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 Then Return SetError(_RWRPCleanup($hProcess, 0, 0, 3), @extended, 0)
    $hToken = $aRet

;~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 Then Return SetError(_RWRPCleanup($hProcess, $hToken, 0, 3), @extended, 0)
    $hDupToken = $aRet

;~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 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 = [$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

daiyu116 发表于 2011-5-19 15:20:53

本帖最后由 daiyu116 于 2011-5-19 15:27 编辑

回复 1# wanghong01

       最近也在使用UAC,发现论坛里面对UAC关注不太多,可能是因为中国使用盗版系统太多了,大部分都在安装操作系统的时候把UAC关掉了,所以测试的机会很少。
       LZ所写的脚本不是太懂,请关注一下其中这一句:
       If Not $aRet Then Return SetError(3, 0, 0)
       另外,贴上我自己曾经用过的UAC降权脚本,也是需要用户互动才可以,其实如果用户不互动的话他也没办法继续运行后面的函数。
      
          #RequireAdmin ;必须添加本行,否则在UAC状态下不起作用。
$value1=RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System", "ConsentPromptBehaviorAdmin")
$value2=RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System", "EnableLUA")
$value3=RegRead("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System", "PromptOnSecureDesktop")
If $value2=0 Then ;说明没有开启UAC
        install()
ElseIf        $value2=1Then
        MsgBox(0,"系统启用UAC","您的操作系统启用了UAC,运行本程序将弹出确认对话框,请点击确定,否则无法正常运行!")
        $value_2=RegWrite("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System", "ConsentPromptBehaviorAdmin","REG_DWORD","0")
        $value_3=RegWrite("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System", "PromptOnSecureDesktop","REG_DWORD","0")
        $value_1=RegWrite("HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System", "EnableLUA","REG_DWORD","0")
                If $value_2=1 And $value_3=1 And $value_1=1 Then
                        install()
                Else
                        MsgBox(0,"修改UAC设置未成功","请确认在运行本程序时对系统弹出的对话框确认!请重新运行本程序,否则请联络系统管理员处理!"&@error)
                        Exit
                EndIf
#comments-start
;以下三项ElseIf综合起来为方式二,但不如方式一便捷直接
ElseIf $value1=2 And $value2=1 And $value3=1 Then ;对应UAC最高权限
        ;Run(@WindowsDir&"\System32\UserAccountControlSettings.exe")
                ;WinSetOnTop("","",1)
                ;WinWaitActive("")
                ;ControlFocus ("","","msctls_trackbar321")
                ;Send("{DOWN 4}")
                ;ControlClick("","","Button1")
                ;install()
               
ElseIf $value1=5 And $value2=1 And $value3=1 Then ;对应UAC中等权限
        Run(@WindowsDir&"\System32\UserAccountControlSettings.exe")
                WinWaitActive("")
                ControlFocus ("","","msctls_trackbar321")
                Send("{DOWN 3}")
                ControlClick("","","Button1")
                MsgBox(0,"修改UAC设置","chongqi")
                install()
ElseIf $value1=5 And $value2=1 And $value3=0 Then ;对应UAC最低权限
        Run(@WindowsDir&"\System32\UserAccountControlSettings.exe")
                WinWaitActive("")
                ControlFocus ("","","msctls_trackbar321")
                Send("{DOWN 2}")
                ControlClick("","","Button1")
                MsgBox(0,"修改UAC设置","chongqi")
                install()
#comments-end
EndIf

FUNC INSTALL()
       .......................这里是我自己的函数,就不贴了
ENDFUNC
      

wanghong01 发表于 2011-5-19 16:26:21

谢谢楼上的!
可是并没有解决我的问题。
我不是要关闭UAC,只是要降权运行另外的程序。
就像Win7的任务管理器一样,在管理员模式也可以降权运行其他程序,但不是以另外的身份运行程序。

wanghong01 发表于 2011-5-19 23:36:18

重装系统,问题解决了。

雨林GG 发表于 2012-5-19 07:26:28

收藏备用,学习Win7

system 发表于 2016-7-22 22:31:44

回复 2# daiyu116


    感谢
页: [1]
查看完整版本: Win7 UAC 提权 和 降权 的问题【已解决】