柠檬时代 发表于 2024-10-13 18:45:24

【提问求助】以服务运行指定程序,权限不继承




在论坛上找到的解决方案是将自己的程序注册为一项服务,赋予它system权限,目前的功能是通过服务启动其他程序。然而,我遇到的问题是服务在启动程序时,权限会一直沿用system级别。是否有方法能让服务在启动第一个程序(比如A)时使用system权限,而当A程序进一步启动其他程序(比如B)时,以当前运行用户的权限执行呢?
目标是确保服务启动链的第一步(如A程序)利用system权限,后续步骤则切换到当前用户权限,以提高安全性和灵活性。

Const $hAdvApi32Dll = DllOpen("AdvApi32.dll")
Const $hKernel32Dll = DllOpen("Kernel32.dll")
Const $tagSERVICE_TABLE_ENTRY = "ptr ServiceName;ptr ServiceMain"
Const $tagSERVICE_STATUS = "dword ServiceType;dword CurrentState;dword ControlsAccepted;dword Win32ExitCode;dword ServiceSpecificExitCode;dword CheckPoint;dword WaitHint"
Global $hServiceStatus, $tServiceStatus, $pServiceStatus
Global $hServiceMain, $pServiceMain, $tServiceTable, $pServiceTable
Global $hServiceHandlerEx, $pServiceHandlerEx
Global $Type, $Start, $ErrorControl, $Description

InstallService("0x00000110", "0x00000002", "0x00000001", "服务验证示例")

;说明:将自身注册为系统服务的函数
;语法:InstallService($Type,$Start,$ErrorControl,$Description)
;$Type,服务类型,"0x00000110"为与桌面交互
;$Start,启动方式,"0x00000002"为自动启动
;$ErrorControl,错误控制,"0x00000001"为无操作
;$Description,描述
Func InstallService($Type, $Start, $ErrorControl, $Description)
        $hServiceMain = DllCallbackRegister("_ServiceMain", "none", "dword;ptr")
        $pServiceMain = DllCallbackGetPtr($hServiceMain)
        $hServiceHandlerEx = DllCallbackRegister("_ServiceHandlerEx", "dword", "dword;dword;ptr;ptr")
        $pServiceHandlerEx = DllCallbackGetPtr($hServiceHandlerEx)
        $pServiceTable = _ServiceHeapAlloc(32)
        $tServiceTable = DllStructCreate($tagSERVICE_TABLE_ENTRY, $pServiceTable)
        DllStructSetData($tServiceTable, "ServiceName", $pServiceTable + 16)
        DllStructSetData($tServiceTable, "ServiceMain", $pServiceMain)
        $tServiceName = DllStructCreate("char ServiceName", $pServiceTable + 16)
        DllStructSetData($tServiceName, "ServiceName", @ScriptName)
        $tServiceStatus = DllStructCreate($tagSERVICE_STATUS)
        $pServiceStatus = DllStructGetPtr($tServiceStatus)
        DllStructSetData($tServiceStatus, "ServiceType", 16)
        DllStructSetData($tServiceStatus, "ControlsAccepted", 3)
        _StartServiceCtrlDispatcher($pServiceTable)
        ;注册服务
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit')
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit', 'Type', 'REG_DWORD', $Type)
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit', 'Start', 'REG_DWORD', $Start)
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit', 'ErrorControl', 'REG_DWORD', $ErrorControl)
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit', 'ImagePath', 'REG_EXPAND_SZ', @ScriptFullPath)
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit', 'DisplayName', 'REG_SZ', @ScriptName)
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit', 'ObjectName', 'REG_SZ', 'LocalSystem')
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit', 'Description', 'REG_SZ', $Description)
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit\Enum')
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit\Enum', '0', 'REG_SZ', 'Root\LEGACY_PCLIMIT\0000')
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit\Enum', 'Count', 'REG_DWORD', '0x00000001')
        RegWrite('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PcLimit\Enum', 'NextInstance', 'REG_DWORD', '0x00000001')
EndFunc   ;==>InstallService

Func _StartServiceCtrlDispatcher($pServiceTable)
        Local $iResult
        $iResult = DllCall($hAdvApi32Dll, "int", "StartServiceCtrlDispatcher", "ptr", $pServiceTable)
        Return SetError(_ServiceLastError(), 0, $iResult)
EndFunc   ;==>_StartServiceCtrlDispatcher

Func _SetServiceStatus($hServiceStatus, $pServiceStatus)
        Local $iResult
        $iResult = DllCall($hAdvApi32Dll, "int", "SetServiceStatus", "hWnd", $hServiceStatus, _
                        "ptr", $pServiceStatus)
        Return SetError(_ServiceLastError(), 0, $iResult)
EndFunc   ;==>_SetServiceStatus

Func _RegisterServiceCtrlHandlerEx($sServiceName, $pHandlerEx, $pContext = 0)
        Local $iResult
        $iResult = DllCall($hAdvApi32Dll, "hWnd", "RegisterServiceCtrlHandlerEx", _
                        "str", $sServiceName, "ptr", $pHandlerEx, "ptr", $pContext)
        Return SetError(_ServiceLastError(), 0, $iResult)
EndFunc   ;==>_RegisterServiceCtrlHandlerEx

Func _ServiceHandlerEx($iRequest, $iEventType, $pEventData, $pContext)
        Switch $iRequest
                Case 1
                        DllStructSetData($tServiceStatus, "CurrentState", 1)
                        _SetServiceStatus($hServiceStatus, $pServiceStatus)
                        Return 0
                Case 2
                        DllStructSetData($tServiceStatus, "CurrentState", 7)
                        _SetServiceStatus($hServiceStatus, $pServiceStatus)
                        Return 0
                Case 3
                        DllStructSetData($tServiceStatus, "CurrentState", 5)
                        _SetServiceStatus($hServiceStatus, $pServiceStatus)
                        Sleep(5000)
                        DllStructSetData($tServiceStatus, "CurrentState", 4)
                        _SetServiceStatus($hServiceStatus, $pServiceStatus)
                        Return 0
                Case 4
                        _SetServiceStatus($hServiceStatus, $pServiceStatus)
                        Return 0
        EndSwitch
EndFunc   ;==>_ServiceHandlerEx

Func _ServiceHeapAlloc($iSize, $iFlags = 8)
        If $iSize < 1 Then Return SetError(87, 0, 0)
        Local $hHeap, $iResult
        $hHeap = DllCall($hKernel32Dll, "hWnd", "GetProcessHeap")
        $iResult = DllCall($hKernel32Dll, "ptr", "HeapAlloc", "hWnd", $hHeap, _
                        "dword", $iFlags, "dword", $iSize)
        Return $iResult
EndFunc   ;==>_ServiceHeapAlloc

Func _ServiceHeapFree(ByRef $pBuffer)
        If $pBuffer = 0 Then Return SetError(87, 0, 0)
        Local $iResult, $hHeap
        $hHeap = DllCall($hKernel32Dll, "hWnd", "GetProcessHeap")
        $iResult = DllCall($hKernel32Dll, "int", "HeapFree", "hWnd", $hHeap, _
                        "dword", 0, "ptr", $pBuffer)
        If $iResult Then $pBuffer = 0
        Return $iResult
EndFunc   ;==>_ServiceHeapFree

Func _ServiceHeapSize(ByRef $pBuffer)
        If $pBuffer = 0 Then Return SetError(87, 0, 0)
        Local $iResult, $hHeap
        $hHeap = DllCall($hKernel32Dll, "hWnd", "GetProcessHeap")
        $iResult = DllCall($hKernel32Dll, "int", "HeapSize", "hWnd", $hHeap, _
                        "dword", 0, "ptr", $pBuffer)
        Return $iResult
EndFunc   ;==>_ServiceHeapSize

Func _ServiceLastError()
        Local $iResult
        $iResult = DllCall($hKernel32Dll, "dword", "GetLastError")
        Return $iResult
EndFunc   ;==>_ServiceLastError

Func _ServiceMain($iNumberofArgs, $pArgs)
        $hServiceStatus = _RegisterServiceCtrlHandlerEx(@ScriptName, $pServiceHandlerEx)
        DllStructSetData($tServiceStatus, "CurrentState", 4)
        _SetServiceStatus($hServiceStatus, $pServiceStatus)
EndFunc   ;==>_ServiceMain


tubaba 发表于 2024-10-15 09:12:25

#include-once
#cs ----------------------------------------------------------------------------

        必须运行在服务(system)权限下,用于系统服务程序启动第三方程序与用户桌面进行交互
        Opt('MustDeclareVars', 1)
        RunOnDesktop(@ComSpec, False)
#ce ----------------------------------------------------------------------------
#include <winapi.au3>
#include <array.au3>
#include <security.au3>
#include <StructureConstants.au3>
#include <WinAPISys.au3>
#CS
        $NULL = 0
        $WTS_CURRENT_SERVER_HANDLE = $NULL
        $WTSActive = 0
        $WTSShadow = 1
        $WTSConnectQuery = 2
        $CREATE_UNICODE_ENVIRONMENT = 0x00000400
        $DETACHED_PROCESS = 0x00000008
        $MAX_PATH = 260
        $PROCESS_ALL_ACCESS = 0x001F0FFF
        ;~ $TOKEN_ALL_ACCESS = 0xf01ff
        $ERROR_SUCCESS = 0
        Global Const $tagWTS_SESSION_INFO = 'dword SessionId;ptr WinStationName;uint State'
        $NORMAL_PRIORITY_CLASS = 0x20
#CE

Func RunOnDesktop($app_path, $UseSystemRights = False)
;~         Local $bReturn = False
        Local $hToken = 0
        Local $env = 0
        Local $iConsoleID = 0
        Local $iProcessPID = 0
        Local $hCur = 0
        Local $hCurToken = 0
        Local $CREATE_NEW_CONSOLE = 0x00000010
        Local $CREATE_UNICODE_ENVIRONMENT = 0x00000400
        Local $NORMAL_PRIORITY_CLASS = 0x20
        ;Get active Desktop ID
        $iConsoleID = WTSGetActiveConsoleSessionId()
        $hToken = WTSQueryUserToken($iConsoleID)
        CreateEnvironmentBlock($env, $hToken, False) ;设定所有帐户运行在当前桌面用户环境变量
        If $UseSystemRights Then
;~                 Local $iWinlogonPID = 0
;~                 Local $hWinlogon = 0
;~                 Local $PROCESS_ALL_ACCESS = 0x001F0FFF
;~                 $iWinlogonPID = _GetWinLogonPID($iConsoleID)
;~                 $hWinlogon = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, False, $iWinlogonPID) ;_ProcessGetHandle($iWinlogonPID)
;~                 Local $hWinLogonToken = _Security__OpenProcessToken($hWinlogon, $TOKEN_ALL_ACCESS) ;_OpenProcessToken($hWinlogon)
;~                 $hToken = _Security__DuplicateTokenEx($hWinLogonToken, $TOKEN_ALL_ACCESS, $SECURITYIMPERSONATION, $TOKENPRIMARY) ;_DuplicateToken($hToken)
;~                 _WinAPI_CloseHandle($hWinLogonToken) ;
;~                 _WinAPI_CloseHandle($hWinlogon) ;

                $hCur = _WinAPI_GetCurrentProcess()
                $hCurToken = _Security__OpenProcessToken($hCur, $TOKEN_ALL_ACCESS)
                $hToken = _Security__DuplicateTokenEx($hCurToken, $TOKEN_ALL_ACCESS, $SECURITYIMPERSONATION, $TOKENPRIMARY)
                Local $tTOKENSESSIONID = DllStructCreate("DWORD")
                DllStructSetData($tTOKENSESSIONID, 1, $iConsoleID)
                Local $ret = _Security__SetTokenInformation($hToken, $TOKENSESSIONID, $tTOKENSESSIONID, DllStructGetSize($tTOKENSESSIONID))
                If $bDebug Then _DebugPrint('_Security__SetTokenInformation:' & $ret) ;debug
                _WinAPI_CloseHandle($hCurToken) ;
        EndIf
        Local $si = DllStructCreate($tagSTARTUPINFO)
        Local $pi = DllStructCreate($tagPROCESS_INFORMATION)
        Local $lpProcessAttributes = DllStructCreate($tagSECURITY_ATTRIBUTES)
        Local $lpThreadAttributes = DllStructCreate($tagSECURITY_ATTRIBUTES)
        DllStructSetData($lpThreadAttributes, "Descriptor", "")
        Local $ta_size = DllStructGetSize($lpThreadAttributes)
        DllStructSetData($lpThreadAttributes, "Length", $ta_size)
        DllStructSetData($lpProcessAttributes, "Descriptor", "")
        Local $pa_size = DllStructGetSize($lpProcessAttributes)
        DllStructSetData($lpProcessAttributes, "Length", $pa_size)
        DllStructSetData($si, "Desktop", "Winsta0//Default")
        DllStructSetData($si, "Flags", $STARTF_USESHOWWINDOW)
        DllStructSetData($si, "ShowWindow", @SW_SHOW)
       
        Local $pi_size = DllStructGetSize($pi)
        Local $si_size = DllStructGetSize($si)
        DllStructSetData($pi, "Size", $pi_size)
        DllStructSetData($si, "Size", $si_size)
;~         Local $ret = CreateProcessAsUser($hToken, 0, $app_path, DllStructGetPtr($lpProcessAttributes), DllStructGetPtr($lpThreadAttributes), 0, $NORMAL_PRIORITY_CLASS + $CREATE_NEW_CONSOLE, $env, "", DllStructGetPtr($si), DllStructGetPtr($pi))
        Local $ret = CreateProcessAsUser($hToken, 0, $app_path, DllStructGetPtr($lpProcessAttributes), DllStructGetPtr($lpThreadAttributes), 0, $NORMAL_PRIORITY_CLASS + $CREATE_NEW_CONSOLE + $CREATE_UNICODE_ENVIRONMENT, $env, 0, DllStructGetPtr($si), DllStructGetPtr($pi))
        If @error And $bDebug Then _DebugPrint('CreateProcessAsUser error:' & $ret) ;debug
        $iProcessPID = DllStructGetData($pi, "ProcessID")
        _WinAPI_CloseHandle(DllStructGetData($pi, "hProcess")) ;
        _WinAPI_CloseHandle(DllStructGetData($pi, "hThread")) ;
        _WinAPI_CloseHandle($hToken) ;
        Return $iProcessPID
EndFunc   ;==>RunOnDesktop

Func SetTBCPrivileges()
        $dwPID = @AutoItPID
        $hToken = 0
        $hProcess = 0
        $tpDebug = DllStructCreate($tagTOKEN_PRIVILEGES)
        $hProcess = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, False, $dwPID)
        If Not $hProcess Then Return False
        ;If not _WinAPI_OpenProcessToken($hProcess,$TOKEN_ALL_ACCESS,$hToken) Then return False
        $hToken = _Security__OpenProcessToken($hProcess, $TOKEN_ALL_ACCESS)
        If @error Then Return False
        $LUID = _Security__LookupPrivilegeValue("", $SE_DEBUG_NAME)
        If $LUID == 0 Then Return False
        DllStructSetData($tpDebug, "Count", 1)
        DllStructSetData($tpDebug, "LUID", $LUID, 1)
        DllStructSetData($tpDebug, "Attributes", $SE_PRIVILEGE_ENABLED, 1)
        If _Security__AdjustTokenPrivileges($hToken, False, DllStructGetPtr($tpDebug), DllStructGetSize($tpDebug), 0, 0) = False Then Return False
        If _WinAPI_GetLastError() <> 0 Then Return False
        _WinAPI_CloseHandle($hToken) ;
        _WinAPI_CloseHandle($hProcess) ;
        Return True
EndFunc   ;==>SetTBCPrivileges

Func CreateEnvironmentBlock(ByRef $lpEnvironment, $hToken, $bInherit)
        Local $struct = DllStructCreate("ptr")
        Local $ret = DllCall('Userenv.dll', 'bool', 'CreateEnvironmentBlock', _
                        'ptr', DllStructGetPtr($struct), _
                        'HANDLE', $hToken, _
                        'bool', $bInherit)
        $lpEnvironment = DllStructGetData($struct, 1)
        Return $ret
EndFunc   ;==>CreateEnvironmentBlock

Func WTSGetActiveConsoleSessionId()
        Local $ret = DllCall('Kernel32.dll', 'dword', 'WTSGetActiveConsoleSessionId')
        Return $ret
EndFunc   ;==>WTSGetActiveConsoleSessionId

Func WTSQueryUserToken($SessionId)
        Local $struct = DllStructCreate("HANDLE")
        Local $ret = DllCall('wtsapi32.dll', 'bool', 'WTSQueryUserToken', _
                        'ULONG', $SessionId, _
                        'ptr*', DllStructGetPtr($struct))
        Return $ret
EndFunc   ;==>WTSQueryUserToken

Func ImpersonateLoggedOnUser(ByRef $hToken)
    Local $aResult = DllCall("advapi32.dll", "int", "ImpersonateLoggedOnUser", "hwnd", $hToken)
    If @error Then Return SetError(@error, @extended, 0)
    Return SetError(0, 0, $aResult <> 0)
EndFunc

Func _TSSendConsoleMessage($ButtonSet, $TitleText, $MessageText, $Timeout = 10, $Wait = False)
        $TitleText = StringToBinary($TitleText, 1)
        Local $pTitle = DllStructCreate('byte Title[' & BinaryLen($TitleText) + 1 & ']')
        DllStructSetData($pTitle, 'Title', $TitleText)
        $MessageText = StringToBinary($MessageText, 1)
        Local $pMessage = DllStructCreate('byte Message[' & BinaryLen($MessageText) + 1 & ']')
        DllStructSetData($pMessage, 'Message', $MessageText)
        Local $pResponse = DllStructCreate("DWORD Response")
        Local $SessionId = WTSGetActiveConsoleSessionId()
        DllStructSetData($pTitle, "Title", $TitleText)
        DllStructSetData($pMessage, "Message", $MessageText)
        Local $Res = DllCall("Wtsapi32.dll", "BOOL", "WTSSendMessageA", "HANDLE", "WTS_CURRENT_SERVER_HANDLE", "DWORD", $SessionId, "ptr", DllStructGetPtr($pTitle), "DWORD", DllStructGetSize($pTitle), "ptr", DllStructGetPtr($pMessage), "DWORD", DllStructGetSize($pMessage), "DWORD", $ButtonSet, "DWORD", $Timeout, "DWORD", DllStructGetPtr($pResponse), "BOOL", $Wait)
        Return $Res
EndFunc   ;==>_TSSendConsoleMessage

Func CreateProcessAsUser($hToken, $lpApplicationName, $lpCommandline, $lpProcessAttributes, $lpThreadAttributes, $bInheritHandles, $dwCreationFlags, $lpEnvironment, $lpCurrentDirectory, $lpStartupInfo, $lpProcessInformation)
        Local $ret = DllCall("advapi32.dll", "bool", "CreateProcessAsUserW", _ ; W is better
                        "handle", $hToken, _
                        "ptr", $lpApplicationName, _ ;$lpApplicationName, _
                        "wstr", $lpCommandline, _ ; wstr for CreateProcessAsUserW
                        "ptr", $lpProcessAttributes, _
                        "ptr", $lpThreadAttributes, _
                        "bool", $bInheritHandles, _ ;$bInheritHandles, _
                        "dword", $dwCreationFlags, _
                        "ptr", $lpEnvironment, _
                        "ptr", $lpCurrentDirectory, _
                        "ptr", $lpStartupInfo, _
                        "ptr", $lpProcessInformation)
        ;If $ret = 0 Then _MsgBox(16, "proc e "&@error&" "&$hToken, _WinAPI_GetLastErrorMessage())
        If $ret = 0 Then Return SetError(_WinAPI_GetLastError(), 0, _WinAPI_GetLastErrorMessage())
        Return $ret
EndFunc   ;==>CreateProcessAsUser

Func _GetWinLogonPID($iActiveSession)
        Local $aWinlogon, $i
        $aWinlogon = ProcessList("winlogon.exe")

        For $i = 1 To $aWinlogon
                If $iActiveSession = _ProcessGetSessionID($aWinlogon[$i]) Then
                        Return $aWinlogon[$i]
                EndIf
        Next
        Return 0
EndFunc   ;==>_GetWinLogonPID

Func _ProcessGetSessionID($vProcessID)
        Local $aRet = DllCall("Kernel32.dll", "bool", "ProcessIdToSessionId", "dword", $vProcessID, "dword*", 0)
        If @error Then Return SetError(2, @error, -1)
        If Not $aRet Then Return SetError(3, 0, -1)
        Return $aRet
EndFunc   ;==>_ProcessGetSessionID

Func _GetUserName()
        Local $aDLL = DllCall("Advapi32.dll", "int", "GetUserNameW", "wstr", "", "dword*", 255)
        If @error Then Return SetError(@error, 0, '')
        Return $aDLL
EndFunc   ;==>_GetUserName

Func _ProcessListOWNER_WTS($PID = 0)
;~ $temp="Process"
;~ $temp="ProcessId"
;~ $temp="SessionId"
;~ $temp="ProcessOWNER"
        Local $tag_WTS_PROCESS_INFO = _
                        "DWORD SessionId;" & _
                        "DWORD ProcessId;" & _
                        "PTR pProcessName;" & _
                        "PTR pUserSid"
        Local $i, $ret, $ret1, $mem, $string
        $ret = DllCall("WTSApi32.dll", "int", "WTSEnumerateProcesses", "int", 0, "int", 0, "int", 1, "ptr*", 0, "int*", 0)
        Local $array[$ret]
        $mem = DllStructCreate($tag_WTS_PROCESS_INFO, $ret)
        For $i = 0 To $ret - 1
                $mem = DllStructCreate($tag_WTS_PROCESS_INFO, $ret + ($i * DllStructGetSize($mem)))
                ;if DllStructGetData($mem, "pProcessName") Then
                $string = DllStructCreate("char", DllStructGetData($mem, "pProcessName"))
                $array[$i] = DllStructGetData($string, 1)
                ;EndIf
                $array[$i] = DllStructGetData($mem, "ProcessId")
                $array[$i] = DllStructGetData($mem, "SessionId")
                ;if DllStructGetData($mem, "pUserSid") Then
                $ret1 = _Security__LookupAccountSid(DllStructGetData($mem, "pUserSid"))
                If IsArray($ret1) Then $array[$i] = $ret1
                ;EndIf
        Next
        DllCall("WTSApi32.dll", "int", "WTSFreeMemory", "int", $ret)
        If $PID Then
                For $i = 0 To UBound($array, 1) - 1
                        If $array[$i] = $PID Then
                                Return $array[$i] & '|' & $array[$i]
                        EndIf
                Next
        EndIf
        Return $array
EndFunc   ;==>_ProcessListOWNER_WTS


tubaba 发表于 2024-10-15 11:24:25

由于是脚本中剥离


1.把debug 的相关语句注释掉.
2.几个常量里面没有包含必需的常量,添加几个包含文件即可.
3.可能需要你自己改造一下,几个API不懂的话,可以百度一下它的用途.
4.如果没有system权限,搜索我的另一作品,ExecRunAs

#include <WindowsConstants.au3>
#include <ProcessConstants.au3>
#include-once
#cs ----------------------------------------------------------------------------

        必须运行在服务(system)权限下,用于系统服务程序启动第三方程序与用户桌面进行交互
        Opt('MustDeclareVars', 1)
        RunOnDesktop(@ComSpec, False)
#ce ----------------------------------------------------------------------------
#include <winapi.au3>
#include <array.au3>
#include <security.au3>
#include <StructureConstants.au3>
#include <WinAPISys.au3>
#CS
        $NULL = 0
        $WTS_CURRENT_SERVER_HANDLE = $NULL
        $WTSActive = 0
        $WTSShadow = 1
        $WTSConnectQuery = 2
        $CREATE_UNICODE_ENVIRONMENT = 0x00000400
        $DETACHED_PROCESS = 0x00000008
        $MAX_PATH = 260
        $PROCESS_ALL_ACCESS = 0x001F0FFF
        ;~ $TOKEN_ALL_ACCESS = 0xf01ff
        $ERROR_SUCCESS = 0
        Global Const $tagWTS_SESSION_INFO = 'dword SessionId;ptr WinStationName;uint State'
        $NORMAL_PRIORITY_CLASS = 0x20
#CE

RunOnDesktop(StringFormat('"%s" /k whoami /all', @ComSpec), False)        ;这是测试命令,编译后用system权限运行

Func RunOnDesktop($app_path, $UseSystemRights = False)
;~         Local $bReturn = False
        Local $hToken = 0
        Local $env = 0
        Local $iConsoleID = 0
        Local $iProcessPID = 0
        Local $hCur = 0
        Local $hCurToken = 0
        Local $CREATE_NEW_CONSOLE = 0x00000010
        Local $CREATE_UNICODE_ENVIRONMENT = 0x00000400
        Local $NORMAL_PRIORITY_CLASS = 0x20
        ;Get active Desktop ID
        $iConsoleID = WTSGetActiveConsoleSessionId()
        $hToken = WTSQueryUserToken($iConsoleID)
        CreateEnvironmentBlock($env, $hToken, False) ;设定所有帐户运行在当前桌面用户环境变量
        If $UseSystemRights Then
;~                 Local $iWinlogonPID = 0
;~                 Local $hWinlogon = 0
;~                 Local $PROCESS_ALL_ACCESS = 0x001F0FFF
;~                 $iWinlogonPID = _GetWinLogonPID($iConsoleID)
;~                 $hWinlogon = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, False, $iWinlogonPID) ;_ProcessGetHandle($iWinlogonPID)
;~                 Local $hWinLogonToken = _Security__OpenProcessToken($hWinlogon, $TOKEN_ALL_ACCESS) ;_OpenProcessToken($hWinlogon)
;~                 $hToken = _Security__DuplicateTokenEx($hWinLogonToken, $TOKEN_ALL_ACCESS, $SECURITYIMPERSONATION, $TOKENPRIMARY) ;_DuplicateToken($hToken)
;~                 _WinAPI_CloseHandle($hWinLogonToken) ;
;~                 _WinAPI_CloseHandle($hWinlogon) ;

                $hCur = _WinAPI_GetCurrentProcess()
                $hCurToken = _Security__OpenProcessToken($hCur, $TOKEN_ALL_ACCESS)
                $hToken = _Security__DuplicateTokenEx($hCurToken, $TOKEN_ALL_ACCESS, $SECURITYIMPERSONATION, $TOKENPRIMARY)
                Local $tTOKENSESSIONID = DllStructCreate("DWORD")
                DllStructSetData($tTOKENSESSIONID, 1, $iConsoleID)
                Local $ret = _Security__SetTokenInformation($hToken, $TOKENSESSIONID, $tTOKENSESSIONID, DllStructGetSize($tTOKENSESSIONID))
;~                 If $bDebug Then _DebugPrint('_Security__SetTokenInformation:' & $ret) ;debug
                _WinAPI_CloseHandle($hCurToken) ;
        EndIf
        Local $si = DllStructCreate($tagSTARTUPINFO)
        Local $pi = DllStructCreate($tagPROCESS_INFORMATION)
        Local $lpProcessAttributes = DllStructCreate($tagSECURITY_ATTRIBUTES)
        Local $lpThreadAttributes = DllStructCreate($tagSECURITY_ATTRIBUTES)
        DllStructSetData($lpThreadAttributes, "Descriptor", "")
        Local $ta_size = DllStructGetSize($lpThreadAttributes)
        DllStructSetData($lpThreadAttributes, "Length", $ta_size)
        DllStructSetData($lpProcessAttributes, "Descriptor", "")
        Local $pa_size = DllStructGetSize($lpProcessAttributes)
        DllStructSetData($lpProcessAttributes, "Length", $pa_size)
        DllStructSetData($si, "Desktop", "Winsta0//Default")
        DllStructSetData($si, "Flags", $STARTF_USESHOWWINDOW)
        DllStructSetData($si, "ShowWindow", @SW_SHOW)

        Local $pi_size = DllStructGetSize($pi)
        Local $si_size = DllStructGetSize($si)
        DllStructSetData($pi, "Size", $pi_size)
        DllStructSetData($si, "Size", $si_size)
;~         Local $ret = CreateProcessAsUser($hToken, 0, $app_path, DllStructGetPtr($lpProcessAttributes), DllStructGetPtr($lpThreadAttributes), 0, $NORMAL_PRIORITY_CLASS + $CREATE_NEW_CONSOLE, $env, "", DllStructGetPtr($si), DllStructGetPtr($pi))
        Local $ret = CreateProcessAsUser($hToken, 0, $app_path, DllStructGetPtr($lpProcessAttributes), DllStructGetPtr($lpThreadAttributes), 0, $NORMAL_PRIORITY_CLASS + $CREATE_NEW_CONSOLE + $CREATE_UNICODE_ENVIRONMENT, $env, 0, DllStructGetPtr($si), DllStructGetPtr($pi))
        $iProcessPID = DllStructGetData($pi, "ProcessID")
        _WinAPI_CloseHandle(DllStructGetData($pi, "hProcess")) ;
        _WinAPI_CloseHandle(DllStructGetData($pi, "hThread")) ;
        _WinAPI_CloseHandle($hToken) ;
        Return $iProcessPID
EndFunc   ;==>RunOnDesktop

Func SetTBCPrivileges()
        $dwPID = @AutoItPID
        $hToken = 0
        $hProcess = 0
        $tpDebug = DllStructCreate($tagTOKEN_PRIVILEGES)
        $hProcess = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, False, $dwPID)
        If Not $hProcess Then Return False
        ;If not _WinAPI_OpenProcessToken($hProcess,$TOKEN_ALL_ACCESS,$hToken) Then return False
        $hToken = _Security__OpenProcessToken($hProcess, $TOKEN_ALL_ACCESS)
        If @error Then Return False
        $LUID = _Security__LookupPrivilegeValue("", $SE_DEBUG_NAME)
        If $LUID == 0 Then Return False
        DllStructSetData($tpDebug, "Count", 1)
        DllStructSetData($tpDebug, "LUID", $LUID, 1)
        DllStructSetData($tpDebug, "Attributes", $SE_PRIVILEGE_ENABLED, 1)
        If _Security__AdjustTokenPrivileges($hToken, False, DllStructGetPtr($tpDebug), DllStructGetSize($tpDebug), 0, 0) = False Then Return False
        If _WinAPI_GetLastError() <> 0 Then Return False
        _WinAPI_CloseHandle($hToken) ;
        _WinAPI_CloseHandle($hProcess) ;
        Return True
EndFunc   ;==>SetTBCPrivileges

Func CreateEnvironmentBlock(ByRef $lpEnvironment, $hToken, $bInherit)
        Local $struct = DllStructCreate("ptr")
        Local $ret = DllCall('Userenv.dll', 'bool', 'CreateEnvironmentBlock', _
                        'ptr', DllStructGetPtr($struct), _
                        'HANDLE', $hToken, _
                        'bool', $bInherit)
        $lpEnvironment = DllStructGetData($struct, 1)
        Return $ret
EndFunc   ;==>CreateEnvironmentBlock

Func WTSGetActiveConsoleSessionId()
        Local $ret = DllCall('Kernel32.dll', 'dword', 'WTSGetActiveConsoleSessionId')
        Return $ret
EndFunc   ;==>WTSGetActiveConsoleSessionId

Func WTSQueryUserToken($SessionId)
        Local $struct = DllStructCreate("HANDLE")
        Local $ret = DllCall('wtsapi32.dll', 'bool', 'WTSQueryUserToken', _
                        'ULONG', $SessionId, _
                        'ptr*', DllStructGetPtr($struct))
        Return $ret
EndFunc   ;==>WTSQueryUserToken

Func ImpersonateLoggedOnUser(ByRef $hToken)
    Local $aResult = DllCall("advapi32.dll", "int", "ImpersonateLoggedOnUser", "hwnd", $hToken)
    If @error Then Return SetError(@error, @extended, 0)
    Return SetError(0, 0, $aResult <> 0)
EndFunc

Func _TSSendConsoleMessage($ButtonSet, $TitleText, $MessageText, $Timeout = 10, $Wait = False)
        $TitleText = StringToBinary($TitleText, 1)
        Local $pTitle = DllStructCreate('byte Title[' & BinaryLen($TitleText) + 1 & ']')
        DllStructSetData($pTitle, 'Title', $TitleText)
        $MessageText = StringToBinary($MessageText, 1)
        Local $pMessage = DllStructCreate('byte Message[' & BinaryLen($MessageText) + 1 & ']')
        DllStructSetData($pMessage, 'Message', $MessageText)
        Local $pResponse = DllStructCreate("DWORD Response")
        Local $SessionId = WTSGetActiveConsoleSessionId()
        DllStructSetData($pTitle, "Title", $TitleText)
        DllStructSetData($pMessage, "Message", $MessageText)
        Local $Res = DllCall("Wtsapi32.dll", "BOOL", "WTSSendMessageA", "HANDLE", "WTS_CURRENT_SERVER_HANDLE", "DWORD", $SessionId, "ptr", DllStructGetPtr($pTitle), "DWORD", DllStructGetSize($pTitle), "ptr", DllStructGetPtr($pMessage), "DWORD", DllStructGetSize($pMessage), "DWORD", $ButtonSet, "DWORD", $Timeout, "DWORD", DllStructGetPtr($pResponse), "BOOL", $Wait)
        Return $Res
EndFunc   ;==>_TSSendConsoleMessage

Func CreateProcessAsUser($hToken, $lpApplicationName, $lpCommandline, $lpProcessAttributes, $lpThreadAttributes, $bInheritHandles, $dwCreationFlags, $lpEnvironment, $lpCurrentDirectory, $lpStartupInfo, $lpProcessInformation)
        Local $ret = DllCall("advapi32.dll", "bool", "CreateProcessAsUserW", _ ; W is better
                        "handle", $hToken, _
                        "ptr", $lpApplicationName, _ ;$lpApplicationName, _
                        "wstr", $lpCommandline, _ ; wstr for CreateProcessAsUserW
                        "ptr", $lpProcessAttributes, _
                        "ptr", $lpThreadAttributes, _
                        "bool", $bInheritHandles, _ ;$bInheritHandles, _
                        "dword", $dwCreationFlags, _
                        "ptr", $lpEnvironment, _
                        "ptr", $lpCurrentDirectory, _
                        "ptr", $lpStartupInfo, _
                        "ptr", $lpProcessInformation)
        ;If $ret = 0 Then _MsgBox(16, "proc e "&@error&" "&$hToken, _WinAPI_GetLastErrorMessage())
        If $ret = 0 Then Return SetError(_WinAPI_GetLastError(), 0, _WinAPI_GetLastErrorMessage())
        Return $ret
EndFunc   ;==>CreateProcessAsUser

Func _GetWinLogonPID($iActiveSession)
        Local $aWinlogon, $i
        $aWinlogon = ProcessList("winlogon.exe")

        For $i = 1 To $aWinlogon
                If $iActiveSession = _ProcessGetSessionID($aWinlogon[$i]) Then
                        Return $aWinlogon[$i]
                EndIf
        Next
        Return 0
EndFunc   ;==>_GetWinLogonPID

Func _ProcessGetSessionID($vProcessID)
        Local $aRet = DllCall("Kernel32.dll", "bool", "ProcessIdToSessionId", "dword", $vProcessID, "dword*", 0)
        If @error Then Return SetError(2, @error, -1)
        If Not $aRet Then Return SetError(3, 0, -1)
        Return $aRet
EndFunc   ;==>_ProcessGetSessionID

Func _GetUserName()
        Local $aDLL = DllCall("Advapi32.dll", "int", "GetUserNameW", "wstr", "", "dword*", 255)
        If @error Then Return SetError(@error, 0, '')
        Return $aDLL
EndFunc   ;==>_GetUserName

Func _ProcessListOWNER_WTS($PID = 0)
;~ $temp="Process"
;~ $temp="ProcessId"
;~ $temp="SessionId"
;~ $temp="ProcessOWNER"
        Local $tag_WTS_PROCESS_INFO = _
                        "DWORD SessionId;" & _
                        "DWORD ProcessId;" & _
                        "PTR pProcessName;" & _
                        "PTR pUserSid"
        Local $i, $ret, $ret1, $mem, $string
        $ret = DllCall("WTSApi32.dll", "int", "WTSEnumerateProcesses", "int", 0, "int", 0, "int", 1, "ptr*", 0, "int*", 0)
        Local $array[$ret]
        $mem = DllStructCreate($tag_WTS_PROCESS_INFO, $ret)
        For $i = 0 To $ret - 1
                $mem = DllStructCreate($tag_WTS_PROCESS_INFO, $ret + ($i * DllStructGetSize($mem)))
                ;if DllStructGetData($mem, "pProcessName") Then
                $string = DllStructCreate("char", DllStructGetData($mem, "pProcessName"))
                $array[$i] = DllStructGetData($string, 1)
                ;EndIf
                $array[$i] = DllStructGetData($mem, "ProcessId")
                $array[$i] = DllStructGetData($mem, "SessionId")
                ;if DllStructGetData($mem, "pUserSid") Then
                $ret1 = _Security__LookupAccountSid(DllStructGetData($mem, "pUserSid"))
                If IsArray($ret1) Then $array[$i] = $ret1
                ;EndIf
        Next
        DllCall("WTSApi32.dll", "int", "WTSFreeMemory", "int", $ret)
        If $PID Then
                For $i = 0 To UBound($array, 1) - 1
                        If $array[$i] = $PID Then
                                Return $array[$i] & '|' & $array[$i]
                        EndIf
                Next
        EndIf
        Return $array
EndFunc   ;==>_ProcessListOWNER_WTS

柠檬时代 发表于 2024-10-15 11:53:03

tubaba 发表于 2024-10-15 11:24
由于是脚本中剥离




非常感谢您的快速回应。目前,我遇到的问题是在将程序编译为32位之后,运行时遇到困难。具体来说,我未能在服务列表中找到与该程序相关的服务进程,即使在电脑重启之后也是如此,程序并未自启动或者执行我指定的任务。当我尝试双击运行该程序时,它以我当前的用户身份直接打开了指定的应用,而非作为服务进程运行。

柠檬时代 发表于 2024-10-15 12:05:22

tubaba 发表于 2024-10-15 11:24
由于是脚本中剥离




在使用了您提供的代码来调用之前以服务形式运行的指定exe之后,权限继承的问题依然存在。

tubaba 发表于 2024-10-15 14:30:52

本帖最后由 tubaba 于 2024-10-15 14:59 编辑


以上演示 第一次execrunas以管理员身份启动, 然后用system权限启动自身,可以看到标题栏的用户名是system,然后用它启动test3.exe,可以看到,此时cmd.exe是运行在标准用户权限下.(test3.exe即由楼上的代码编译)



我不知道你做成服务的方式,有两种方法
一种是用第三方程序,比如使用Instsrv.exe和Srvany.exe 安装windows服务
另一种,自己用au3编写服务,论坛也有介绍.


你应该明白的是,服务是运行在system帐户下,环境变量与登录用户的环境变量完全不一样,比如@temp这种宏,指向的目录是不一样的.
你可以先测试你的exe,在system帐户下运行时,其功能是否可以达到你的预期.
最后一点,服务程序是运行在session0下,而桌面用户在session1,2,3......以上,这也就意味着,你服务程序里如果有msgbox等弹出的GUI,在桌面用户下是看不到的,也就是通常所说的无法交互.我提供的方法中,是创建当前sessionID下的进程,所以可以交互





页: [1]
查看完整版本: 【提问求助】以服务运行指定程序,权限不继承