2016-09-23 4 views
0

Wir haben eine Dienstanwendung, die einen Prozess in der Konsolensitzung (WTSGetActiveConsoleSessionId) erzeugt, um einen Desktop-Steuerstilzugriff auf den Computer zu ermöglichen. Dies funktioniert in den meisten Situationen gut, aber es gibt einige VMs, die den Prozess erfolgreich erstellen, soweit das Ergebnis von CreateProcessAsUser betroffen ist, jedoch wird der Prozess nicht erstellt.CreateProcessAsUser ist erfolgreich, aber es wurde kein Prozess erstellt.

Der Dienst wird unter dem Konto LocalSystem ausgeführt. Der gestartete Prozess läuft NICHT. Es laufen keine Virenschutzprogramme. Wir haben dieses Verhalten nur unter Windows Server 2008 R2 gesehen (aber das ist nicht exklusiv).

Der Code, den wir verwenden, ist wie folgt:

function StartProcessInSession(strProcess: String; bLocalSystem: Boolean = True; iSessionID: Integer = -1): Boolean; 

    procedure SPISLog(strLog: String; bError: Boolean = False); 
    begin 
    Log(strLog); 
    if bError then Abort; 
    end; 

var pi: PROCESS_INFORMATION; 
    si: STARTUPINFO; 
    winlogonPid, dwSessionId: DWord; 
    hUserToken, hUserTokenDup, hPToken, hProcess: THANDLE; 
    dwCreationFlags: DWORD; 
    tp: TOKEN_PRIVILEGES; 
    lpenv: Pointer; 
    bError: Boolean; 
    strClone: String; 
begin 
    if GetProcessID(strProcess, iSessionID) > 0 then 
    begin 
    Result := True; 
    Exit; 
    end; 
    Result := False; 
    bError := False; 
    if not InitProcLibs then Exit; 
    if bLocalSystem then strClone := 'winlogon.exe' else strClone := 'explorer.exe'; 
    winlogonPid := GetProcessID(strClone, iSessionID); 
    try 
    dwSessionId := WTSGetActiveConsoleSessionId(); 
    dwCreationFlags := NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE; 
    ZeroMemory(@si, sizeof(STARTUPINFO)); 
    si.cb := sizeof(STARTUPINFO); 
    si.lpDesktop := PChar('Winsta0\Default'); 
    ZeroMemory(@pi, sizeof(pi)); 
    hProcess := OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid); 
    if (not OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY or TOKEN_DUPLICATE or 
     TOKEN_ASSIGN_PRIMARY or TOKEN_ADJUST_SESSIONID or TOKEN_READ or TOKEN_WRITE, hPToken)) then 
     bError := True; 
    if bError then SPISLog('SPIS - OpenProcessToken failed (' + SysErrorMessage(GetLastError) + ').', True); 
    if (not LookupPrivilegeValue(nil, SE_DEBUG_NAME, tp.Privileges[0].Luid)) then bError := True; 
    if bError then SPISLog('SPIS - LookupPrivilegeValue failed (' + SysErrorMessage(GetLastError) + ').', True); 
    tp.PrivilegeCount := 1; 
    tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; 
    DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, nil, SecurityIdentification, TokenPrimary, hUserTokenDup); 
    SetTokenInformation(hUserTokenDup, TokenSessionId, Pointer(dwSessionId), SizeOf(DWORD)); 
    if (not AdjustTokenPrivileges(hUserTokenDup, FALSE, @tp, SizeOf(TOKEN_PRIVILEGES), nil, nil)) then bError := True; 
    if bError then SPISLog('SPIS - AdjustTokenPrivileges failed (' + SysErrorMessage(GetLastError) + ').', True); 
    if (GetLastError() = ERROR_NOT_ALL_ASSIGNED) then bError := True; 
    if bError then SPISLog('SPIS - AdjustTokenPrivileges: ERROR_NOT_ALL_ASSIGNED (' + SysErrorMessage(GetLastError) + ').', True); 
    lpEnv := nil; 
    if (CreateEnvironmentBlock(lpEnv, hUserTokenDup, TRUE)) then 
     dwCreationFlags := dwCreationFlags or CREATE_UNICODE_ENVIRONMENT 
    else 
     lpEnv := nil; 
    if not Assigned(lpEnv) then SPISLog('SPIS - CreateEnvironmentBlock failed (' + SysErrorMessage(GetLastError) + ').', True); 
    try 
     UniqueString(strProcess); 
     if not CreateProcessAsUser(hUserTokenDup, nil, PChar(strProcess), nil, nil, FALSE, 
     dwCreationFlags, lpEnv, PChar(ExtractFilePath(strProcess)), si, pi) then bError := True; 
     if bError then 
     SPISLog('SPIS - CreateProcessAsUser failed (' + SysErrorMessage(GetLastError) + ').', True) 
     else 
     SPISLog('Started process in ' + IntToStr(dwSessionId) + ' using token from ' + IntToStr(winlogonPid) + '.'); 
     try 
     try CloseHandle(hProcess); except {} end; 
     try CloseHandle(hUserToken); except {} end; 
     try CloseHandle(hUserTokenDup); except {} end; 
     try CloseHandle(hPToken); except {} end; 
     except 
     {} 
     end; 
    finally 
     DestroyEnvironmentBlock(lpEnv); 
    end; 
    except 
    on E: Exception do 
    begin 
     bError := True; 
     if not (E is EAbort) then 
     SPISLog('SPIS - ' + E.Message + ' (' + SysErrorMessage(GetLastError) + ').', True); 
    end; 
    end; 
    Result := not bError; 
end; 

function GetProcessID(strProcess: String; iSessionID: Integer = -1): DWORD; 
var dwSessionId, winlogonSessId: DWord; 
    hsnap: THandle; 
    procEntry: TProcessEntry32; 
    myPID: Cardinal; 
begin 
    Result := 0; 
    if not InitProcLibs then Exit; 
    { check running processes and return ID of process in current session... } 
    if iSessionID = -1 then 
    dwSessionId := WTSGetActiveConsoleSessionId 
    else 
    dwSessionId := iSessionID; 
    hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
    if (hSnap = INVALID_HANDLE_VALUE) then Exit; 
    strProcess := UpperCase(ExtractFileName(strProcess)); 
    myPID:= GetCurrentProcessId; 
    procEntry.dwSize := sizeof(TProcessEntry32); 
    if (not Process32First(hSnap, procEntry)) then Exit; 
    repeat 
    if (procEntry.th32ProcessID <> myPID) and ((UpperCase(procEntry.szExeFile) = strProcess) or 
     (UpperCase(ExtractFileName(procEntry.szExeFile)) = strProcess)) then 
    begin 
     winlogonSessId := 0; 
     if (ProcessIdToSessionId(procEntry.th32ProcessID, winlogonSessId) and (winlogonSessId = dwSessionId)) then 
     begin 
     Result := procEntry.th32ProcessID; 
     break; 
     end; 
    end; 
    until (not Process32Next(hSnap, procEntry)); 
end; 

Weiß jemand, warum es scheitern würde, oder ob es eine Art zu arbeiten, was mit diesem Aufruf in der API geschieht?

+1

Verwenden Sie WTSEnumerateSessions und suchen Sie nach der ersten aktiven Sitzung anstelle von WTSGetActiveConsoleSession. Es funktioniert nicht mit RDP-Verbindungen. – FredS

+0

"eine Möglichkeit herauszufinden, was mit diesem Aufruf in der API passiert?" - muss einen Prozess im gesperrten Zustand erstellen, den Debugger an den neu erstellten Prozess anhängen und danach wieder starten – RbMm

+2

Dieser Code ist nahe an nicht lesbar. Die Fehlerbehandlung ist undurchdringlich. –

Antwort

0

Vielen Dank für Ihre Hilfe, fand ich endlich das Problem, der Prozess begann ich statisch eine DLL (speziell aw_sas64.dll) verlinkt, dies funktionierte auf den meisten Maschinen, aber nicht andere, ich bin mir immer noch nicht sicher warum (Die DLL befindet sich im selben Ordner wie die EXE).

Ich konnte nicht die DLL zu arbeiten, indem sie es dynamisch zu verknüpfen (obwohl die 32-Bit-Version dynamisch verknüpft OK), aber sobald ich die statische Verbindung und Verwendung kommentiert wurde der Prozess wurde OK durch die obige Prozedur gestartet .

Nochmals, vielen Dank an alle, ich habe noch ein paar Probleme übrig, aber das löst das Rätsel.

Verwandte Themen