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;
}