#define NDEBUG
#include <internal/debug.h>
+#define UNICODE_PATH_SEP L'\\'
+#define UNICODE_NO_PATH L"..."
+#define OB_NAME_TAG TAG('O','b','N','m')
typedef struct _RETENTION_CHECK_PARAMS
{
IN KPROCESSOR_MODE AccessMode)
{
NTSTATUS Status = STATUS_SUCCESS;
+ ULONG StringLength;
+ PWCHAR StringBuffer = NULL;
UNICODE_STRING LocalName = {}; /* <= GCC 4.0 + Optimizer */
- /* First Probe the String */
- DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName);
- if (AccessMode != KernelMode)
+ /* Initialize the Input String */
+ RtlInitUnicodeString(CapturedName, NULL);
+
+ /* Protect everything */
+ _SEH_TRY
{
- DPRINT("Probing Struct\n");
- _SEH_TRY
+ /* First Probe the String */
+ DPRINT("ObpCaptureObjectName: %wZ\n", ObjectName);
+ if (AccessMode != KernelMode)
{
- /* FIXME: Explorer or win32 broken I think */
- #if 0
ProbeForRead(ObjectName,
sizeof(UNICODE_STRING),
sizeof(USHORT));
- #endif
LocalName = *ObjectName;
+
+ ProbeForRead(LocalName.Buffer,
+ LocalName.Length,
+ sizeof(WCHAR));
}
- _SEH_HANDLE
+ else
{
- Status = _SEH_GetExceptionCode();
+ /* No probing needed */
+ LocalName = *ObjectName;
}
- _SEH_END;
-
- if (NT_SUCCESS(Status))
+
+ /* Make sure there really is a string */
+ DPRINT("Probing OK\n");
+ if ((StringLength = LocalName.Length))
{
- DPRINT("Probing OK\n");
- _SEH_TRY
+ /* Check that the size is a valid WCHAR multiple */
+ if ((StringLength & (sizeof(WCHAR) - 1)) ||
+ /* Check that the NULL-termination below will work */
+ (StringLength == (MAXUSHORT - sizeof(WCHAR) + 1)))
{
- #if 0
- DPRINT("Probing buffer\n");
- ProbeForRead(LocalName.Buffer,
- LocalName.Length,
- sizeof(USHORT));
- #endif
+ /* PS: Please keep the checks above expanded for clarity */
+ DPRINT1("Invalid String Length\n");
+ Status = STATUS_OBJECT_NAME_INVALID;
}
- _SEH_HANDLE
+ else
{
- Status = _SEH_GetExceptionCode();
+ /* Allocate a non-paged buffer for this string */
+ DPRINT("Capturing String\n");
+ CapturedName->Length = StringLength;
+ CapturedName->MaximumLength = StringLength + sizeof(WCHAR);
+ if ((StringBuffer = ExAllocatePoolWithTag(NonPagedPool,
+ StringLength + sizeof(WCHAR),
+ OB_NAME_TAG)))
+ {
+ /* Copy the string and null-terminate it */
+ RtlMoveMemory(StringBuffer, LocalName.Buffer, StringLength);
+ StringBuffer[StringLength / sizeof(WCHAR)] = UNICODE_NULL;
+ CapturedName->Buffer = StringBuffer;
+ DPRINT("String Captured: %wZ\n", CapturedName);
+ }
+ else
+ {
+ /* Fail */
+ DPRINT1("Out of Memory!\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
}
- _SEH_END;
}
-
- /* Fail if anything up to here died */
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Probing failed\n");
- return Status;
- }
- }
- else
- {
- LocalName = *ObjectName;
}
-
- /* Make sure there really is a string */
- DPRINT("Probing OK\n");
- if (LocalName.Length)
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
- /* Allocate a non-paged buffer for this string */
- DPRINT("Capturing String\n");
- CapturedName->Length = LocalName.Length;
- CapturedName->MaximumLength = LocalName.Length + sizeof(WCHAR);
- CapturedName->Buffer = ExAllocatePoolWithTag(NonPagedPool,
- CapturedName->MaximumLength,
- TAG('O','b','N','m'));
-
- /* Copy the string and null-terminate it */
- RtlMoveMemory(CapturedName->Buffer, LocalName.Buffer, LocalName.Length);
- CapturedName->Buffer[LocalName.Length / sizeof(WCHAR)] = UNICODE_NULL;
- DPRINT("String Captured: %p, %wZ\n", CapturedName, CapturedName);
+ Status = _SEH_GetExceptionCode();
+
+ /* Remember to free the buffer in case of failure */
+ DPRINT1("Failed\n");
+ if (StringBuffer) ExFreePool(StringBuffer);
}
+ _SEH_END;
+ /* Return */
+ DPRINT("Returning: %lx\n", Status);
return Status;
}
DPRINT("ObpCaptureObjectAttributes\n");
RtlZeroMemory(ObjectCreateInfo, sizeof(OBJECT_CREATE_INFORMATION));
- /* Check if we got Oba */
- if (ObjectAttributes)
+ /* SEH everything here for protection */
+ _SEH_TRY
{
- if (AccessMode != KernelMode)
+ /* Check if we got Oba */
+ if (ObjectAttributes)
{
- DPRINT("Probing OBA\n");
- _SEH_TRY
+ if (AccessMode != KernelMode)
{
- /* FIXME: SMSS SENDS BULLSHIT. */
- #if 0
+ DPRINT("Probing OBA\n");
ProbeForRead(ObjectAttributes,
- sizeof(ObjectAttributes),
+ sizeof(OBJECT_ATTRIBUTES),
sizeof(ULONG));
- #endif
}
- _SEH_HANDLE
+
+ /* Validate the Size and Attributes */
+ DPRINT("Validating OBA\n");
+ if ((ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES)) ||
+ (ObjectAttributes->Attributes & ~OBJ_VALID_ATTRIBUTES))
{
- Status = _SEH_GetExceptionCode();
+ Status = STATUS_INVALID_PARAMETER;
+ DPRINT1("Invalid Size: %lx or Attributes: %lx\n",
+ ObjectAttributes->Length, ObjectAttributes->Attributes);
+ _SEH_LEAVE;
}
- _SEH_END;
- }
-
- /* Validate the Size */
- DPRINT("Validating OBA\n");
- if (ObjectAttributes->Length != sizeof(OBJECT_ATTRIBUTES))
- {
- Status = STATUS_INVALID_PARAMETER;
- }
-
- /* Fail if SEH or Size Validation failed */
- if(!NT_SUCCESS(Status))
- {
- DPRINT1("ObpCaptureObjectAttributes failed to probe object attributes\n");
- goto fail;
- }
- /* Set some Create Info */
- DPRINT("Creating OBCI\n");
- ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
- ObjectCreateInfo->Attributes = ObjectAttributes->Attributes;
- LocalObjectName = ObjectAttributes->ObjectName;
- SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
- SecurityQos = ObjectAttributes->SecurityQualityOfService;
+ /* Set some Create Info */
+ DPRINT("Creating OBCI\n");
+ ObjectCreateInfo->RootDirectory = ObjectAttributes->RootDirectory;
+ ObjectCreateInfo->Attributes = ObjectAttributes->Attributes;
+ LocalObjectName = ObjectAttributes->ObjectName;
+ SecurityDescriptor = ObjectAttributes->SecurityDescriptor;
+ SecurityQos = ObjectAttributes->SecurityQualityOfService;
- /* Validate the SD */
- if (SecurityDescriptor)
- {
- DPRINT("Probing SD: %x\n", SecurityDescriptor);
- Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
- AccessMode,
- NonPagedPool,
- TRUE,
- &ObjectCreateInfo->SecurityDescriptor);
- if(!NT_SUCCESS(Status))
+ /* Validate the SD */
+ if (SecurityDescriptor)
{
- DPRINT1("Unable to capture the security descriptor!!!\n");
- ObjectCreateInfo->SecurityDescriptor = NULL;
- goto fail;
- }
+ DPRINT("Probing SD: %x\n", SecurityDescriptor);
+ Status = SeCaptureSecurityDescriptor(SecurityDescriptor,
+ AccessMode,
+ NonPagedPool,
+ TRUE,
+ &ObjectCreateInfo->SecurityDescriptor);
+ if(!NT_SUCCESS(Status))
+ {
+ DPRINT1("Unable to capture the security descriptor!!!\n");
+ ObjectCreateInfo->SecurityDescriptor = NULL;
+ _SEH_LEAVE;
+ }
- DPRINT("Probe done\n");
- ObjectCreateInfo->SecurityDescriptorCharge = 0; /* FIXME */
- ObjectCreateInfo->ProbeMode = AccessMode;
- }
+ DPRINT("Probe done\n");
+ ObjectCreateInfo->SecurityDescriptorCharge = 2048; /* FIXME */
+ ObjectCreateInfo->ProbeMode = AccessMode;
+ }
- /* Validate the QoS */
- if (SecurityQos)
- {
- if (AccessMode != KernelMode)
+ /* Validate the QoS */
+ if (SecurityQos)
{
- DPRINT("Probing QoS\n");
- _SEH_TRY
+ if (AccessMode != KernelMode)
{
+ DPRINT("Probing QoS\n");
ProbeForRead(SecurityQos,
sizeof(SECURITY_QUALITY_OF_SERVICE),
sizeof(ULONG));
}
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
-
- if(!NT_SUCCESS(Status))
- {
- DPRINT1("Unable to capture QoS!!!\n");
- goto fail;
- }
- ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
- ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService;
+ /* Save Info */
+ ObjectCreateInfo->SecurityQualityOfService = *SecurityQos;
+ ObjectCreateInfo->SecurityQos = &ObjectCreateInfo->SecurityQualityOfService;
+ }
+ }
+ else
+ {
+ LocalObjectName = NULL;
}
}
-
- /* Clear Local Object Name */
- DPRINT("Clearing name\n");
- RtlZeroMemory(ObjectName, sizeof(UNICODE_STRING));
-
- /* Now check if the Object Attributes had an Object Name */
- if (LocalObjectName)
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
{
- DPRINT("Name Buffer: %x\n", LocalObjectName->Buffer);
- Status = ObpCaptureObjectName(ObjectName,
- LocalObjectName,
- AccessMode);
+ Status = _SEH_GetExceptionCode();
+ DPRINT1("Failed\n");
}
- else
+ _SEH_END;
+
+ if (NT_SUCCESS(Status))
{
- /* He can't have specified a Root Directory */
- if (ObjectCreateInfo->RootDirectory)
+ /* Now check if the Object Attributes had an Object Name */
+ if (LocalObjectName)
{
- DPRINT1("Invalid name\n");
- Status = STATUS_OBJECT_NAME_INVALID;
+ DPRINT("Name Buffer: %wZ\n", LocalObjectName);
+ Status = ObpCaptureObjectName(ObjectName,
+ LocalObjectName,
+ AccessMode);
+ }
+ else
+ {
+ /* Clear the string */
+ RtlInitUnicodeString(ObjectName, NULL);
+
+ /* He can't have specified a Root Directory */
+ if (ObjectCreateInfo->RootDirectory)
+ {
+ DPRINT1("Invalid name\n");
+ Status = STATUS_OBJECT_NAME_INVALID;
+ }
}
}
-
-fail:
- if (!NT_SUCCESS(Status))
+ else
{
DPRINT1("Failed to capture, cleaning up\n");
ObpReleaseCapturedAttributes(ObjectCreateInfo);
}
- DPRINT("Return to caller\n");
+ DPRINT("Return to caller %x\n", Status);
return Status;
}
* RETURN VALUE
*/
NTSTATUS
+NTAPI
ObFindObject(POBJECT_CREATE_INFORMATION ObjectCreateInfo,
PUNICODE_STRING ObjectName,
PVOID* ReturnedObject,
*
* @implemented
*/
-NTSTATUS STDCALL
-ObQueryNameString (IN PVOID Object,
- OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
- IN ULONG Length,
- OUT PULONG ReturnLength)
+NTSTATUS
+STDCALL
+ObQueryNameString(IN PVOID Object,
+ OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+ IN ULONG Length,
+ OUT PULONG ReturnLength)
{
- POBJECT_NAME_INFORMATION LocalInfo;
- POBJECT_HEADER ObjectHeader;
- ULONG LocalReturnLength;
- NTSTATUS Status;
-
- PAGED_CODE();
+ POBJECT_HEADER_NAME_INFO LocalInfo;
+ POBJECT_HEADER ObjectHeader;
+ PDIRECTORY_OBJECT ParentDirectory;
+ ULONG NameSize;
+ PWCH ObjectName;
+ NTSTATUS Status;
- *ReturnLength = 0;
+ DPRINT("ObQueryNameString: %x, %x\n", Object, ObjectNameInfo);
- if (Length < sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR))
- return STATUS_INVALID_BUFFER_SIZE;
+ /* Get the Kernel Meta-Structures */
+ ObjectHeader = BODY_TO_HEADER(Object);
+ LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader);
- ObjectNameInfo->Name.MaximumLength = (USHORT)(Length - sizeof(OBJECT_NAME_INFORMATION));
- ObjectNameInfo->Name.Length = 0;
- ObjectNameInfo->Name.Buffer =
- (PWCHAR)((ULONG_PTR)ObjectNameInfo + sizeof(OBJECT_NAME_INFORMATION));
- ObjectNameInfo->Name.Buffer[0] = 0;
+ /* Check if a Query Name Procedure is available */
+ if (ObjectHeader->Type->TypeInfo.QueryNameProcedure)
+ {
+ /* Call the procedure */
+ DPRINT("Calling Object's Procedure\n");
+ Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure(Object,
+ ObjectNameInfo,
+ Length,
+ ReturnLength);
- ObjectHeader = BODY_TO_HEADER(Object);
+ /* Return the status */
+ return Status;
+ }
- if (ObjectHeader->Type != NULL &&
- ObjectHeader->Type->TypeInfo.QueryNameProcedure != NULL)
+ /* Check if the object doesn't even have a name */
+ if (!LocalInfo || !LocalInfo->Name.Buffer)
{
- DPRINT ("Calling %x\n", ObjectHeader->Type->TypeInfo.QueryNameProcedure);
- Status = ObjectHeader->Type->TypeInfo.QueryNameProcedure (Object,
- ObjectNameInfo,
- Length,
- ReturnLength);
+ /* We're returning the name structure */
+ DPRINT("Nameless Object\n");
+ *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
+
+ /* Check if we were given enough space */
+ if (*ReturnLength > Length)
+ {
+ DPRINT1("Not enough buffer space\n");
+ return STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ /* Return an empty buffer */
+ ObjectNameInfo->Name.Length = 0;
+ ObjectNameInfo->Name.MaximumLength = 0;
+ ObjectNameInfo->Name.Buffer = NULL;
+
+ return STATUS_SUCCESS;
}
- else if (HEADER_TO_OBJECT_NAME(ObjectHeader)->Name.Length > 0 && HEADER_TO_OBJECT_NAME(ObjectHeader)->Name.Buffer != NULL)
+
+ /*
+ * Find the size needed for the name. We won't do
+ * this during the Name Creation loop because we want
+ * to let the caller know that the buffer isn't big
+ * enough right at the beginning, not work our way through
+ * and find out at the end
+ */
+ if (Object == NameSpaceRoot)
+ {
+ /* Size of the '\' string */
+ DPRINT("Object is Root\n");
+ NameSize = sizeof(UNICODE_PATH_SEP);
+ }
+ else
{
- DPRINT ("Object does not have a 'QueryName' function\n");
+ /* Get the Object Directory and add name of Object */
+ ParentDirectory = LocalInfo->Directory;
+ NameSize = sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
- if (HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory == NameSpaceRoot)
- {
- DPRINT ("Reached the root directory\n");
- ObjectNameInfo->Name.Length = 0;
- ObjectNameInfo->Name.Buffer[0] = 0;
- Status = STATUS_SUCCESS;
- }
- else if (HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory != NULL)
- {
- LocalInfo = ExAllocatePool (NonPagedPool,
- sizeof(OBJECT_NAME_INFORMATION) +
- MAX_PATH * sizeof(WCHAR));
- if (LocalInfo == NULL)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- Status = ObQueryNameString (HEADER_TO_OBJECT_NAME(ObjectHeader)->Directory,
- LocalInfo,
- MAX_PATH * sizeof(WCHAR),
- &LocalReturnLength);
- if (!NT_SUCCESS (Status))
- {
- ExFreePool (LocalInfo);
- return Status;
- }
-
- Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
- &LocalInfo->Name);
-
- ExFreePool (LocalInfo);
-
- if (!NT_SUCCESS (Status))
- return Status;
- }
+ /* Loop inside the directory to get the top-most one (meaning root) */
+ while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
+ {
+ /* Get the Name Information */
+ LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
- DPRINT ("Object path %wZ\n", &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name);
- Status = RtlAppendUnicodeToString (&ObjectNameInfo->Name,
- L"\\");
- if (!NT_SUCCESS (Status))
- return Status;
+ /* Add the size of the Directory Name */
+ if (LocalInfo && LocalInfo->Directory)
+ {
+ /* Size of the '\' string + Directory Name */
+ NameSize += sizeof(UNICODE_PATH_SEP) + LocalInfo->Name.Length;
- Status = RtlAppendUnicodeStringToString (&ObjectNameInfo->Name,
- &HEADER_TO_OBJECT_NAME(ObjectHeader)->Name);
+ /* Move to next parent Directory */
+ ParentDirectory = LocalInfo->Directory;
+ }
+ else
+ {
+ /* Directory with no name. We append "...\" */
+ DPRINT("Nameless Directory\n");
+ NameSize += sizeof(UNICODE_NO_PATH) + sizeof(UNICODE_PATH_SEP);
+ break;
+ }
+ }
}
- else
- {
- DPRINT ("Object is unnamed\n");
- ObjectNameInfo->Name.MaximumLength = 0;
- ObjectNameInfo->Name.Length = 0;
- ObjectNameInfo->Name.Buffer = NULL;
+ /* Finally, add the name of the structure and the null char */
+ *ReturnLength = NameSize + sizeof(OBJECT_NAME_INFORMATION) + sizeof(UNICODE_NULL);
+ DPRINT("Final Length: %x\n", *ReturnLength);
- Status = STATUS_SUCCESS;
+ /* Check if we were given enough space */
+ if (*ReturnLength > Length)
+ {
+ DPRINT1("Not enough buffer space\n");
+ return STATUS_INFO_LENGTH_MISMATCH;
}
- if (NT_SUCCESS (Status))
+ /*
+ * Now we will actually create the name. We work backwards because
+ * it's easier to start off from the Name we have and walk up the
+ * parent directories. We use the same logic as Name Length calculation.
+ */
+ LocalInfo = HEADER_TO_OBJECT_NAME(ObjectHeader);
+ ObjectName = (PWCH)((ULONG_PTR)ObjectNameInfo + *ReturnLength);
+ *--ObjectName = UNICODE_NULL;
+
+ if (Object == NameSpaceRoot)
+ {
+ /* This is already the Root Directory, return "\\" */
+ DPRINT("Returning Root Dir\n");
+ *--ObjectName = UNICODE_PATH_SEP;
+ ObjectNameInfo->Name.Length = (USHORT)NameSize;
+ ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
+ ObjectNameInfo->Name.Buffer = ObjectName;
+
+ return STATUS_SUCCESS;
+ }
+ else
{
- ObjectNameInfo->Name.MaximumLength =
- (ObjectNameInfo->Name.Length) ? ObjectNameInfo->Name.Length + sizeof(WCHAR) : 0;
- *ReturnLength =
- sizeof(OBJECT_NAME_INFORMATION) + ObjectNameInfo->Name.MaximumLength;
- DPRINT ("Returned object path: %wZ\n", &ObjectNameInfo->Name);
+ /* Start by adding the Object's Name */
+ ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
+ RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
+
+ /* Now parse the Parent directories until we reach the top */
+ ParentDirectory = LocalInfo->Directory;
+ while ((ParentDirectory != NameSpaceRoot) && (ParentDirectory))
+ {
+ /* Get the name information */
+ LocalInfo = HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ParentDirectory));
+
+ /* Add the "\" */
+ *(--ObjectName) = UNICODE_PATH_SEP;
+
+ /* Add the Parent Directory's Name */
+ if (LocalInfo && LocalInfo->Name.Buffer)
+ {
+ /* Add the name */
+ ObjectName = (PWCH)((ULONG_PTR)ObjectName - LocalInfo->Name.Length);
+ RtlMoveMemory(ObjectName, LocalInfo->Name.Buffer, LocalInfo->Name.Length);
+
+ /* Move to next parent */
+ ParentDirectory = LocalInfo->Directory;
+ }
+ else
+ {
+ /* Directory without a name, we add "..." */
+ DPRINT("Nameless Directory\n");
+ ObjectName -= sizeof(UNICODE_NO_PATH);
+ ObjectName = UNICODE_NO_PATH;
+ break;
+ }
+ }
+
+ /* Add Root Directory Name */
+ *(--ObjectName) = UNICODE_PATH_SEP;
+ DPRINT("Current Buffer: %S\n", ObjectName);
+ ObjectNameInfo->Name.Length = (USHORT)NameSize;
+ ObjectNameInfo->Name.MaximumLength = (USHORT)(NameSize + sizeof(UNICODE_NULL));
+ ObjectNameInfo->Name.Buffer = ObjectName;
+ DPRINT("Complete: %wZ\n", ObjectNameInfo);
}
- return Status;
+ return STATUS_SUCCESS;
}
NTSTATUS
/* Capture all the info */
DPRINT("Capturing Create Info\n");
Status = ObpCaptureObjectAttributes(ObjectAttributes,
- AccessMode,
+ ObjectAttributesAccessMode,
Type,
ObjectCreateInfo,
&ObjectName);
DPRINT("Failed %p (type was %x %wZ) should be %x %wZ\n",
Header,
Header->Type,
- &BODY_TO_HEADER(Header->Type)->NameInfo,
+ &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(Header->Type))->Name,
ObjectType,
- &BODY_TO_HEADER(ObjectType)->NameInfo);
+ &HEADER_TO_OBJECT_NAME(BODY_TO_HEADER(ObjectType))->Name);
return(STATUS_UNSUCCESSFUL);
}
if (Header->Type == PsProcessType)
* @implemented
*/
NTSTATUS STDCALL
-ObOpenObjectByPointer(IN POBJECT Object,
+ObOpenObjectByPointer(IN PVOID Object,
IN ULONG HandleAttributes,
IN PACCESS_STATE PassedAccessState,
IN ACCESS_MASK DesiredAccess,
* Reference count.
*/
ULONG
+NTAPI
ObGetObjectHandleCount(PVOID Object)
{
POBJECT_HEADER Header;