Programmieren mit C++

Visual C++

Systemnahe Lösungen mit VC++

Prozeß-Besitzer ermitteln

Wie kann man den Besitzer eines Prozesses unter Windows NT ermitteln?

Frage

Eine Funktion, die ein direktes Verhältnis zwischen Prozessen unter Win32 liefert, sucht man in der NT-Dokumentation vergebens, obwohl es in den NT DDK Header-Files rund 25 undokumentierte API-Funktionen gibt, die in der einen oder anderen Situation nützlich sein können. Die Funktion, die nachfolgend für einen Lösungsvorschlag verwendet wird, ist NtQueryInformationProcess() und wie folgt deklariert:

Lösung

NTSTATUS NtQueryInformationProcess(
 IN HANDLE ProcessHandle,
 IN PROCESSINFOCLASS ProcessInformationClass,
 OUT PVOID ProcessInformation,
 IN ULONG ProcessInformationLength,
 OUT PULONG ReturnLength OPTIONAL);

Wird in ProcessInformationClass der Wert ProcessBasicInformation sowie in ProcessHandle ein gültiges Handle auf einen Prozeß übergeben, füllt NtQueryInformationProcess() eine PROCESS_BASIC_INFORMATION-Struktur aus, deren Adresse im Parameter ProcessInformation steht. Im Member InheritedFromUniqueProcessId der PROCESS_BASIC_INFORMATION-Struktur ist nach einem erfolgreichen Aufruf die ID des Prozesses eingetragen, der den durch ProcessHandle spezifizierten Prozeß erzeugt hat.

Um die Prozeß-ID des besitzenden Prozesses zu ermitteln, muß man nur einen Zeiger auf die Funktion NtQueryInformationProcess() erzeugen und diese Funktion mit den korrekten Parametern aufrufen. Als Hülle dafür wird folgend die Service-Funktion GetParentProcessID() implementiert, die als Parameter die ID des vorgegebenen Prozesses erwartet und zu diesem die ID des besitzenden Prozesses als Funktionsergebnis returniert bzw. im Fehlerfall den Wert 0xffffffff.

DWORD GetParentProcessID(DWORD   dwPID)
{
  NTSTATUS                     ntStatus;
  DWORD                        dwParentPID =0xffffffff;
  HANDLE                       hProcess;
  PROCESS_BASIC_INFORMATION    pbi;
  ULONG                        ulRetLen;

Den Einsprungpunkt für die Funktion NtQueryInformationProcess() erzeugt das Makro CREATE_DYNFUNC_5(), auf das weiter unten eingegangen wird.

  CREATE_DYNFUNC_5(NtQueryInformationProcess,
                   NtQueryInformationProcess,
                   ntdll,
                   NTSTATUS,
                   __stdcall,
                   HANDLE,
                   PROCESSINFOCLASS,
                   PVOID,
                   ULONG,
                   PULONG);

Das Handle des Prozesses liefert:

  hProcess    =   OpenProcess(PROCESS_QUERY_INFORMATION,
                              FALSE, dwPID);

Da dieser Aufruf fehlschlagen kann, wenn ein ungültiges Prozeßhandle in dwPID übergeben wird oder aber nicht ausreichende Zugriffsrechte vorliegen, ist das Handle zu verifizieren, bevor darauf zurückgegriffen werden darf.

  if (!hProcess)
    return 0xffffffff;

Über den zuvor per Makro erzeugten Einsprungpunkt können jetzt die Informationen ermittelt werden.

  ntStatus = NtQueryInformationProcess(
      hProcess,
      ProcessBasicInformation,
      (void*) &pbi,
      sizeof(PROCESS_BASIC_INFORMATION),
      &ulRetLen);

Im Erfolgsfall wird die ID des Erzeugers kopiert...

  if (!ntStatus)
    dwParentPID =   pbi.InheritedFromUniqueProcessId;

...der Prozeß geschlossen...

  CloseHandle(hProcess);

...und das Ergebnis returniert.

  return dwParentPID;
}

Der auf den ersten Blick vielleicht etwas ungewohnte Codeblock ist der Aufruf der Funktion CREATE_DYNFUNC_5(), die de facto ein Makro ist, mit dessen Hilfe das Definieren und laden einer Funktion mit den richtigen Typendeklarationen leichter vonstatten geht. Das Anhängsel „_5“ zeigt an, daß die Funktion 5 Parameter übernehmen soll, deren Typen in den Parametern ab Index 5 spezifiziert sind.

In den ersten drei Parametern werden der Name des neuen Zeigers sowie der Name der Funktion in der externen Bibliothek sowie der Name der Bibliothek, die üblicherweise eine DLL ist, selbst übergeben.

Das Makro ist wie folgt definiert:

#define DYNLOADED_FPTR( ptrname, procname, dllname)\
 FPTR_##procname ptrname = \
  ( FPTR_##procname ) GetProcAddress ( GetModuleHandle (\
   _TEXT( #dllname)), #procname);
 
#define CREATE_DYNFUNC_5( ptrname, procname, dllname, rettype, \
 callconv, a1, a2, a3, a4, a5)\
  typedef  rettype (callconv *FPTR_##procname) (a1,a2,a3,a4,a5);\
   DYNLOADED_FPTR( ptrname, procname, dllname);

Im oben gezeigten Beispiel expandiert das Makro zu:

Funktion NtQuery-InformationProcess

typedef NTSTATUS (__stdcall *FPTR_NtQueryInformationProcess) (
  HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);   FPTR_NtQueryInformationProcess NtQueryInformationProcess = (FPTR_NtQueryInformationProcess ) GetProcAddress ( GetModuleHandleA ( "ntdll"), "NtQueryInformationProcess");

Dieser Aufruf kann fehlschlagen, wenn die DLL zum Zeitpunkt der Codeausführung nicht geladen ist. Allerdings wird NTDLL.DLL für jeden Prozeß, der auf NT läuft, geladen, so daß dies hier im gezeigten Beispiel nicht weiter geprüft wurde.





Sachgebiet


© 2009-2012 by Alojado Publishing. Alle Rechte vorbehalten. Ausgewiesene Marken gehören ihren jeweiligen Eigentümern.
Mit der Benutzung dieser Seite erkennen Sie die Nutzungsbedingungen und die Datenschutzerklärung an. Der Betreiber übernimmt keine Haftung für den Inhalt verlinkter externer Internetseiten.
Seite erzeugt 2012-05-20 03:00:34 von textarchiv.alojado.de