2011. január 12., szerda

NT Native API


Problem/Question/Abstract:

NT Native API is basic API in Windows NT/2000. All other API (Win32 is included) are use this API. But functions from ntdll.dll are poorely documented.

Answer:

You can download full source code (ntdll.pas is included):
  http://homepages.mtgroup.ru/alexk/files/NativeApp.zip

Unit ntdll.pas contains only definitions for some functions and structures from NT Native API.

program NativeApp;

// PURPOSE: Simple Windows NT/2000 console application that calls
// Native API functions

{$APPTYPE CONSOLE}

uses
  Windows, SysUtils, ntdll;

type
  TEnumNtObjectCallBack = function(
    pusObjectName: PNtUnicodeString;
    ObjectTypeName: string;
    DirectoryHandle: THandle;
    UserData: Pointer
    ): Boolean; // False => stop

  //-------------------------------------------------------------

function NtUnicodeStringToString(pusString: PNtUnicodeString): string;
var
  asString: TNtAnsiString;
begin
  Result := '';
  if (pusString = nil) or (pusString^.Length = 0) then
    Exit;
  // convert with allocating
  RtlUnicodeStringToAnsiString(@asString, pusString, True);
  try
    SetString(Result, asString.Buffer, asString.Length);
  finally
    RtlFreeAnsiString(@asString); // free allocated memory
  end;
end;
//-------------------------------------------------------------
// Open any named NT object.
// If DirectoryHandle=0 then ObjectName must be full qualified name
// (start with backslash symbol),
// otherwise ObjectName specify relative path from this directory
// You must call CloseHandle to free obtained handle.

function OpenObject(ObjectName: PNtUnicodeString;
  DirectoryHandle: THandle;
  DesireAccess: ACCESS_MASK): THandle;
var
  ObjectAttributes: TNtObjectAttributes;
  IoStatus: TIoStatusBlock;
  doserr: DWORD;
  rc: NTSTATUS;
begin
  InitializeObjectAttributes(@ObjectAttributes, ObjectName,
    OBJ_CASE_INSENSITIVE, DirectoryHandle, nil);
  rc := NtOpenFile(Result, DesireAccess, ObjectAttributes, IoStatus,
    FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, 0);
  if rc <> STATUS_SUCCESS then
  begin
    doserr := RtlNtStatusToDosError(rc);
    SetLastError(doserr);
    Result := INVALID_HANDLE_VALUE;
  end;
end;
//-------------------------------------------------------------
// Open directory and call Treate function for all objects
// in this directory.

function EnumNtObjects(Path: string;
  Treate: TEnumNtObjectCallBack;
  UserData: Pointer): NTSTATUS;
const
  BufferSize = 2048;
var
  hDir: THandle;
  doserr: DWORD;
  DirObject: TNtObjectAttributes;
  asDirName: TNtAnsiString;
  usDirName: TNtUnicodeString;
  cbBytesReturned: DWORD;
  dwIndex: DWORD;
  Buffer: array[0..BufferSize - 1] of Byte;
  DirInfo: TDirectoryInformationTYpe1 absolute Buffer;
  FileNameInfo: TFileNameInformation absolute Buffer;
begin
  if not Assigned(Treate) or (Path = '') then
  begin
    Result := STATUS_INVALID_PARAMETER;
    Exit;
  end;
  RtlInitAnsiString(@asDirName, PChar(Path));
  RtlAnsiStringToUnicodeString(@usDirName, @asDirName, True);
  try
    InitializeObjectAttributes(@DirObject, @usDirName,
      OBJ_CASE_INSENSITIVE, 0, nil);
    hDir := 0;
    Result := NtOpenDirectoryObject(hDir,
      DIRECTORY_TRAVERSE or DIRECTORY_QUERY, DirObject);
    if Result <> STATUS_SUCCESS then
    begin
      doserr := RtlNtStatusToDosError(Result);
      SetLastError(doserr);
    end
    else
    try
      dwIndex := 0;
      repeat
        Result := NtQueryDirectoryObject(hDir,
          @Buffer, BufferSize,
          TDirectoryInformationClass(1), // ???
          False, dwIndex, cbBytesReturned);
        if Result <> 0 then
        begin
          if Result = STATUS_NO_MORE_DATA then
          begin
            Result := STATUS_SUCCESS;
            Break;
          end;
          doserr := RtlNtStatusToDosError(Result);
          SetLastError(doserr);
          Break;
        end;
      until not Treate(@DirInfo.ObjectName,
        NtUnicodeStringToString(@DirInfo.ObjectTypeName),
        hDir, UserData);
    finally
      CloseHandle(hDir);
    end;
  finally
    RtlFreeUnicodeString(@usDirName);
  end;
end;

//=============================================================
// Sample for EnumNtObjects callback function
type
  TUserData = record
    DesireObjectType: PChar;
    DesireAccess: ACCESS_MASK;
  end;
  PUserData = ^TUserData;

function EnumNtObjectsCallBack(pusObjectName: PNtUnicodeString;
  ObjectTypeName: string;
  DirectoryHandle: THandle;
  UserData: Pointer): Boolean;
var
  sObjectName: string;
  hObject: THandle;
begin
  Result := True;
  sObjectName := NtUnicodeStringToString(pusObjectName);
  with PUserData(UserData)^ do
    if (DesireObjectType <> '*')
      and (CompareText(ObjectTypeName, DesireObjectType) <> 0) then
      Exit;
  if (CompareText(ObjectTypeName, 'Directory') = 0)
    //NtOpenDirectoryObject
  or (CompareText(ObjectTypeName, 'Type') = 0)
    or (CompareText(ObjectTypeName, 'Port') = 0)
    or (CompareText(ObjectTypeName, 'Key') = 0) // NtOpenKey
  or (CompareText(ObjectTypeName, 'Event') = 0) // OpenEvent
  or (CompareText(ObjectTypeName, 'Semaphore') = 0) // OpenSemaphore
  or (CompareText(ObjectTypeName, 'Mutant') = 0) // OpenMutex
  or (CompareText(ObjectTypeName, 'Timer') = 0) // NtOpenTimer
  or (CompareText(ObjectTypeName, 'Section') = 0) // NtOpenSection
  or (CompareText(ObjectTypeName, 'SymbolicLink') = 0)
    {// NtOpenSymbolicLinkObject } then
  begin
    WriteLn(ObjectTypeName, ' ', sObjectName);
    Exit;
  end;
  hObject := OpenObject(pusObjectName, DirectoryHandle,
    PUserData(UserData)^.DesireAccess);
  if hObject = INVALID_HANDLE_VALUE then
  begin
    Write('  NtOpenObject failed for ', sObjectName, ': ');
    WriteLn(SysErrorMessage(GetLastError));
    Exit;
  end;
  try
    WriteLn(ObjectTypeName, ' ', sObjectName,
      ' is opened successfully');

    // do something with object here

  finally
    CloseHandle(hObject);
  end;
end;

//=============================================================
// Application

var
  sObjectType, sPath: string;
  rUserData: TUserData;
begin
  if (ParamCount = 0) or (ParamCount > 2) then
  begin
    WriteLn('(c) 20 jul 2000 Alex Konshin mailto:alexk@mtgroup.ru');
    WriteLn;
    WriteLn('Sample console application that use NT Native API.');
    WriteLn;
    WriteLn('Using:');
    WriteLn;
    WriteLn('  NativeApp ObjectType [Path]');
    WriteLn;
    WriteLn('Where:');
    WriteLn;
    WriteLn('  ObjectType = *(all objects), Directory, Type, Device, Mutant,');
    WriteLn('        Section, Semaphore,...');
    WriteLn('        (use NativeApp Type \ObjectTypes to list NT object types)');
    WriteLn;
    WriteLn('  Path = NT objects directory name.');
    WriteLn;
    WriteLn('Examples:');
    WriteLn;
    WriteLn('  NativeApp Device \Device');
    WriteLn('  NativeApp Mutant \BaseNamedObjects');
    WriteLn;
    Exit;
  end;
  sObjectType := ParamStr(1);
  sPath := ParamStr(2);
  if sPath = '' then
    sPath := '\';
  with rUserData do
  begin
    DesireObjectType := PChar(sObjectType);
    DesireAccess := FILE_READ_DATA; // GENERIC_READ or GENERIC_WRITE;
  end;
  EnumNtObjects(sPath, EnumNtObjectsCallBack, @rUserData);
end.

Links for more informations:
  http://www.sysinternals.com/ntdll.htm
  http://www.sysinternals.com/winobj.htm

Books:
  http://www.amazon.com/exec/obidos/ASIN/1578701996/systemsinternals

See also Zw*, Rtl* functions descriptions in Win2000 DDK.

Nincsenek megjegyzések:

Megjegyzés küldése