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)…