AGB  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Neuen Beitrag zur Code-Library hinzufügen Delphi Service: UAC Elevated Child Prozess im Benutzerkontext starten

Service: UAC Elevated Child Prozess im Benutzerkontext starten

Ein Thema von Zacherl · begonnen am 9. Mai 2011 · letzter Beitrag vom 26. Jul 2013
Antwort Antwort
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
3.471 Beiträge
 
Delphi XE3 Professional
 
#1

Service: UAC Elevated Child Prozess im Benutzerkontext starten

  Alt 9. Mai 2011, 17:37
Hallo zusammen,

nachdem ich nun fast 4 Stunden herumprobiert habe, poste ich hier mal eine Lösung, mit der man aus einem Dienst heraus einen Prozess mit UAC Elevation starten kann. Ist der momentan eingeloggte Benutzer kein Administrator, wird der Prozess mit eingeschränkten Rechten gestartet.

Das Besondere an dieser Lösung ist, dass der neu erzeugte Prozess auch wirklich im Kontext des Benutzers und nicht als SYSTEM läuft.

Delphi-Quellcode:
function OpenShellProcessToken(ProcessName: String;
  var hToken: THandle): Boolean;
var
  hSnapshot,
  hProcess: THandle;
  Process: TProcessEntry32;
begin
  Result := false;
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if (hSnapshot <> 0) and (hSnapshot <> INVALID_HANDLE_VALUE) then
  try
    FillChar(Process, SizeOf(Process), #0);
    Process.dwSize := SizeOf(Process);
    if Process32First(hSnapshot, Process) then
    repeat
      if (AnsiLowerCase(Process.szExeFile) =
        AnsiLowerCase(ProcessName)) then
      begin
        hProcess :=
          OpenProcess(PROCESS_ALL_ACCESS, false, Process.th32ProcessID);
        if (hProcess <> 0) and (hProcess <> INVALID_HANDLE_VALUE) then
        try
          Result := OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, hToken);
        finally
          CloseHandle(hProcess);
        end;
        Break;
      end;
    until (not Process32Next(hSnapshot, Process));
  finally
    CloseHandle(hSnapshot);
  end;
end;

function CreateProcessElevated(lpApplicationName: PChar; lpCommandLine: PChar;
  lpCurrentDirectory: PChar; var ProcessInfo: TProcessInformation): Boolean;
var
  WTSGetActiveConsoleSessionId: function: DWord; stdcall;
  WTSQueryUserToken: function(SessionId: ULONG;
    var phToken: THandle): BOOL; stdcall;
  CreateEnvironmentBlock: function(lpEnvironment: PPointer; hToken: THandle;
    bInherit: BOOL): BOOL; stdcall;
  DestroyEnvironmentBlock: function(lpEnvironment: LPVOID): BOOL; stdcall;
var
  hUserToken,
  hLinkedToken,
  hElevatedToken: THandle;
  ReturnLength,
  ElevationType: DWord;
  Environment: Pointer;
  StartupInfo: TStartupInfo;
begin
  Result := false;
  @CreateEnvironmentBlock :=
    GetProcAddress(LoadLibrary('userenv.dll'), 'CreateEnvironmentBlock');
  @DestroyEnvironmentBlock :=
    GetProcAddress(LoadLibrary('userenv.dll'), 'DestroyEnvironmentBlock');
  if (not Assigned(CreateEnvironmentBlock)) or
    (not Assigned(DestroyEnvironmentBlock)) then Exit;
  @WTSGetActiveConsoleSessionId :=
    GetProcAddress(LoadLibrary('kernel32.dll'), 'WTSGetActiveConsoleSessionId');
  @WTSQueryUserToken :=
    GetProcAddress(LoadLibrary('wtsapi32.dll'), 'WTSQueryUserToken');
  if (Assigned(WTSGetActiveConsoleSessionId) and
    Assigned(WTSQueryUserToken)) then
  begin
    Result := WTSQueryUserToken(WTSGetActiveConsoleSessionId, hUserToken);
  end else
  begin
    Result := OpenShellProcessToken('explorer.exe', hUserToken);
  end;
  if Result then
  try
    if GetTokenInformation(hUserToken, TokenElevationType, @ElevationType,
      SizeOf(ElevationType), ReturnLength) then
    begin
      if (ElevationType = 3) then
      begin
        if GetTokenInformation(hUserToken, TokenLinkedToken,
          @hLinkedToken, SizeOf(hLinkedToken), ReturnLength) then
        try
          Result := DuplicateTokenEx(hLinkedToken, MAXIMUM_ALLOWED, nil,
            SecurityImpersonation, TokenPrimary, hElevatedToken);
        finally
          CloseHandle(hLinkedToken);
        end;
      end else
      begin
        hElevatedToken := hUserToken;
      end;
      try
        if CreateEnvironmentBlock(@Environment, hElevatedToken, false) then
        try
          FillChar(StartupInfo, SizeOf(StartupInfo), #0);
          StartupInfo.cb := SizeOf(StartupInfo);
          Result := CreateProcessAsUser(hElevatedToken, lpApplicationName,
            lpCommandLine, nil, nil, false, CREATE_NEW_CONSOLE or
            CREATE_DEFAULT_ERROR_MODE or CREATE_UNICODE_ENVIRONMENT,
            Environment, lpCurrentDirectory, StartupInfo, ProcessInfo);
        finally
          DestroyEnvironmentBlock(Environment);
        end;
      finally
        CloseHandle(hElevatedToken);
      end;
    end;
  finally
    CloseHandle(hUserToken);
  end;
end;
Lauffähig sollte das ganze ab Windows 2000 sein.

Viele Grüße
Zacherl
"Do not argue with an idiot. He will drag you down to his level and beat you with experience."
  Mit Zitat antworten Zitat
Benutzerbild von rollstuhlfahrer
rollstuhlfahrer

Registriert seit: 1. Aug 2007
Ort: Ludwigshafen am Rhein
1.527 Beiträge
 
Delphi 7 Professional
 
#2

AW: Service: UAC Elevated Child Prozess im Benutzerkontext starten

  Alt 9. Mai 2011, 21:03
Delphi-Quellcode:
    if GetTokenInformation(hUserToken, TokenElevationType, @ElevationType,
      SizeOf(ElevationType), ReturnLength) then
    begin
      if (ElevationType = 3) then
      begin
        if GetTokenInformation(hUserToken, TokenLinkedToken,
          @hLinkedToken, SizeOf(hLinkedToken), ReturnLength) then
        try
          Result := DuplicateTokenEx(hLinkedToken, MAXIMUM_ALLOWED, nil,
            SecurityImpersonation, TokenPrimary, hElevatedToken);
        finally
          CloseHandle(hLinkedToken);
        end;
Das ist also der Code, um dem neuen Prozess Admin-Rechte zu verschaffen? - Das hab ich jetzt nicht wirklich verstanden: Du erstellst ein User-Token. Dazu erstellst du ein 2. Token, welches mit dem ersten verknüpft ist. Dann erstellst du ein 3. Token, welches aus dem 2. Token dupliziert wurde. Soweit komme ich schon nicht mehr mit. ABER: Jetzt schließt du vorzeitig das 2. Token. Das will mir nicht in den Kopf.

Aber egal, Hauptsache der Code funktioniert. Mich würde natürlich trotzdem gerne interessieren, bei welcher Zeile jetzt dem System gesagt wurde, dass der Prozess Admin-Rechte bekommt. Und was mich auch brennend interessiert ist, was passiert, wenn eine Anwendung mit Admin-Manifest ohne Admin-Rechte gestartet wurde.

Übrigens: Da ist ein größerer Fehler drin: Laut MSDN kommt in ElevationType eine Zahl ungleich Null rein, wenn es Admin-Rechte zu verteilen gibt, ansonsten kommt da Null rein. Die Prüfung auf 3 ist somit nicht 100%ig sicher!
Bernhard
Iliacos intra muros peccatur et extra!
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
3.471 Beiträge
 
Delphi XE3 Professional
 
#3

AW: Service: UAC Elevated Child Prozess im Benutzerkontext starten

  Alt 9. Mai 2011, 22:42
Das ist also der Code, um dem neuen Prozess Admin-Rechte zu verschaffen? - Das hab ich jetzt nicht wirklich verstanden: Du erstellst ein User-Token. Dazu erstellst du ein 2. Token, welches mit dem ersten verknüpft ist. Dann erstellst du ein 3. Token, welches aus dem 2. Token dupliziert wurde. Soweit komme ich schon nicht mehr mit. ABER: Jetzt schließt du vorzeitig das 2. Token. Das will mir nicht in den Kopf.
UserToken ist das Standardtoken vom aktuell eingeloggten Benutzer. Jedes Benutzertoken hab ab Vista laut diversen Seiten ein LinkedToken. Dieses muss man verwenden, um den Prozess UAC elevated zu starten.
Ich konvertiere das Token dann in ein Primary Token namens ElevatedToken. Danach kann ich das "alte" Token ja ohne weiteres schließen Das Neue bleibt ja erhalten.

Und was mich auch brennend interessiert ist, was passiert, wenn eine Anwendung mit Admin-Manifest ohne Admin-Rechte gestartet wurde.
Das habe ich noch gar nicht ausprobiert.

Übrigens: Da ist ein größerer Fehler drin: Laut MSDN kommt in ElevationType eine Zahl ungleich Null rein, wenn es Admin-Rechte zu verteilen gibt, ansonsten kommt da Null rein. Die Prüfung auf 3 ist somit nicht 100%ig sicher!
Da hast du dich verguckt. Ich frage nicht die TokenElevation, sondern die TokenElevationType Klasse ab. Der MSDN Eintrag dazu ist hier zu finden:
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

Wobei ich sehe grade, dass ich den Typen als DWord deklariert habe. Ist das korrekt für ein C++ Enum oder muss da besser Byte hin?
"Do not argue with an idiot. He will drag you down to his level and beat you with experience."
  Mit Zitat antworten Zitat
Benutzerbild von rollstuhlfahrer
rollstuhlfahrer

Registriert seit: 1. Aug 2007
Ort: Ludwigshafen am Rhein
1.527 Beiträge
 
Delphi 7 Professional
 
#4

AW: Service: UAC Elevated Child Prozess im Benutzerkontext starten

  Alt 9. Mai 2011, 22:53
Da hast du dich verguckt. Ich frage nicht die TokenElevation, sondern die TokenElevationType Klasse ab. Der MSDN Eintrag dazu ist hier zu finden:
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
Nehm ich zurück.

Wobei ich sehe grade, dass ich den Typen als DWord deklariert habe. Ist das korrekt für ein C++ Enum oder muss da besser Byte hin?
Da scheinen sich die Meinungen zu spalten. Laut diesem Thread ist ein Enum 4 Bytes groß, also sollte DWord passen.

ADD: Es scheint dabei aber dem Compiler überlassen zu sein, wie groß der Typ dann wirklich ist (siehe Stackoverflow).

Bernhard
Bernhard
Iliacos intra muros peccatur et extra!

Geändert von rollstuhlfahrer ( 9. Mai 2011 um 22:56 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
3.471 Beiträge
 
Delphi XE3 Professional
 
#5

AW: Service: UAC Elevated Child Prozess im Benutzerkontext starten

  Alt 9. Mai 2011, 22:56
Danke dir fürs nachschlagen, dann werd ichs einfach mal so lassen. Habe zwar bisher nur unter Win7 64 bit getestet, aber da funktionierts schonmal wunderbar
"Do not argue with an idiot. He will drag you down to his level and beat you with experience."
  Mit Zitat antworten Zitat
Dezipaitor

Registriert seit: 14. Apr 2003
Ort: Stuttgart
1.699 Beiträge
 
Delphi 7 Professional
 
#6

AW: Service: UAC Elevated Child Prozess im Benutzerkontext starten

  Alt 9. Mai 2011, 23:14
Glückwunsch für diesen Akt. Ich will deine Freude nicht schmälern, aber den Code hättest du sicher auch mit etwas Suche und Geduld hier in irgendeiner Form gefunden. Trotzdem ist die daraus gewonnene Erkenntnis und Erfahrung unersetzlich und wird dir bei ähnlichen Problemen helfen.



Wenn du eine Anwendung mit Manifest, aber ohne Admintoken in CreateProcessAsUser starten willst, wird CPAU fehlschlagen und die Fehlermeldung ERROR_ELEVATION_REQUIRED (740) über GetLastError zurückmelden. Dann muss man ShellExecute (nicht im Dienst, sondern über extra Prozess!) verwenden.

Jedes Tokenn besitzt ein Feld LinkedToken, das ein weiteres Token enthält. Wenn UAC aktiv ist, dann bekommt man darüber das Admintoken. Das Admintoken hat auch so ein Feld und man bekommt darüber das eingeschränkte Token. Es ist also ein Ringschluss. Nun ist es aber dennoch möglich auch als normaler Benutzer das Admintoken über dieses Feld zu laden, jedoch verweigert CPAU und ImpersonateLoggedOnUser die Nutzung. Mehr Info siehe dazu in der Hilfe zur letztgenannten Funktion.

Enums haben tatsächlich keine exakte Größe, wenn man allgemein spricht. Man kann aber Compilern normalerweise irgendwie mitteilen, wie groß mindestens ein Enum sein soll, z.B. in Delphi mit $MINENUMSIZE (oder ähnlich). MS C++ Compiler kann es auch und das Windows SDK nutzt es auch. Am sichersten kannst du es sehen, indem du den Datentyp in C mit sizeof auf dessen Größe prüfst.
Christian
Windows, Tokens, Access Control List, Dateisicherheit, Desktop, Vista Elevation?
Goto: JEDI API LIB & Windows Security Code Library (JWSCL)
  Mit Zitat antworten Zitat
Benutzerbild von kuba
kuba

Registriert seit: 26. Mai 2006
Ort: Arnsberg
491 Beiträge
 
Delphi XE7 Professional
 
#7

AW: Service: UAC Elevated Child Prozess im Benutzerkontext starten

  Alt 26. Jul 2013, 00:07
Das ist also der Code, um dem neuen Prozess Admin-Rechte zu verschaffen?
Nee, steht doch im Einleitungstext. Der Prozess wird lediglich UAC-Elevated gestartet...

Ist der momentan eingeloggte Benutzer kein Administrator, wird der Prozess mit eingeschränkten Rechten gestartet.
Habe gerade ein paar Tests gemacht ...

KUBA
Stefan Kubatzki
E=mc2
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:00 Uhr.
Powered by vBulletin® Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2014 by Daniel R. Wolf