Entwickler-Ecke

Windows API - Alle laufenden Prozesse listen / speicherbedarf anzeigen


Alice - Di 04.12.07 14:43
Titel: Alle laufenden Prozesse listen / speicherbedarf anzeigen
hi all,

ich versuche unter xp/vista mir alle laufenden prozesse un deren
akt. speicherverbrauch anzuzeigen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure TForm1.Button2Click(Sender: TObject);
var
MyHandle: THandle;
Struct: TProcessEntry32;
begin
 Listbox1.Items.Clear;
try
 MyHandle:=CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
 Struct.dwSize:=Sizeof(TProcessEntry32);
  if Process32First(MyHandle, Struct) then ListBox1.Items.Add(Struct.szExeFile);
 while Process32Next(MyHandle, Struct) do begin
  ListBox1.Items.Add(Struct.szExeFile + GetProcessMemorySize(Struct.th32ProcessID));
 end;
except on exception do
 ShowMessage('Error showing process list');
end;

end;


und


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
function TForm1.GetProcessMemorySize(ProcessID: Integer): String;
var
  Process: THandle;
  MemInfo: TProcessMemoryCounters;
begin
  Process := OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessID);
  if (GetProcessMemoryInfo(Process, @MemInfo, SizeOf(MemInfo))) then
    Result := '-'+floatToStr(MemInfo.WorkingSetSize / 1024)
  else
    Result := '-0';
end;


was soweit auch ganz gut funkt.,
nur bei einigen prozessen erhalte ich als
memorysize 0

wieso?

cu

alice


Delete - Di 04.12.07 15:58
Titel: Re: Alle laufenden Prozesse listen / speicherbedarf anzeigen
user profile iconAlice hat folgendes geschrieben:
nur bei einigen prozessen erhalte ich als
memorysize 0

wieso?

Weil du keine Rechte hast die Prozesse zu öffnen? Würdest du mal den Rückgabewert von OpenProcess auswerten (GetLastError, ...), wüsstest du es auch.


Alice - Di 04.12.07 18:17
Titel: Re: Alle laufenden Prozesse listen / speicherbedarf anzeigen
user profile iconLuckie hat folgendes geschrieben:

Weil du keine Rechte hast die Prozesse zu öffnen? Würdest du mal den Rückgabewert von OpenProcess auswerten (GetLastError, ...), wüsstest du es auch.


hi,

hmm...
bin als admin an der maschine angemeldet.
von daher sollte es eigentlich keinerlei probleme geben, denke ich mal!?

als getlasterror bekomme ich: 'Das Handle ist ungültig' zurück,
(bei denen die als speicherbed. eine 0 zurückgeben)

cu

alice


BlackDragon - Do 06.12.07 15:52

Hallo.

Du bist zwar als Admistrator angemeldet, aber Prozesse die vom System gestartet werden, stehen "über" dir. Du musst dir erst noch die entsprechenden Privilegien "aneignen".

Suchbegriffe:

- ImpersonateSelf
- OpenThreadToken
- SeDebugPrivilege

Alles entweder hier im Forum, in der Win32-Hilfe bei Delphi oder auf MSDN [http://msdn2.microsoft.com/en-us/library/] zu finden.

Das wird lustig sage ich dir. :P

Schau es dir mal an, wenn Fragen sind frag...

Mfg

Olli


Alice - Fr 07.12.07 19:38

user profile iconBlackDragon hat folgendes geschrieben:


- ImpersonateSelf
- OpenThreadToken
- SeDebugPrivilege


hi,

thx!

ich schaue mir die sache mal an...,
stimmt schon, ist schwieriger wie erstmal gedacht...

cu

alice


BlackDragon - Sa 08.12.07 01:42

user profile iconAlice hat folgendes geschrieben:

ich schaue mir die sache mal an...,
stimmt schon, ist schwieriger wie erstmal gedacht...


Bin da momentan selber dran, daher weiß ich was du meinst. Bin aber schon recht tief drin in der Materie.
Solltest du nicht klar kommen, einfach melden...

Ciao

Olli


BlackDragon - Di 11.12.07 10:56

Hi.

@Alice: Du hattest zwar eine PN gesendet, aber ich werde einen Lösungsansatz hier posten, da sicher noch einige dieses Problem haben werden.

Das Problem ist, wie bereits geschrieben, dass die nötigen Rechte fehlen um alle Informationen zu allen Prozessen zu erhalten.

Als erstes muss das Programm den Sicherheitsrahmen des lokalen Systems "imitieren". Das geschieht über den Aufruf von
ImpersonateSelf(SecurityImpersonation) [http://msdn2.microsoft.com/en-us/library/aa378729.aspx].
Dann muss über die OpenThreadToken [http://msdn2.microsoft.com/en-us/library/aa379296.aspx]-Funktion ein Handle zum eigenem Thread (das Programm) mit der gewünschten Zugriffsart geöffnet werden. Über die LookupPrivilegeValue [http://msdn2.microsoft.com/en-us/library/aa379180.aspx]-Funktion wird eine eindeutige ID geholt, welche das entsprechende Sicherheitsprivileg beschreibt. Über den Parameter "lpName" wird der String "SeDebugPrivilege" übergeben, dadurch wird der gewünschte Zugriff bedingungslos gewährt. Diese ID braucht man um die Privilegien des eigenen Anwendung zu ändern.
Jetzt müssen die Privilegien der eigenen Anwendung noch eingestellt werden (AdjustTokenPrivileges [http://msdn2.microsoft.com/en-us/library/aa375202.aspx]-Funktion) und schon gibts bei der Informationsabfrage der Prozesse keine Probleme mehr.

ACHTUNG: Ich habs selbst noch nicht probiert, aber durch die erhaltenen Privilegien könnte man auch wichtige Prozesse "abschießen", auf welche man sonst keinen Zugriff hat. Es könnte also möglich sein wichtige Systemprozesse zu beenden oder deren Einstellungen zu verändern (Priorität, etc...). Es sollten außerdem aus Sicherheitsgründen die Privilegien, nach den gewünschten Aktionen, immer wieder zurückgesetzt werden.

Hier nach der Theorie nun auch mal etwas Quelltext:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
{*******************************************************************************
Function: SetDebugPrivilege

@pmfunc Setzt die Privilegien des aktuellen Threads auf "Debug-Privileg",
dadurch wird der Zugriff auf Systemgeschützte Prozesse gewährt. Ist der Übergabe-
parameter = false wird dem Thread dieses Recht wieder entzogen. (<- Sicherheit)

Erstellt: BlackDragon (30.11.2007)
Geändert: BlackDragon (30.11.2007)

@rdesc True bei Erfolg.
*******************************************************************************}


function TForm1.SetDebugPrivilege(
  bEnable: Boolean  {@pparm Privileg setzen = true/ entziehen = false }
): Boolean;
var
  hToken: THandle;
const
  SE_DEBUG_NAME = 'SeDebugPrivilege';
begin
  ImpersonateSelf(SecurityImpersonation);  { den Sicherheitsrahmen "imitieren" }
  { ThreadToken öffnen }
  if OpenThreadToken(GetCurrentThread(), {aktueller Thread}
            TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, {gewünschter Zugriff}
            false,
            hToken) then
  begin
    SetPrivilege(hToken, SE_DEBUG_NAME, bEnable); {Privileg setzen bzw. nehmen}
    CloseHandle(hToken);
    Result := true;
  end else
  begin
    Result := false;
  end;
end;

{*******************************************************************************
Procedure: SetPrivilege

@pmproc Setzt das in "sPrivilege" übergebene Privileg bzw. entzieht es.

Erstellt: BlackDragon (30.11.2007)
Geändert: BlackDragon (30.11.2007)
*******************************************************************************}


procedure TForm1.SetPrivilege(
  hToken: THandle; {@pparm Handle auf ein Token }
  sPrivilege: String{@pparm Name des Privilegs }
  bEnable: Boolean {@pparm Setzen = true / entziehen = false }
);
var
  tp: TTokenPrivileges;
  tpPrev: TTokenPrivileges;
  luid: Int64;
  BufferLength: Cardinal;
  ReturnValue: Cardinal;
begin
  BufferLength := SizeOf(TTokenPrivileges);
  LookupPrivilegeValue(nil,PAnsiChar(sPrivilege),luid); { Wert der LUID anhand von sPrivilege bekommen }
  tp.PrivilegeCount := 1;
  tp.Privileges[0].Luid := luid;
  {* Privileg setzen *}
  if bEnable then
  begin
    tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
  end else
  begin
    tp.Privileges[0].Attributes := 0;
  end;
  AdjustTokenPrivileges(hToken,false,tp,BufferLength,tpPrev,ReturnValue);
end;


Ich kann jetzt jederzeit über


Delphi-Quelltext
1:
SetDebugPrivilege(true);                    


die Privilegien setzen und über


Delphi-Quelltext
1:
SetDebugPrivilege(false);                    


wieder zurücksetzen.


Was ich auch noch nicht ausprobiert habe, ob es einen Unterschied bezüglich des Holens von Informationen macht "OpenProcess(...)" mit Zugriffslevel PROCESS_ALL_ACCESS aufzurufen. Eigentlich sollte PROCESS_QUERY_INFORMATION reichen.

Ich hoffe dass ich helfen konnte und ich nix vergessen bzw. falsch wiedergegeben habe. Bin halt selber noch nicht so tief in die WinAPI und deren Auswüchse eingetaucht.

Mfg

Olli