Object info from handle (Iconic help :))

c++ / delphi package - dll injection and api hooking
Post Reply
Davita
Posts: 163
Joined: Tue Sep 13, 2005 7:31 pm

Object info from handle (Iconic help :))

Post by Davita »

Hello guys :)

I need to retrieve object informatino, such as File/Process/Registry etc from a handle. Is there any way from the api to do that? without causing a big performance penalty. thanks :)
Nico Bendlin
Posts: 46
Joined: Fri Apr 28, 2006 1:17 pm

Post by Nico Bendlin »

There are several ways to optimize the query for a large amount of handles.
The following sample code retrieves the object type name for a single handle:

Code: Select all

{$ALIGN ON}
{$MINENUMSIZE 4}

type
  TNtStatus = LongInt;

type
  PNtUnicodeString = ^TNtUnicodeString;
  TNtUnicodeString = record
    Length       : Word;
    MaximumLength: Word;
    Buffer       : PWideChar;
  end;

type
  TObjectInformationClass = (
    ObjectBasicInformation,       // 0
    ObjectNameInformation,        // 1
    ObjectTypeInformation,        // 2
    ObjectTypesInformation,       // 3
    ObjectHandleFlagInformation,  // 4
    ObjectSessionInformation,     // 5
    MaxObjectInfoClass            // 6
  );

type
  PObjectBasicInformation = ^TObjectBasicInformation;
  TObjectBasicInformation = record
    Attributes            : ULONG;
    GrantedAccess         : ACCESS_MASK;
    HandleCount           : ULONG;
    PointerCount          : ULONG;
    PagedPoolCharge       : ULONG;
    NonPagedPoolCharge    : ULONG;
    Reserved              : array [0..2] of ULONG;
    NameInfoSize          : ULONG;
    TypeInfoSize          : ULONG;
    SecurityDescriptorSize: ULONG;
    CreationTime          : LARGE_INTEGER;
  end;

type
  PObjectNameInformation = ^TObjectNameInformation;
  TObjectNameInformation = record
    Name: TNtUnicodeString;
  end;

type
  PObjectTypeInformation = ^TObjectTypeInformation;
  TObjectTypeInformation = record
    TypeName                  : TNtUnicodeString;
    TotalNumberOfObjects      : ULONG;
    TotalNumberOfHandles      : ULONG;
    TotalPagedPoolUsage       : ULONG;
    TotalNonPagedPoolUsage    : ULONG;
    TotalNamePoolUsage        : ULONG;
    TotalHandleTableUsage     : ULONG;
    HighWaterNumberOfObjects  : ULONG;
    HighWaterNumberOfHandles  : ULONG;
    HighWaterPagedPoolUsage   : ULONG;
    HighWaterNonPagedPoolUsage: ULONG;
    HighWaterNamePoolUsage    : ULONG;
    HighWaterHandleTableUsage : ULONG;
    InvalidAttributes         : ULONG;
    GenericMapping            : TGenericMapping;
    ValidAccessMask           : ULONG;
    SecurityRequired          : Boolean;
    MaintainHandleCount       : Boolean;
    PoolType                  : ULONG;
    DefaultPagedPoolCharge    : ULONG;
    DefaultNonPagedPoolCharge : ULONG;
  end;

type
  TObjectTypesInformation = record
    NumberOfTypes: ULONG;
    // AlignUp(Pointer)
  { TypeInformation: TObjectTypeInformation; }
  { TypeInformation.TypeName.Buffer: array [TypeName.MaximumLength] of Byte; }
    //...
  end;

type
  PObjectHandleFlagInformation = ^TObjectHandleFlagInformation;
  TObjectHandleFlagInformation = record
    Inherit         : Boolean;  // HANDLE_FLAG_INHERIT
    ProtectFromClose: Boolean;  // HANDLE_FLAG_PROTECT_FROM_CLOSE
  end;

type
  PObjectSessionInformation = ^TObjectSessionInformation;
  TObjectSessionInformation = record
    SessionId: ULONG;
  end;

const
  NtDllLib = 'ntdll.dll';

function NtQueryObject(Handle: THandle;
  ObjectInformationClass: TObjectInformationClass; ObjectInformation: Pointer;
  ObjectInformationLength: ULONG; ReturnLength: PULONG): TNtStatus; stdcall;
  external NtDllLib;
function RtlNtStatusToDosError(Status: TNtStatus): ULONG; stdcall;
  external NtDllLib;

////////////////////////////////////////////////////////////////////////////////

function GetObjectTypeNameByHandle(AHandle: THandle): WideString;
const
  InfoLength = SizeOf(TObjectTypeInformation) + High(Word) * SizeOf(WideChar);
var
  TypeInfo: PObjectTypeInformation;
  ErrCode: DWORD;
  Status: TNtStatus;
begin
  Result := '';
  TypeInfo := VirtualAlloc(nil, InfoLength, MEM_COMMIT, PAGE_READWRITE);
  if Assigned(TypeInfo) then
  try
    Status := NtQueryObject(AHandle, ObjectTypeInformation, TypeInfo,
      InfoLength, nil);
    if Status >= 0 then
    begin
      SetLength(Result, TypeInfo.TypeName.Length div SizeOf(WideChar));
      if Length(Result) > 0 then
        Move(TypeInfo.TypeName.Buffer[0], Result[1],
          Length(Result) * SizeOf(WideChar));
    end;
    SetLastError(RtlNtStatusToDosError(Status));
  finally
    ErrCode := GetLastError();
    VirtualFree(TypeInfo, 0, MEM_RELEASE);
    SetLastError(ErrCode);
  end;
end;

////////////////////////////////////////////////////////////////////////////////

procedure TForm1.FormCreate(ASender: TObject);
var
  Process: THandle;
begin
  if DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
    GetCurrentProcess(), @Process, 0, False, 0) then
  try
    MessageBoxW(Handle, PWideChar(GetObjectTypeNameByHandle(Process)),
      'Process', MB_ICONINFORMATION);
  finally
    CloseHandle(Process);
  end;
end;
Davita
Posts: 163
Joined: Tue Sep 13, 2005 7:31 pm

Post by Davita »

Many thanks :)
I will give it a try :)
Nico Bendlin
Posts: 46
Joined: Fri Apr 28, 2006 1:17 pm

Post by Nico Bendlin »

If you want to determine the object types of many handles, you might call NtQuerySystemInformation(SystemHandleInformation) or NtQuerySystemInformation(SystemExtendedHandleInformation) and use the ObjectTypeIndex to cache the results (note: do not assume that this index is the same as in NtQueryObject(ObjectTypesInformation) - e.g. depending on the Windows version the index for the File object type is currently off by one or two).

Note: NtQuerySystemInformation(SystemHandleInformation) isn’t correctly emulated on WOW64.
Post Reply