![]() |
Handle in Objektnamen konvertieren
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich möchte an dieser Stelle auf ein Problem eingehen, das in dieser oder einer ähnlichen Form meiner Ansicht nach zu den mit häufigsten Fragen in diversen Foren zählt: Wie bekomme ich den Dateinamen aus einem dazugehörigen Dateihandle? Bzw. anders: Wie kann ich den Namen des Objektes ermitteln, auf das ein Handle verweist? Obwohl die Problemstellung trivial klingt, ist sie im Usermode allein nicht sauber zu lösen. Es existiert zwar mit ![]() ![]() Aus diesem Grunde stelle ich hier eine Kernel Mode Lösung vor, die mit Hilfe von ![]() ![]() ![]() Das Herzstück stellt dabei ein kleiner Treiber dar (h2on.sys -> Handle To Object Name). Der vollständige Code des Treibers kann dem Attachment entnommen werden. Ebenfalls enthalten sind 2 vorkompilierte Treiber die mit dem XP x86 DDK (builds\x86) bzw. dem Windows 2003 x64 DDK (builds\x64) compiliert wurden. Um den x64 Treiber aber effektiv nutzen zu können, ist der Besitz eines Code Signing Zertifikats notwendig. Der Treiber ist übrigens in der Lage auf x64 Systemen sowohl Handles von 32bit als auch von 64bit Prozessen aufzulösen. Ebenfalls steht die Auflösung sowohl für 32bit als auch für 64bit Prozesse zur Verfügung. Der Treiber ist also vollständig bitdepth agnostic. Nachfolgend die Kernel Mode Routine, die das übergebene Handle hObject des Prozesses ulProcessID in den dazugehörigen Objektnamen auflöst inkl. einiger Erklärungen:
Code:
Nun ist die Kernel Mode Implementierung natürlich nur eine Hälfte der Medallie. Irgendwie möchte man als Programmierer jetzt natürlich auch auf den Treiber zugreifen um seine Handles aufzulösen. Entsprechend kommt der Treiber kombiniert mit einer kleinen Interface Unit (include\h2on.pas), die die Treiber Funktionalität in eine simple API kapselt:
NTSTATUS
H2ONGetObjectNameFromHandle ( __in_opt ULONG ulProcessId, __in HANDLE hObject, __inout_opt PWCHAR objName, __in ULONG ulBuffSize, __out PULONG pulBuffSizeRequired ) { NTSTATUS ntStatus = STATUS_SUCCESS; PEPROCESS pProcess = NULL; KAPC_STATE apcState = {0,}; BOOLEAN bAttached = FALSE; HANDLE hProcessId = 0; PVOID pObject = NULL; ULONG ulInfoBuffSize = 0; ULONG ulInfoBuffSizeReq = 0; POBJECT_NAME_INFORMATION pNameInfo = NULL; if (!hObject) { return STATUS_INVALID_PARAMETER_2; } if (!pulBuffSizeRequired) { return STATUS_INVALID_PARAMETER_5; } *pulBuffSizeRequired = 0; if (ulProcessId) { /* Der Caller hat eine Process ID angegeben. Aus diesem Grunde müssen wir uns den entsprechenden EPROCESS Pointer besorgen. */ /* * Microsoft hat einer etwas merkwürdige Art mit Process IDs umzugehen. Sie möchten sie zwar grundsätzlich als HANDLE übergeben * haben, liefern sie aber stets als ULONG zurück. Um uns hässliche Casts zu ersparen, erstellen wir lieber eine temporäre Variable * die die Process ID als HANDLE speichert. */ *((PULONG)(&hProcessId)) = ulProcessId; ntStatus = PsLookupProcessByProcessId (hProcessId, &pProcess); if (!NT_SUCCESS (ntStatus)) { goto cleanup; } } else { pProcess = PsGetCurrentProcess (); } /* Wir müssen uns nur mit der übergebenen Prozess ID verbinden, wenn dies nicht bereits unser aktueller Prozess ist. */ if (PsGetCurrentProcess () != pProcess) { /* * Und da wir in diesem Fall kein Handle unseres eigenen Prozesses auflösen wollen, verbinden wir uns mit dem * gewünschten Prozess um unsere Magie wirken zu lassen :). */ KeStackAttachProcess (pProcess, &apcState); bAttached = TRUE; } /* * Jetzt, da wir uns im korrekten Prozesskontext befinden, können wir das Handle endlich auflösen und holen uns eine * Referenz zum gewünschten Objekt. */ ntStatus = ObReferenceObjectByHandle (hObject, 0, NULL, KernelMode, &pObject, NULL); if (!NT_SUCCESS (ntStatus)) { goto cleanup; } /* * Da wir nicht genau wissen wie lang der ObjectName sein wird, raten wir einfach und erstellen vorerst einen Buffer * unserer Standardgröße. */ ulInfoBuffSize = H2ON_DEFAULT_BUFF_SIZE; do { pNameInfo = ExAllocatePoolWithTag (PagedPool, ulInfoBuffSize, H2ON_TAG); if (!pNameInfo) { /* Speicher ist aus wie es scheint, in dem Fall gibts einen entsprechenden Fehlercode zurück und es wird aufgeräumt. */ ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } /* Jetzt versuchen wir uns den Namen des referenzierten Objects zu holen */ ntStatus = ObQueryNameString (pObject, pNameInfo, ulInfoBuffSize, &ulInfoBuffSizeReq); if (ntStatus == STATUS_INFO_LENGTH_MISMATCH) { /* Falls unser Buffer zu klein war, geben wir den alten Buffer frei und setzen die korrekte Größe für den Buffer. */ ExFreePoolWithTag (pNameInfo, H2ON_TAG); pNameInfo = NULL; ulInfoBuffSize = ulInfoBuffSizeReq; } /* Und das Ganze wird wiederholt, bis die Größe passt :) */ } while (STATUS_INFO_LENGTH_MISMATCH == ntStatus); /* Eine kleine Überprüfung des Rückgabewerts von ObQueryNameString bringt Gewissheit, das wir den korrekten Namen jetzt haben. */ if (!NT_SUCCESS (ntStatus)) { goto cleanup; } /* Also gehts los damit den Namen in den Usermode zu schaffen ... zuerst mal schauen ob da genug Platz ist. */ if ((pNameInfo->Name.Length + sizeof (WCHAR)) > ulBuffSize) { /* Was in diesem Falle leider nicht der Fall ist. Fehler ausspucken und aufräumen. */ ntStatus = STATUS_BUFFER_TOO_SMALL; *pulBuffSizeRequired = pNameInfo->Name.Length; goto cleanup; } else { /* Ist in diesem Falle vorhanden, sehr schön. Also wird rüberkopiert. */ if (objName) { RtlCopyMemory (objName, pNameInfo->Name.Buffer, pNameInfo->Name.Length); RtlCopyMemory (((PUCHAR)objName) + pNameInfo->Name.Length, L"", sizeof (WCHAR)); } } /* Und zu guter letzt wird aufgeräumt ... */ cleanup: if (pNameInfo) { ExFreePoolWithTag (pNameInfo, H2ON_TAG); } if (pObject) { ObDereferenceObject (pObject); } if (bAttached) { KeUnstackDetachProcess (&apcState); } if (pProcess && ulProcessId) { ObDereferenceObject (pProcess); } return ntStatus; }
Delphi-Quellcode:
Dazu gesellen sich 2 Helferfunktionen um den Treiber im System zu installieren bzw. zu deinstallieren:
function GetObjectNameFromHandle(dwProcessId: DWORD; hObject: THandle;
objName: PWideChar; dwBuffSize: DWORD; pdwBuffSizeRequired: PDWORD): DWORD; { dwProcessId: Die Prozess ID des Prozesses dem das aufzulösende Handle gehört. Kann Null sein, wenn ein Handle des eigenen Prozesses aufgelöst werden soll. hObject: Das eigentliche Handle. objName: Ein Pointer auf einen Buffer, der den aufgelösten Objektnamen erhält. dwBuffSize: Die Größe des mit objName übergebenen Buffers in Bytes. pdwBuffSizeRequired: Pointer auf ein DWORD, daß die Größe des Objektnamen zurückliefert, falls der mit objName übergebene Buffer zu klein sein sollte. Rückgabewert: Falls die Operation erfolgreich gewesen sein sollte, wird ERROR_SUCCESS zurück geliefert. Ansonsten ein entsprechender Fehlercode. }
Delphi-Quellcode:
Beide Funktionen liefern einen Boolean Wert zurück, der angibt ob der Treiber korrekt installiert und gestartet bzw. gestoppt und deinstalliert wurde.
function InstallAndStartDriver(): Boolean;
function UninstallAndStopDriver(): Boolean; |
DP-Maintenance
Dieses Thema wurde von "Daniel G" von "Neuen Beitrag zur Code-Library hinzufügen" nach "Tutorials und Kurse" verschoben.
Aufgrund des Umfangs eher für die Tutorial-Sparte geeignet als für die Code-Lib. |
Re: Handle in Objektnamen konvertieren
Zugegeben: Ich kenne mich nicht mit Treiber-Entwicklung aus. Mir kommt dieser Code jedoch wie eine einzige Sicherheitslücke vor.
|
Re: Handle in Objektnamen konvertieren
Zitat:
- dieses dann (teilweise) in den Arbeitsspeicher mappen - ![]() einzige Mankos: - man braucht die nötigen Rechte um eine MMF damit erstellen zu können (sollten aber meißtens vorhanden sein) - die Datei muß mindestens 1 Byte groß sein, da man ja etwas benötigt, um es in den Speicher mappen zu können |
Re: Handle in Objektnamen konvertieren
Zitat:
![]() Zitat:
Davon Abgesehen funktioniert Deine Methode explizit nur mit Dateihandles. Die hier vorgestellte Methode allerdings grundsätzlich mit allen Handles. Das Beispiel mit den Dateihandles ist nur die häufigste Anwendung. Prinzipiell kannst Du auch Handles zu Mutexes oder Events zu Namen auflösen oder aber Registry Handles z.B.. Zitat:
|
Re: Handle in Objektnamen konvertieren
Zitat:
aber ich bin mir sicher, daß es auch mit GetModuleFileName ging ... nja, wäre wohl auch irgendwie etwas logisch, da Beide irgendwie die Adresse, bzw. den Namen, von in den Speicher gemappten Dateien liefern. GetModulaName will zwar 'nen Handle, aber dieses stimmt rein zufällig mit der Speicheradresse überein :roll: Zitat:
Zitat:
Nja, es war aber auch nur als Beispiel dafür, daß man nicht immer gleich mit Kanonen (Treibern) auf Spatzen (Dateihandles) schießen muß und es auch manchmal ganz einfach geht. |
Re: Handle in Objektnamen konvertieren
Zitat:
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:40 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz