Jump to content

[Solved] Why doesnt my service start in logged in user's session?


E1M1
 Share

Recommended Posts

Hello

My intention is to restart my service in logged in user's session but have it run as SYSTEM. Logic tells me that if environment's token is from user and other token that is passed to CreateProcessAsUser() is from system then it should run it in user's environment but it doesnt.

I have even Local $sDesktop = "winsta0\default" but still no result. If I get hToken from user then it runs in user session but it's username isn't SYSTEM anymore.

;~ CreateProcessAsUser(hToken,NULL,app_path,NULL,NULL,FALSE,CREATE_UNICODE_ENVIRONMENT |DETACHED_PROCESS,lpEnvironment,NULL,&StartUPInfo,&ProcessInfo))
#include <winapi.au3>
#include <array.au3>
#include <security.au3>
GUICreate("...")
GUISetState(@SW_SHOW)
$force_gui = true
;~ $force_gui = False
;~ $list = ProcessList("ra2.exe")
;~ If $list[0][0] > 1 Then
;~ Sleep(1000)
;~ MsgBox(0,"test","abc",10)
;~ Exit
;~ EndIf

$NULL = 0
$FALE = 0
$TRUE = 1
$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'


;testing
;~ $s = ""
;~ GetModuleFileName(0,$s,260)
;~ MsgBox(0,0,$s)

#cs
typedef struct _STARTUPINFO {
DWORD cb; 1
LPTSTR lpReserved; 2
LPTSTR lpDesktop; 3
LPTSTR lpTitle; 4
DWORD dwX; 5
DWORD dwY; 6
DWORD dwXSize; 7
DWORD dwYSize; 8
DWORD dwXCountChars; 9
DWORD dwYCountChars; 10
DWORD dwFillAttribute; 11
DWORD dwFlags; 12
WORD wShowWindow; 13
WORD cbReserved2; 14
LPBYTE lpReserved2; 15
HANDLE hStdInput; 16
HANDLE hStdOutput; 17
HANDLE hStdError; 18
} STARTUPINFO, *LPSTARTUPINFO;


typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
#ce
LaunchProcessWin()
Func LaunchProcessWin()
$bReturn = False
$hToken = 0
$env = 0
$StartUPInfo = DllstructCreate($tagSTARTUPINFO)
$ProcessInfo = DllStructCreate("HANDLE;HANDLE;DWORD;DWORD")
MemSet(DllStructGetPtr($StartUPInfo),Chr(0),DllStructGetSize($StartUPInfo))
MemSet(DllStructGetPtr($ProcessInfo),Chr(0),DllStructGetSize($ProcessInfo))
DllStructSetData($StartUPInfo, 13, @SW_SHOW)
Local $sDesktop = "winsta0\default"
Local $lpDesktop = DllStructCreate("char[" & StringLen($sDesktop) + 1 & "]")
DllStructSetData($lpDesktop, 1, $sDesktop)
DllStructSetData($StartUPInfo, 3, DllStructGetPtr($lpDesktop))
DllStructSetData($StartUPInfo, 1, DllStructGetSize($StartUPInfo))
$app_path = ""
SetTBCPrivileges()
$id = WTSGetActiveConsoleSessionId()
_MsgBox(0, DllStructGetData($StartUPInfo, 3), $id )
$hTokenuser = WTSQueryUserToken($id)
$hToken = _Security__OpenProcessToken(-1, $TOKEN_ALL_ACCESS)
_MsgBox(0, 2, "abc")
$hToken = _Security__DuplicateTokenEx($hToken, $TOKEN_ALL_ACCESS, $SECURITYIMPERSONATION, $TOKENPRIMARY)
CreateEnvironmentBlock($env, $hTokenuser, 0)
_MsgBox(0,$hToken, $env)
GetModuleFileName(0,$app_path,$MAX_PATH)
_MsgBox(0, 3, DllStructGetPtr($StartUPInfo))
$file = DllStructCreate("char[260]")
$lpProcessAttributes=dllstructcreate($tagSECURITY_ATTRIBUTES)
$lpThreadAttributes=dllstructcreate($tagSECURITY_ATTRIBUTES)
DLLStructSetData($lpThreadAttributes,"Descriptor",0)
$ta_size=dllstructgetsize($lpThreadAttributes)
DLLStructSetData($lpThreadAttributes,"Length",$ta_size)
DLLStructSetData($lpProcessAttributes,"Descriptor",0)
$pa_size=dllstructgetsize($lpProcessAttributes)
DLLStructSetData($lpProcessAttributes,"Length",$pa_size)
$ret = CreateProcessAsUser($hToken, "", $app_path, DllStructGetPtr($lpProcessAttributes), DllStructGetPtr($lpThreadAttributes), 0, $CREATE_UNICODE_ENVIRONMENT + $DETACHED_PROCESS, $env,"", $StartUPInfo, $ProcessInfo)
_MsgBox(0, "4 "&$ret[0], DllStructGetData($ProcessInfo,3))
;CreateProcessAsUser(hToken,NULL,app_path,NULL,NULL,FALSE,CREATE_UNICODE_ENVIRONMENT |DETACHED_PROCESS,lpEnvironment,NULL,&StartUPInfo,&ProcessInfo)// C++
EndFunc ;==>LaunchProcessWin


Func MemSet($pDest, $nChar, $nCount)
DllCall("msvcrt.dll", "ptr:cdecl", "memset", "ptr", $pDest, "int", $nChar, "int", $nCount)
If @error Then Return SetError(1,0,False)
Return True
EndFunc


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

Func WTSQueryUserToken($SessionId)
$struct = DllStructCreate("HANDLE")
$Ret = DllCall('wtsapi32.dll', 'bool', 'WTSQueryUserToken', _
'ULONG', $SessionId, _
'ptr*', DllStructGetPtr($struct))
If $Ret[0] <> 0 Then
Return $Ret[2]
Else
_MsgBox(16, "Error (you must run me as system service)", _WinAPI_GetLastErrorMessage(), 10)
Exit
EndIf
EndFunc ;==>WTSQueryUserToken

Func WTSGetActiveConsoleSessionId()
$Ret = DllCall('Kernel32.dll', 'dword', 'WTSGetActiveConsoleSessionId')
Return $Ret[0]
EndFunc ;==>WTSGetActiveConsoleSessionId


Func GetModuleFileName($hModule,byref $lpFilename, $nSize)
$Ret = DllCall('Kernel32.dll', 'int', 'GetModuleFileNameW', _
'handle', $hModule, _
'wstr', 0, _
'int', $nSize)
$lpFilename = $Ret[2]
Return $Ret[0]
EndFunc


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


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
$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),$NULL,$NULL) = False Then Return false
if _WinAPI_GetLastError() <> $ERROR_SUCCESS Then Return False
_WinAPI_CloseHandle($hToken);
_WinAPI_CloseHandle($hProcess);
Return true
EndFunc

Func _WinAPI_OpenProcessToken($pHandle, $iAccess, byref $hToken)
Local $aResult = DllCall("advapi32.dll", "int", "OpenProcessToken", "hwnd", $pHandle, "int", $iAccess, "int*", 0)
If @error Or $aResult[0] = 0 Then Return SetError(1, 0, 0)
$hToken = $aResult[3]
Return $aResult[0]
EndFunc

;Debugging

Func _MsgBox($a, $b, $c, $d = 0)
If @UserName <> "SYSTEM" Or $force_gui Then
MsgBox($a, $b, $c, $d)
Else
FileWrite(@ScriptDir & "\mb.txt", '"' & $b & '"' & ", " & '"' & $c & '"' & @CRLF)
EndIf
EndFunc ;==>_MsgBox
Func __ArrayDisplay($a, $b = "array")
If @UserName <> "SYSTEM" Or $force_gui Then
_ArrayDisplay($a, $b)
Else
$dat = $b & @CRLF
For $i = 0 To UBound($a) - 1
$dat &= @TAB & $a[$i] & @CRLF
Next
FileWrite(@ScriptDir & "\arr.txt", $dat)
EndIf
EndFunc ;==>__ArrayDisplay

edit: had to set token information. Here's working code for everyone who are interested

;~ CreateProcessAsUser(hToken,NULL,app_path,NULL,NULL,FALSE,CREATE_UNICODE_ENVIRONMENT |DETACHED_PROCESS,lpEnvironment,NULL,&StartUPInfo,&ProcessInfo))
#include <winapi.au3>
#include <array.au3>
#include <security.au3>
#include <SecurityConstants.au3>
GUICreate("...")
GUISetState(@SW_SHOW)
$force_gui = true

;~ $force_gui = False
;~ $list = ProcessList("ra2.exe")
;~ If $list[0][0] > 1 Then
;~ Sleep(1000)
;~ MsgBox(0,"test","abc",10)
;~ Exit
;~ EndIf

$NULL = 0
$FALE = 0
$TRUE = 1
$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'
wlist()
func wlist()
    $wl = WinList()
    $swin = "---------"&@AutoItPID
    For $i = 1 to $wl[0][0]
        $swin &= $wl[$i][0]&@CRLF
    Next
    FileWrite(@ScriptDir&"\winl.txt",$swin)
EndFunc

;testing
;~ $s = ""
;~ GetModuleFileName(0,$s,260)
;~ MsgBox(0,0,$s)

#cs
    typedef struct _STARTUPINFO {
    DWORD  cb; 1
    LPTSTR lpReserved; 2
    LPTSTR lpDesktop; 3
    LPTSTR lpTitle; 4
    DWORD  dwX; 5
    DWORD  dwY; 6
    DWORD  dwXSize; 7
    DWORD  dwYSize; 8
    DWORD  dwXCountChars; 9
    DWORD  dwYCountChars; 10
    DWORD  dwFillAttribute; 11
    DWORD  dwFlags; 12
    WORD   wShowWindow; 13
    WORD   cbReserved2; 14
    LPBYTE lpReserved2; 15
    HANDLE hStdInput; 16
    HANDLE hStdOutput; 17
    HANDLE hStdError; 18
    } STARTUPINFO, *LPSTARTUPINFO;


    typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD  dwProcessId;
    DWORD  dwThreadId;
    } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
#ce
LaunchProcessWin()
Func LaunchProcessWin()
    $bReturn = False
    $hToken = 0
    $env = 0
    $StartUPInfo = DllstructCreate($tagSTARTUPINFO)
    $ProcessInfo = DllStructCreate("HANDLE;HANDLE;DWORD;DWORD")
    MemSet(DllStructGetPtr($StartUPInfo),Chr(0),DllStructGetSize($StartUPInfo))
    MemSet(DllStructGetPtr($ProcessInfo),Chr(0),DllStructGetSize($ProcessInfo))
    DllStructSetData($StartUPInfo, 13, @SW_SHOW)
    Local $sDesktop = "winsta0\default"
    Local $lpDesktop = DllStructCreate("wchar[" & StringLen($sDesktop) + 1 & "]")
    DllStructSetData($lpDesktop, 1, $sDesktop)
    DllStructSetData($StartUPInfo, 3, DllStructGetPtr($lpDesktop))
    DllStructSetData($StartUPInfo, 1, DllStructGetSize($StartUPInfo))
    $app_path = ""
    SetTBCPrivileges()
    $id = WTSGetActiveConsoleSessionId()
    _MsgBox(0, DllStructGetData($StartUPInfo, 3), $id )
    $hTokenuser = WTSQueryUserToken($id)
    $hToken = _Security__OpenProcessToken(-1, $TOKEN_ALL_ACCESS)
    _MsgBox(0, 2, "abc")
    $hToken = _Security__DuplicateTokenEx($hToken, $TOKEN_ALL_ACCESS, $SECURITYIMPERSONATION, $TOKENPRIMARY)
    $sid = DllStructCreate("DWORD")
    DllStructSetData($sid,1,$id)
    _Security__SetTokenInformation($hToken, $TOKENSESSIONID, DllStructGetPtr($sid), DllStructGetSize($sid))
    CreateEnvironmentBlock($env, $hToken, 0)
    _MsgBox(0,$hToken, $env)
    GetModuleFileName(0,$app_path,$MAX_PATH)
    _MsgBox(0, 3, DllStructGetPtr($StartUPInfo))
    $file = DllStructCreate("char[260]")
    $lpProcessAttributes=dllstructcreate($tagSECURITY_ATTRIBUTES)
    $lpThreadAttributes=dllstructcreate($tagSECURITY_ATTRIBUTES)
    DLLStructSetData($lpThreadAttributes,"Descriptor",0)
    $ta_size=dllstructgetsize($lpThreadAttributes)
    DLLStructSetData($lpThreadAttributes,"Length",$ta_size)
    DLLStructSetData($lpProcessAttributes,"Descriptor",0)
    $pa_size=dllstructgetsize($lpProcessAttributes)
    DLLStructSetData($lpProcessAttributes,"Length",$pa_size)
    Run("taskmgr")
    $ret = CreateProcessAsUser($hToken, "", $app_path, DllStructGetPtr($lpProcessAttributes), DllStructGetPtr($lpThreadAttributes), 0, $CREATE_UNICODE_ENVIRONMENT + $DETACHED_PROCESS, $env,"", $StartUPInfo, $ProcessInfo)
    _MsgBox(0, "4 "&$ret[0], DllStructGetData($ProcessInfo,3))
    ;CreateProcessAsUser(hToken,NULL,app_path,NULL,NULL,FALSE,CREATE_UNICODE_ENVIRONMENT |DETACHED_PROCESS,lpEnvironment,NULL,&StartUPInfo,&ProcessInfo)// C++
EndFunc   ;==>LaunchProcessWin


Func MemSet($pDest, $nChar, $nCount)
    DllCall("msvcrt.dll", "ptr:cdecl", "memset", "ptr", $pDest, "int", $nChar, "int", $nCount)
    If @error Then Return SetError(1,0,False)
    Return True
EndFunc


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

Func WTSQueryUserToken($SessionId)
    $struct = DllStructCreate("HANDLE")
    $Ret = DllCall('wtsapi32.dll', 'bool', 'WTSQueryUserToken', _
            'ULONG', $SessionId, _
            'ptr*', DllStructGetPtr($struct))
    If $Ret[0] <> 0 Then
        Return $Ret[2]
    Else
        _MsgBox(16, "Error (you must run me as system service)", _WinAPI_GetLastErrorMessage(), 10)
        Exit
    EndIf
EndFunc   ;==>WTSQueryUserToken

Func WTSGetActiveConsoleSessionId()
    $Ret = DllCall('Kernel32.dll', 'dword', 'WTSGetActiveConsoleSessionId')
    Return $Ret[0]
EndFunc   ;==>WTSGetActiveConsoleSessionId


Func GetModuleFileName($hModule,byref $lpFilename, $nSize)
    $Ret = DllCall('Kernel32.dll', 'int', 'GetModuleFileNameW', _
            'handle', $hModule, _
            'wstr', 0, _
            'int', $nSize)
    $lpFilename = $Ret[2]
    Return $Ret[0]
EndFunc


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


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
    $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),$NULL,$NULL) = False Then Return false
    if _WinAPI_GetLastError() <> $ERROR_SUCCESS Then Return False
    _WinAPI_CloseHandle($hToken);
    _WinAPI_CloseHandle($hProcess);
    Return true
EndFunc

Func _WinAPI_OpenProcessToken($pHandle, $iAccess, byref $hToken)
    Local $aResult = DllCall("advapi32.dll", "int", "OpenProcessToken", "hwnd", $pHandle, "int", $iAccess, "int*", 0)
    If @error Or $aResult[0] = 0 Then Return SetError(1, 0, 0)
    $hToken = $aResult[3]
    Return $aResult[0]
EndFunc

;Debugging

Func _MsgBox($a, $b, $c, $d = 0)
    If @UserName <> "SYSTEM" Or $force_gui Then
        MsgBox($a, $b, $c, $d)
    Else
        FileWrite(@ScriptDir & "\mb.txt", '"' & $b & '"' & ", " & '"' & $c & '"' & @CRLF)
    EndIf
EndFunc   ;==>_MsgBox
Func __ArrayDisplay($a, $b = "array")
    If @UserName <> "SYSTEM" Or $force_gui Then
        _ArrayDisplay($a, $b)
    Else
        $dat = $b & @CRLF
        For $i = 0 To UBound($a) - 1
            $dat &= @TAB & $a[$i] & @CRLF
        Next
        FileWrite(@ScriptDir & "\arr.txt", $dat)
    EndIf
EndFunc   ;==>__ArrayDisplay
Edited by E1M1

edited

Link to comment
Share on other sites

  • 10 months later...

hi E1M1,

i have a problem if i use your second script.

I write in the line of app patch:

$app_path = "C:\Windows\System32\cmd.exe"

and run this script as service with "srvany.exe".

The good message is, that the cmd.exe open with the SYSTEM-Account in the User Session ID (1), but the bad message is, that this script open the cmd.exe not one time. It open the programm infinitely until the memory is full :(.

can you help me by my problem?

sorry for my bad english :)

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...