Although the Windows NT API is not object-oriented, NT uses objects internally to provide support for certain features uniformly across a variety of different entities. Internally, files, events, mutexes, pipes, and so on, are all implemented as objects. This allows NT to perform some operations, such as security checks, in a generic fashion for different types of objects.

Diatas itu qoute from Here , and code berikut adalah sample implementasinya

here u go

function NtSuccess(AStatus: LongInt): Boolean;
begin
  Result := AStatus >= 0;
  if not result then begin
    SetLastError(RtlNtStatusToDosError(AStatus));
  end;
end;

function AddSlash(s:string): String;
begin
  Result:=s;
  if (Result[length(Result)]<>'\') then Result:=Result+'\';
end;

type
TGenericOpen = function (Handle: PHANDLE; DesiredAccess: ACCESS_MASK; ObjectAttributes: POBJECT_ATTRIBUTES): NTSTATUS; stdcall;

function GetOpenFunc(TypeName : String):TGenericOpen;
begin
  if (TypeName = 'SymbolicLink') then result := NtOpenSymbolicLinkObject
  else if (TypeName = 'Mutant') then result := NtOpenMutant
  else if (TypeName = 'Event') then result := NtOpenEvent
  else if (TypeName = 'Job') then result := NtOpenJobObject
  else if (TypeName = 'Section') then result := NtOpenSection
  else if (TypeName = 'Semaphore') then result := NtOpenSemaphore
  else if (TypeName = 'Timer') then result := NtOpenTimer
  else result := nil;
end;

function QuerySymbolLink(Handle : THandle): string;
var
info    : UNICODE_STRING;
binfo   : array[0..MAX_PATH] of widechar;
dwread  : Integer;
begin
  info.Length := 0;
  info.MaximumLength := sizeof(binfo);
  info.Buffer := binfo;
  if not NtSuccess(NtQuerySymbolicLinkObject(Handle, @info, @dwread)) then begin
    Codesite.SendWinError('NtOpenSymbolicLinkObject', GetLastError);
    exit('');
  end;
  result := info.Buffer;
end;

function QueryMutant(Handle : THandle): string;
var
  info    : MUTANT_BASIC_INFORMATION;
  dwread  : Integer;
begin
  if not NtSuccess(NtQueryMutant(Handle, MutantBasicInformation, @info, sizeof(info), @dwread)) then begin
    Codesite.SendWinError('NtQueryMutant', GetLastError);
    exit('');
  end;
  result := format('[[%d / %s / %s]',[info.SignalState, BoolToStr(info.Owned,true), BoolToStr(info.Abandoned, true)]);
end;

function QueryEvent(Handle : THandle): string;
var
  info    : EVENT_BASIC_INFORMATION;
  dwread  : Integer;
begin
  if not NtSuccess(NtQueryEvent(Handle, EventBasicInformation, @info, sizeof(info), @dwread)) then begin
    Codesite.SendWinError('NtQueryEvent', GetLastError);
    exit('');
  end;
  result := format('[[%d / %d ]',[Integer(info.EventType), info.SignalState]);
end;

function QueryJobObject(Handle : THandle): string;
var
  info    : JOBOBJECT_BASIC_ACCOUNTING_INFORMATION;
  dwread  : Integer;
begin
  if not NtSuccess(NtQueryInformationJobObject(Handle, JobObjectBasicAccountingInformation, @info, sizeof(info), @dwread)) then begin
    Codesite.SendWinError('NtQueryInformationJobObject', GetLastError);
    exit('');
  end;
  result := format('[[%d / %d / %d]',[Integer(info.TotalProcesses), info.ActiveProcesses, info.TotalTerminatedProcesses]);
end;

function OpenInfo(TypeName : String; Path : String): THandle;
var
  ItemName  : UNICODE_STRING;
  ItemObj   : OBJECT_ATTRIBUTES;
  Func      : TGenericOpen;
begin
  result := 0;
  RtlInitUnicodeString(@ItemName, PChar(Path));
  InitializeObjectAttributes(@ItemObj, @ItemName, OBJ_CASE_INSENSITIVE, 0, nil);

  Func := GetOpenFunc(TypeName);
  if not assigned(func) then exit;

  if not NtSuccess(Func(@result, GENERIC_ALL, @ItemObj)) then begin
    Codesite.SendWinError('OpenItem', GetLastError);
    exit;
  end;
end;

Procedure Enum(Path :Widestring);
var
  hDir, hItem : THandle;
  DirName     : UNICODE_STRING;
  DirObj      : OBJECT_ATTRIBUTES;
  Buffer      : Pointer;
  ctx,dwread  : Integer;
  info        : string;
begin
  Codesite.Send(csmgreen, Path);
  RtlInitUnicodeString(@DirName, PChar(Path));
  InitializeObjectAttributes(@DirObj, @DirName, OBJ_CASE_INSENSITIVE, 0, nil);

  if not NtSuccess(NtOpenDirectoryObject(@hDir, DIRECTORY_TRAVERSE or DIRECTORY_QUERY, @DirObj)) then begin
    Codesite.SendWinError('NtOpenDirectoryObject', GetLastError);
    exit;
  end;

  GetMem(Buffer,2048);
  try
    ctx := 0;
    repeat
      if not NtSuccess(NtQueryDirectoryObject(hDir, Buffer, 2048, true, false, @ctx, @dwread)) then
      begin
        break;
      end;

      with PDirectoryBasicInformation(buffer)^ do begin

        if (ObjectTypeName.Buffer = 'Directory') then Enum(AddSlash(Path) + ObjectName.Buffer )
        else if (ObjectTypeName.Buffer = 'Driver') then Codesite.Send(csmblue,' %s : %s', [ObjectTypeName.Buffer,ObjectName.Buffer])
        else begin

          hItem := OpenInfo(ObjectTypeName.Buffer,AddSlash(Path) + ObjectName.Buffer);
          if hItem=0 then continue;

          if (ObjectTypeName.Buffer = 'SymbolicLink') then info := QuerySymbolLink(hItem)
          else if (ObjectTypeName.Buffer = 'Mutant')then info := QueryMutant(hItem)
          else if (ObjectTypeName.Buffer = 'Event')then info := QueryEvent(hItem);

          if (info <> '') then Codesite.Send(csmblue,'[%s / %s] : %s',[ObjectTypeName.Buffer,ObjectName.Buffer,info])
          else Codesite.Send(csmred,' %s : %s', [ObjectTypeName.Buffer,ObjectName.Buffer]);

          ZwClose(hItem);
          info := '';
        end;
      end;


    until false;
  finally
    ZwClose(hDir);
    FreeMem(Buffer,2048);
  end;
end;

begin
  Enum('\');
end.

btw cuman 4 yang gue buatin querynya (querynya berdasarkan tipe dari object ex mutex, symbolink).. selebihnya tinggal query sendiri aja valuenya (search in jwanative unit with phrase “query” for know what function used)…

nah fungsinya apa sih dari enum object itu ? banyak sih misalnya digunaiin pada antiforensic tools, antirootkit (enum loaded driver), bahkan sampai ada malware yang gunain resultnya untuk fungsi (antiemulator / sandbox)…