Unit DriverCommands;

{
  Tento soubor zajistuje funkce pro praci s ovladacem obinit.sys.
  Jedna se o instalaci a odinstalaci jeho sluzby, nacitani a uvolneni
  do/z prostoru jadra a sbirani jednotlivych udalostia ziskavani
  ruznych informaci o jejich obsahu.
}

Interface

Uses
  Windows, Driver;


Type
  // Typ operace, jejiz data udalost obsahuje
  TObjectOperationType = (ootUnknown, ootCreateHandle, ootOpenHandle, ootDuplicateHandle, ootInheritHandle, ootCloseHandle, ootOkayToClose, ootDelete);
  // Puvod nove vznikhleho handle
  TOpenReason = (orCreateHandle, orOpenHandle, orDuplicateHandle, orInheritHandle);
  // Ttyp udalosti
  TEventType = (etUnknown, etOpen, etClose, etOkayToClose, etDelete);
  // Puvod operace (rezim jadra, uzivatelsky rezim)
  TAccessMode = (amUknown, amKernel, amUser);

  // Definice informaci spolecnych pro kazdou udalost
  _UM_EVENT = Record
    EventType : TEventType;
    EventSize : DWORD;
    Time : LARGE_INTEGER;
    end;
  UM_EVENT = _UM_EVENT;
  PUM_EVENT = ^UM_EVENT;

  // Data specificka pro udalost etOpen
  _EVENT_OPEN = Record
    ProcessId : DWORD;
    Obj : Pointer;
    OpenReason : TOpenReason;
    GrantedAccess : DWORD;
    TID : DWORD;
    PID : DWORD;
    AccessMode : TAccessMode;
    Status : DWORD;
    TypeNameLength : DWORD;
    ObjectNameLength : DWORD;
    TypeNameOffset : DWORD;
    ObjectNameOffset : DWORD;
    end;
  EVENT_OPEN = _EVENT_OPEN;
  PEVENT_OPEN = ^EVENT_OPEN;

  // Struktura informaci o udalosti etClose
  _EVENT_CLOSE = Record
    ProcessId : DWORD;
    Obj : Pointer;
    GrantedAccess : DWORD;
    TID : DWORD;
    PID : DWORD;
    AccessMode : TAccessMode;
    TypeNameLength : DWORD;
    ObjectNameLength : DWORD;
    TypeNameOffset : DWORD;
    ObjectNameOffset : DWORD;
    end;
  EVENT_CLOSE = _EVENT_CLOSE;
  PEVENT_CLOSE = ^EVENT_CLOSE;

  // Struktura dat udalosti etOkayToClose
  _EVENT_OKAYTOCLOSE = Record
    ProcessId : DWORD;
    Obj : Pointer;
    Handle : THandle;
    TID : DWORD;
    PID : DWORD;
    AccessMode : TAccessMode;
    CloseAllowed : DWORD;
    TypeNameLength : DWORD;
    ObjectNameLength : DWORD;
    TypeNameOffset : DWORD;
    ObjectNameOffset : DWORD;
    end;
  EVENT_OKAYTOCLOSE = _EVENT_OKAYTOCLOSE;
  PEVENT_OKAYTOCLOSE = ^EVENT_OKAYTOCLOSE;

  // Struktura dat o udalosti etDelete
  _EVENT_DELETE = Record
    Obj : Pointer;
    TID : DWORD;
    PID : DWORD;
    TypeNameLength : DWORD;
    TypeNameOffset : DWORD;
    end;
  EVENT_DELETE = _EVENT_DELETE;
  PEVENT_DELETE = ^EVENT_DELETE;


Function ObinitDriverInit:Boolean;
Procedure ObinitDriverFinit;
Function ObinitDriverLoad:Boolean;
Procedure ObinitDriverUnload;

Function ObinitDriverGetEvent(Var Event:PUM_EVENT):Boolean;
Function ObinitDriverEventGetNames(Event:PUM_EVENT; Var ObjectName:WideString; Var ObjectTypeName:Widestring):Boolean;
Function ObinitDriverEventGetContext(Event:PUM_EVENT; Var TID:DWORD; Var PID:DWORD; Var Obj:Pointer; Var ProcessId:DWORD; Var AccessMode:TAccessMode):Boolean;
Function ObinitDriverEventGetOperationType(Event:PUM_EVENT):TObjectOperationType;

Implementation

Uses
  SysUtils, Utils;

Const
  IOCTL_GET_EVENT_INDEX = 0;
  IOCTL_OBINIT_GET_EVENT = $c07fc004;

Function ObinitDriverInit:Boolean;
{
  Nainstaluje sluzbu ovladace obinit.sys a zaregistruje kody
  IOCTL, ktere bude mozne ovladaci posilat.
}
begin
Result := DriverInit('obinit', ExtractFilePath(ParamStr(0)) + 'obinit.sys', 'obinit', [IOCTL_OBINIT_GET_EVENT]);
end;

Procedure ObinitDriverFinit;
{
  Odinstaluje sluzbu ovladace.
}
begin
DriverFinit;
end;

Function ObinitDriverLoad:Boolean;
{
  Nacte ovladac obinit.sys do pameti jadra a pripoji aplikaci
  k jeho komunikacnimu zarizeni. Aplikace se tim stane jedinym
  procesem, ktery muze z ovladace sbirat informace o operacich
  nad sledovanymi typy objektu.
}
begin
Result := DriverLoad;
If Result Then
  begin
  Result := DriverConnect;
  If Not Result Then
    DriverUnload;
  end;
end;

Procedure ObinitDriverUnload;
{
  Odpoji se od komunikacniho zarizeni ovladace obinit.sys a
  samotny ovladac uvolni z pameti jadra.
}
begin
DriverDisconnect;
DriverUnload;
end;

Function ObinitDriverGetEvent(Var Event:PUM_EVENT):Boolean;
{
  Precte jednu udalost z interniho seznamu ovladace obinit.sys.
  Rutina alokuje potrebny prostor pro tuto udalost na halde. Pro
  uvolneni tohoto porstoru je treba pouzit funkci HeapFree.
}
Var
  E : PUM_EVENT;
  EventSize : DWORD;
begin
Result := False;
EventSize := 32768;
Event := Nil;
E := HeapAlloc(GetProcessHeap, 0, EventSize);
If Assigned(E) Then
  Result := DriverIOCTL(IOCTL_GET_EVENT_INDEX, Nil, 0, E, EventSize);

If Not Result Then
  begin
  If Assigned(E) Then
    HeapFree(GetProcessHeap, 0, E);
  end
Else Event := E;
end;

Function ObinitDriverEventGetNames(Event:PUM_EVENT; Var ObjectName:WideString; Var ObjectTypeName:Widestring):Boolean;
{
  Ze zaznamu udalosti zjisti plne jmeno objektu (vcetne cesty) a
  jmeno jeho typu.
}
Var
  NameStart : PWideChar;
  OpenEvent : PEVENT_OPEN;
  CloseEvent : PEVENT_CLOSE;
  OkayToCloseEvent : PEVENT_OKAYTOCLOSE;
  DeleteEvent : PEVENT_DELETE;
  ObjectNameLength : Integer;
  ObjectNameOffset : Integer;
  ObjectTypeNameLength : Integer;
  ObjectTypeNameOffset : Integer;
  Name : PWideChar;
begin
ObjectName := '';
ObjectTypeName := '';
OpenEvent := Nil;
CloseEvent := Nil;
OkayToCloseEvent := Nil;
DeleteEvent := Nil;
ObjectNameLength := 0;
ObjectTypeNameLength := 0;
ObjectNameLength := 0;
ObjectTypeNameOffset := 0;
Result := True;
Case Event.EventType Of
  etOpen : begin
    OpenEvent := PEVENT_OPEN(PByte(Event) + SizeOf(UM_EVENT));
    ObjectNameLength := OpenEvent.ObjectNameLength;
    ObjectNameOffset := OpenEvent.ObjectNameOffset;
    ObjectTypeNameLength := OpenEvent.TypeNameLength;
    ObjectTypeNameOffset := OpenEvent.TypeNameOffset;
    end;
  etClose : begin
    CloseEvent := PEVENT_CLOSE(PByte(Event) + SizeOf(UM_EVENT));
    ObjectNameLength := CloseEvent.ObjectNameLength;
    ObjectNameOffset := CloseEvent.ObjectNameOffset;
    ObjectTypeNameLength := CloseEvent.TypeNameLength;
    ObjectTypeNameOffset := CloseEvent.TypeNameOffset;
    end;
  etOkayToClose : begin
    OkayToCloseEvent := PEVENT_OKAYTOCLOSE(PByte(Event) + SizeOf(UM_EVENT));
    ObjectNameLength := OkayToCloseEvent.ObjectNameLength;
    ObjectNameOffset := OkayToCloseEvent.ObjectNameOffset;
    ObjectTypeNameLength := OkayToCloseEvent.TypeNameLength;
    ObjectTypeNameOffset := OkayToCloseEvent.TypeNameOffset;
    end;
  etDelete : begin
    DeleteEvent := PEVENT_DELETE(PByte(Event) + SizeOf(UM_EVENT));
    ObjectTypeNameLength := DeleteEvent.TypeNameLength;
    ObjectTypeNameOffset := DeleteEvent.TypeNameOffset;
    end;
  Else begin
    Result := False;
    Error(Format('Unknown event type %d', [Ord(Event.EventType)]));
    end;
  end;

If Result Then
  begin
  If ObjectNameLength > 0 Then
    begin
    Inc(ObjectNameOffset, SizeOf(UM_EVENT));
    Name := PWideChar(PByte(Event) + ObjectNameOffset);
    While ObjectNameLength > 0 Do
      begin
      ObjectName := ObjectName + Name^;
      Inc(Name);
      Dec(ObjectNameLength, SizeOf(WideChar));
      end;
    end;

  If ObjectTypeNameLength > 0 Then
    begin
    Inc(ObjectTypeNameOffset, SizeOf(UM_EVENT));
    Name := PWChar(PByte(Event) + ObjectTypeNameOffset);
    While ObjectTypeNameLength > 0 Do
      begin
      ObjectTypeName := ObjectTypeName + Name^;
      Inc(Name);
      Dec(ObjectTypeNameLength, SizeOf(WideChar));
      end;
    end;
  end;
end;

Function ObinitDriverEventGetContext(Event:PUM_EVENT; Var TID:DWORD; Var PID:DWORD; Var Obj:Pointer; Var ProcessId:DWORD; Var AccessMode:TAccessMode):Boolean;
{
  Ziska ze zaznamu udalosti informace o TID vlakna a PID procesu, ktere
  danou operaci nad sledovanym typem objektu provedly.
}
Var
  OpenEvent : PEVENT_OPEN;
  CloseEvent : PEVENT_CLOSE;
  OkayToCloseEvent : PEVENT_OKAYTOCLOSE;
  DeleteEvent : PEVENT_DELETE;
begin
Result := True;
OpenEvent := Nil;
CloseEvent := Nil;
OkayToCloseEvent := Nil;
DeleteEvent := Nil;
Case Event.EventType Of
  etOpen : begin
    OpenEvent := PEVENT_OPEN(PByte(Event) + SizeOf(UM_EVENT));
    TID := OpenEvent.TID;
    PID := OpenEvent.PID;
    Obj := OpenEvent.Obj;
    ProcessId := OpenEvent.ProcessId;
    AccessMode := OpenEvent.AccessMode;
    end;
  etClose : begin
    CloseEvent := PEVENT_CLOSE(PByte(Event) + SizeOf(UM_EVENT));
    TID := CloseEvent.TID;
    PID := CloseEvent.PID;
    Obj := CloseEvent.Obj;
    ProcessId := CloseEvent.ProcessId;
    AccessMode := CloseEvent.AccessMode;
    end;
  etOkayToClose : begin
    OkayToCloseEvent := PEVENT_OKAYTOCLOSE(PByte(Event) + SizeOf(UM_EVENT));
    TID := OkayToCloseEvent.TID;
    PID := OkayToCloseEvent.PID;
    Obj := OkayToCloseEvent.Obj;
    ProcessId := OkayToCloseEvent.ProcessId;
    AccessMode := OkayToCloseEvent.AccessMode;
    end;
  etDelete : begin
    DeleteEvent := PEVENT_DELETE(PByte(Event) + SizeOf(UM_EVENT));
    TID := DeleteEvent.TID;
    PID := DeleteEvent.PID;
    Obj := DeleteEvent.Obj;
    ProcessId := 0;
    AccessMode := amKernel;
    end;
  Else Result := False;
  end;
end;

Function ObinitDriverEventGetOperationType(Event:PUM_EVENT):TObjectOperationType;
{
  Ze zaznamu udalosti zjisti, jaky typ operace dana udalost popisuje.
}
Var
  OpenEvent : PEVENT_OPEN;
begin
Result := ootUnknown;
Case Event.EventType Of
  etOpen : begin
    OpenEvent := PEVENT_OPEN(PByte(Event) + SizeOf(UM_EVENT));
    Case OpenEvent.OpenReason Of
      orCreateHandle : Result := ootCreateHandle;
      orOpenHandle : Result := ootOpenHandle;
      orDuplicateHandle : Result := ootDuplicateHandle;
      orInheritHandle : Result := ootInheritHandle;
      end;
    end;
  etClose : Result := ootCloseHandle;
  etOkayToClose : Result := ootOkayToClose;
  etDelete : Result := ootDelete;
  end;
end;

End.

