Unit SSDT;

{
  Tato unita obsahuje rutiny urcene pro praci s obsahem tabulek
  systemovych volani. Vyuziva ovladace ssdtinfo.sys na zjisteni
  aktualniho obsahu techto tabulek
}

Interface

Const
  // Typ tabulky
  TABLE_TYPE_NORMAL = 1; // Pouze hlavni modul jadra
  TABLE_TYPE_SHADOW = 2; // Stinova tabulka

Type
  // Typy pro tabulku offstu (pro x64)
  TOffsetTable = Packed Array [0..1] Of Cardinal;
  POffsetTable = ^TOffsetTable;

  // Typ pole adres systemovych sluzeb
  TAddressTable = Packed Array [0..1] Of Pointer;
  PAddressTable = ^TAddressTable;

  // Typ pole citacu
  TCounterTable = Packed Array [0..1] Of Cardinal;
  PCounterTable = ^TCounterTable;

  // Typ tabulky argumentu
  TArgumentTable = Packed Array [0..1] Of Byte;
  PArgumentTable = ^TArgumentTable;

  // Struktura jedne podtabulky
  _SERVICE_TABLE_ENTRY = Packed Record
    // Adresa tabulky adres systemovych sluzeb
    ServiceTable : PAddressTable;
    // Adresa tabulky citacu
    CounterTable : PCounterTable;
    // Pocet systemovych sluzeb v podtabulce
    NumberOfServices : Cardinal;
    // Adresa tabulky argumentu
    ArgumentTable : PArgumentTable;
    end;
  SERVICE_TABLE_ENTRY = _SERVICE_TABLE_ENTRY;
  PSERVICE_TABLE_ENTRY = ^SERVICE_TABLE_ENTRY;

  // Struktura tabulky systemovych volani
  _SERVICE_TABLE = Packed Record
    Subtables : Packed Array [0..3] Of SERVICE_TABLE_ENTRY;
    end;
  SERVICE_TABLE = _SERVICE_TABLE;
  PSERVICE_TABLE = ^SERVICE_TABLE;

  // Struktura jedne podtabulky pro x64
  _SERVICE_TABLE_ENTRY_64 = Packed Record
    ServiceTable : Int64;
    CounterTable : Int64;
    NumberOfServices : Int64;
    ArgumentTable : Int64;
    end;
  SERVICE_TABLE_ENTRY_64 = _SERVICE_TABLE_ENTRY_64;
  PSERVICE_TABLE_ENTRY_64 = ^SERVICE_TABLE_ENTRY_64;

  // Struktura tabulky systemovych volani na x64
  _SERVICE_TABLE_64 = Packed Record
    Subtables : Packed Array [0..3] Of SERVICE_TABLE_ENTRY_64;
    end;
  SERVICE_TABLE_64 = _SERVICE_TABLE_64;
  PSERVICE_TABLE_64 = ^SERVICE_TABLE_64;

  // Zaznam informaci o tabulce systemovych volani
  TSSDTInfo = Packed Record
    // Pocet subtabulek
    NumberOfSubtables : Integer;
    // Obsah tabulky v pameti jadra
    Table : SERVICE_TABLE;
    // Adresa tabulky v pameti jadra
    TableAddress : Pointer;
    // Pole adres systemovych sluzeb pro jednotlive subtabulky
    Addresses : Packed Array [0..3] Of PAddressTable;
    // Pole originalnich adres systemovych sluzeb pro jednotlive subtabulky
    OriginalAddresses : Packed Array [0..3] Of PAddressTable;
    // Pole citacu pro jednotlive subtabulky
    Counters : Packed Array [0..3] Of PCounterTable;
    // Pole argumentu pro jednotlive subtabulky
    Arguments : Packed Array [0..3] Of PArgumentTable;
    // Nasledujici pole udavaji, zda se podarilo pro danou subtabulku
    // zjistit zadane informace (adresy, orig. adresy, citace, pocty
    // sluzeb, pocty argumentu)
    AddressesRetrieved : Packed Array [0..3] Of Boolean;
    OriginalAddressesRetrieved : Packed Array [0..3] Of Boolean;
    CountersRetrieved : Packed Array [0..3] Of Boolean;
    ArgumentsRetrieved : Packed Array [0..3] Of Boolean;
    end;
  PSSDTInfo = ^TSSDTInfo;


Function SSDTGetGeneralInfo(Info:PSERVICE_TABLE; Var TableAddress:Pointer):Boolean;
Function SSDTGetAddressTable(Subtable:Cardinal; Buffer:PAddressTable; Var BufferSize:Cardinal):Boolean;
Function SSDTGetCounterTable(Subtable:Cardinal; Buffer:PCounterTable; Var BufferSize:Cardinal):Boolean;
Function SSDTGetArgumentTable(Subtable:Cardinal; Buffer:PArgumentTable; Var BufferSize:Cardinal):Boolean;
Function SSDTGetFunctionName(Index:Integer):WideString;
Function SSDTLoadFunctionNames:Boolean;
Function SSDTGetOriginalAddresses(Subtable:PSERVICE_TABLE_ENTRY; Buffer:PAddressTable; BufferSize:Cardinal):Boolean;

Function SSDTShadowGetGeneralInfo(Info:PSERVICE_TABLE; Var TableAddress:Pointer):Boolean;
Function SSDTShadowGetAddressTable(Subtable:Cardinal; Buffer:PAddressTable; Var BufferSize:Cardinal):Boolean;
Function SSDTShadowGetCounterTable(Subtable:Cardinal; Buffer:PCounterTable; Var BufferSize:Cardinal):Boolean;
Function SSDTShadowGetArgumentTable(Subtable:Cardinal; Buffer:PArgumentTable; Var BufferSize:Cardinal):Boolean;
Function SSDTShadowGetFunctionName(Index:Integer):WideString;
Function SSDTShadowLoadFunctionNames:Boolean;
Function SSDTShadowGetOriginalAddresses(Subtable:PSERVICE_TABLE_ENTRY; Buffer:PAddressTable; BufferSize:Cardinal):Boolean;

Function _SSDTGetGeneralInfo(TableType:Integer; Info:PSERVICE_TABLE; Var TableAddress:Pointer):Boolean;
Function _SSDTGetAddressTable(TableType:Integer; Subtable:Cardinal; Buffer:PAddressTable; Var BufferSize:Cardinal):Boolean;
Function _SSDTGetCounterTable(TableType:Integer; Subtable:Cardinal; Buffer:PCounterTable; Var BufferSize:Cardinal):Boolean;
Function _SSDTGetArgumentTable(TableType:Integer; Subtable:Cardinal; Buffer:PArgumentTable; Var BufferSize:Cardinal):Boolean;
Function _SSDTGetFunctionName(TableType:Integer; Subtable:Integer; Index:Integer) : WideString;
Function _SSDTGetOriginalAddresses(TableType:Integer; SubtableIndex:Integer; Subtable:PSERVICE_TABLE_ENTRY; Buffer:PAddressTable; BufferSize:Cardinal) : boolean;

Function SSDTGetSubtablesCount:Integer;

Function SSDTGetAllInfo(TableType:Integer; Info:PSSDTInfo):Boolean;
Procedure FreeSSDTInfo(Info:PSSDTInfo);

Function SSDTDriverInit:Boolean;
Procedure SSDTDriverFinit;


Implementation

Uses
  Windows, ImageHlp,
  Classes, SysUtils, Driver, Utils;

Const
  // Kody IOCTL pro ovladac ssdtinfo.sys
  IOCTL_SSDTINFO_GENERAL = $c07fc004;
  IOCTL_SSDTINFO_ADDRESSES = $c07fc008;
  IOCTL_SSDTINFO_COUNTERS = $c07fc00c;
  IOCTL_SSDTINFO_ARGUMENTS = $c07fc010;

  // Indexy techto kodu pro framework v unite Driver.pas
  IOCTL_SSDTINFO_GENERAL_INDEX = 0;
  IOCTL_SSDTINFO_ADDRESSES_INDEX = 1;
  IOCTL_SSDTINFO_COUNTERS_INDEX = 2;
  IOCTL_SSDTINFO_ARGUMENTS_INDEX = 3;


Type
  // Struktura vstupu pro IOCTL_SSDTINFO_GENERAL
  _IN_GENERAL = Cardinal;
  IN_GENERAL = _IN_GENERAL;
  PIN_GENERAL = ^IN_GENERAL;

  // Struktura vystupu pro IOCTL_SSDTINFO_GENERAL
  _OUT_GENERAL = Packed Record
    // Adresa tabulky v pameti jadra
    TableAddress : Pointer;
    // Obsah tabulky
    ServiceTable : SERVICE_TABLE;
    end;
  OUT_GENERAL = _OUT_GENERAL;
  POUT_GENERAL = ^OUT_GENERAL;

  // Struktura vstupu pro ostatni IOCTL
  _IN_SPECIFIC = Packed Record
    // Typ tabulky (pouze modul jadra, stinova)
    TableType : Cardinal;
    // Index subtabulky
    Subtable : Cardinal;
  end;
  IN_SPECIFIC = _IN_SPECIFIC;
  PIN_SPECIFIC = ^IN_SPECIFIC;


Var
  // Jmena systemovych sluzeb jadra
  _SSDTFunctionNames : TStringList;
  // Jmena systemovych sluzeb GUI
  _ShadowFunctionNames : TStringList;


Function SSDTGetGeneralInfo(Info:PSERVICE_TABLE; Var TableAddress:Pointer) : Boolean;
{
  Zjisti obecne informace o tabulce systemovych volani pouze
  pro modul jadra.
}
begin
Result := _SSDTGetGeneralInfo(TABLE_TYPE_NORMAL, Info, TableAddress);
end;

Function SSDTShadowGetGeneralInfo(Info:PSERVICE_TABLE; Var TableAddress:Pointer) : Boolean;
{
  Zjisti obecne informace o stinove tabulce systemovych volani.
}
begin
Result := _SSDTGetGeneralInfo(TABLE_TYPE_SHADOW, Info, TableAddress);
end;

Function SSDTGetAddressTable(Subtable:Cardinal; Buffer:PAddressTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah tabulky adres systemovych sluzeb pro tabulku systemovych
  volani pouze hlavniho modulu jadra.
}
begin
Result := _SSDTGetAddressTable(TABLE_TYPE_NORMAL, Subtable, Buffer, BufferSize);
end;

Function SSDTShadowGetAddressTable(Subtable:Cardinal; Buffer:PAddressTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah tabulky adres systemovych sluzeb pro stinovou tabulku
  systemovych volani.
}
begin
Result := _SSDTGetAddressTable(TABLE_TYPE_SHADOW, Subtable, Buffer, BufferSize);
end;

Function SSDTGetCounterTable(Subtable:Cardinal; Buffer:PCounterTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah tabulky citacu zadane subtabulky z tabulky systemovych
  volani pouze pro hlavni modul jadra.
}
begin
Result := _SSDTGetCounterTable(TABLE_TYPE_NORMAL, Subtable, Buffer, BufferSize);
end;

Function SSDTShadowGetCounterTable(Subtable:Cardinal; Buffer:PCounterTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah pole citacu zadane subtabulky ze stinove tabulky systemovych
  volani.
}
begin
Result := _SSDTGetCounterTable(TABLE_TYPE_SHADOW, Subtable, Buffer, BufferSize);
end;

Function SSDTGetArgumentTable(Subtable:Cardinal; Buffer:PArgumentTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah pole argumentu zadane subtabulky tabulky systemovych
  volani urcene pouze pro hlavni modul jadra.
}
begin
Result := _SSDTGetArgumentTable(TABLE_TYPE_NORMAL, Subtable, Buffer, BufferSize);
end;

Function SSDTShadowGetArgumentTable(Subtable:Cardinal; Buffer:PArgumentTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah pole argumentu zadane subtabulky stinove tabulky
  systemovych volani.
}
begin
Result := _SSDTGetArgumentTable(TABLE_TYPE_SHADOW, Subtable, Buffer, BufferSize);
end;

Function SSDTGetFunctionName(Index:Integer):WideString;
{
  Vrati nazev zadane systemove sluzby v tabulce systemovych
  sluzeb jadra.
}
begin
Result := 'N/A';
If Assigned(_SSDTFunctionNames) And (Index < _SSDTFunctionNames.Count) Then
  Result := _SSDTFunctionNames[Index];
end;

Function SSDTShadowGetFunctionName(Index:Integer):WideString;
{
  Vrati jmeno zadane systemove sluzby z tabulky systemovvych sluzeb
  GUI.
}
begin
Result := 'N/A';
If Assigned(_ShadowFunctionNames) And (Index < _ShadowFunctionNames.Count) Then
  Result := _ShadowFunctionNames[Index];
end;

Function SSDTLoadFunctionNames:Boolean;
{
  Nacte jmena systemovych sluzeb jadra.
}
Var
  FileName : WideString;
  Major, Minor, Build : Cardinal;
begin
Result := False;
GetOSVersion(Major, Minor, Build);
FileName := ExtractFilePath(ParamStr(0));
FileName := Format('%sssdt-%d-%d-%d.dat', [FileName, Major, Minor, Build]);
If FileName <> '' Then
  begin
  _SSDTFunctionNames := TStringList.Create;
  Try
    _SSDTFunctionNames.LoadFromFile(FileName);
    Result := True;
  Except
    Result := False;
    end;

  If Not Result Then
    FreeAndNil(_SSDTFunctionNames);
  end;
end;

Function SSDTShadowLoadFunctionNames:Boolean;
{
  Nacte jmena systemovych sluzeb pro GUI.
}
Var
  FileName : WideString;
  Major, Minor, Build : Cardinal;
begin
Result := False;
FileName := ExtractFilePath(ParamStr(0));
GetOSVersion(Major, Minor, Build);
FileName := Format('%sshadow-%d-%d-%d.dat', [FileName, Major, Minor, Build]);
If FileName <> '' Then
  begin
  _ShadowFunctionNames := TStringList.Create;
  Try
    _ShadowFunctionNames.LoadFromFile(FileName);
    Result := True;
  Except
    Result := False;
    end;

  If Not Result Then
    FreeAndNil(_ShadowFunctionNames);
  end;
end;

Function _SSDTGetGeneralInfo(TableType:Integer; Info:PSERVICE_TABLE; Var TableAddress:Pointer) : Boolean;
{
  Vrati obecne informace o dane tabulce systemovych volani.
}
Var
  BytesReturned : Cardinal;
  Buffer : OUT_GENERAL;
begin
BytesReturned := SizeOf(OUT_GENERAL);
Result := DriverIOCTL(IOCTL_SSDTINFO_GENERAL_INDEX, @TableType, Sizeof(TableType), @Buffer, BytesReturned);
TableAddress := Buffer.TableAddress;
Info^ := Buffer.ServiceTable;
end;

Function _SSDTGetAddressTable(TableType:Integer; Subtable:Cardinal; Buffer:PAddressTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah tabulky adres zadane subtabulky ve vzolene tabulce
  systemovych volani.
}
Var
  Input : IN_SPECIFIC;
begin
Input.TableType := TableType;
Input.Subtable := Subtable;
Result := DriverIOCTL(IOCTL_SSDTINFO_ADDRESSES_INDEX, @Input,SizeOf(Input), Buffer, BufferSize);
end;

Function _SSDTGetCounterTable(TableType:Integer; Subtable:Cardinal; Buffer:PCounterTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah tabulky citacu zadane subtabulky ve vzolene tabulce
  systemovych volani.
}
Var
  Input : IN_SPECIFIC;
begin
Input.TableType := TableType;
Input.Subtable := Subtable;
Result := DriverIOCTL(IOCTL_SSDTINFO_COUNTERS_INDEX, @Input,SizeOf(Input), Buffer, BufferSize);
end;

Function _SSDTGetArgumentTable(TableType:Integer; Subtable:Cardinal; Buffer:PArgumentTable; Var BufferSize:Cardinal) : Boolean;
{
  Vrati obsah tabulky argumentu zadane subtabulky ve vzolene tabulce
  systemovych volani.
}
Var
  Input : IN_SPECIFIC;
begin
Input.TableType := TableType;
Input.Subtable := Subtable;
Result := DriverIOCTL(IOCTL_SSDTINFO_ARGUMENTS_INDEX, @Input, SizeOf(Input), Buffer, BufferSize);
end;

Function SSDTGetSubtablesCount:Integer;
{
  Vrati pocet subtabulek v tabulce systemovych volani. Toto cislo vypada
  zavisle na verzi operaciho systemu.
}
Var
  Major, Minor, Build : Cardinal;
begin
GetOSVersion(Major, Minor, Build);
If Major = 6 Then
  Result := 2
Else Result := 4;
end;

Function _SSDTGetFunctionName(TableType:Integer; Subtable:Integer; Index:Integer) : WideString;
{
  Vrati nazev systemove sluzby ze zadane tabulky systemovych volani a
  jeji subtabulky
}
begin
Result := '<neznamy>';
Case TableType Of
  TABLE_TYPE_NORMAL : begin
    If Subtable = 0 Then
      Result := SSDTGetFunctionName(Index);
    end;
  TABLE_TYPE_SHADOW : begin
    If Subtable = 0 Then
      Result := SSDTGetFunctionName(Index)
    Else If Subtable = 1 Then
      Result := SSDTShadowGetFunctionName(Index);
    end;
  end;
end;

Function SSDTShadowGetOriginalAddresses(Subtable:PSERVICE_TABLE_ENTRY; Buffer:PAddressTable; BufferSize:Cardinal) : Boolean;
{
  Zjisti originalni adresy systemovych sluzeb pro druhou subtabulku
  stinove tabulky systemovych volani. Tyto adresy patri funkcim GUI.
}
Var
  DriverNameList : TNameList;
  DriverBaseList : TPointerList;
  DriverSizeList : TIntegerList;
  Index : Integer;

  pMap : PAddressTable;
  Offset : Cardinal;

  I : Integer;
  DriverName : WideString;
  ImageBase : Cardinal;
  L : PLOADEDIMAGE;
begin
ZeroMemory(Buffer, BufferSize);
Result := BufferSize >= Subtable^.NumberOfServices * SizeOf(Pointer);
If Result Then
  begin
  Result := GetDriverList(DriverNameList, DriverBaseList, DriverSizeList);
  If Result Then
    begin
    Index := GetAddressOwner(DriverBaseList, DriverSizeList, Subtable^.ServiceTable);
    Result := Index >= 0;
    If Result Then
      begin
      DriverName := DriverNameList[Index];
      Result := ExtractFileName(DriverNameList[Index]) = 'win32k.sys';
      If Result Then
        begin
        Offset := Cardinal(Subtable^.ServiceTable) - Cardinal(DriverBaseList[Index]);
        L := ImageLoad(PAnsiChar(AnsiString(DriverName)), Nil);
        Result := Assigned(L);
        If Result Then
          begin
          ImageBase := L^.FileHeader^.OptionalHeader.ImageBase;
          pMap := ImageRVAtoVA(L^.FileHeader, L^.MappedAddress, Offset, Nil);
          Try
            ZeroMemory(Buffer, BufferSize);
            CopyMemory(Buffer, pMap, Subtable^.NumberOfServices * SizeOf(Pointer));
            For I := 0 To Subtable^.NumberOfServices - 1 Do
              Buffer^[I] := Pointer(Cardinal(Buffer^[I]) - ImageBase + Cardinal(DriverBaseList[Index]));
          Except
            Result := False;
            Error('Chyba pri kopirovani!');
            end;

          ImageUnload(L);
          end Else Error(Format('Nepodarilo se nacist %s! %s', [DriverName, LastErrorStr]));
        end Else Error('Modul neni win32k.sys!');
      end Else Error('Adresa nema vlastnika!');

    DriverNameList := Nil;
    DriverBaseList := Nil;
    DriverSizeList := Nil;
    end Else Error('Nepodarilo se ziskat seznam ovladacu!');
  end Else Error('Buffer je prilis maly!');
end;

Function SSDTGetOriginalAddresses(Subtable:PSERVICE_TABLE_ENTRY; Buffer:PAddressTable; BufferSize:Cardinal) : Boolean;
{
  Zjisti originalni adresy systemovych sluzeb pro prvni subtabulku
  stinove tabulky systemovych volani. Tyto adresy patri funkcim jadra.
}
Var
  DriverNameList : TNameList;
  DriverAddressList : TPointerList;
  DriverSizeList : TIntegerList;
  Index : Integer;
  pMap : PAddressTable;
  Offset : Cardinal;
  I : Integer;
  DriverName : WideString;
  ImageBase : Cardinal;
  L : PLOADEDIMAGE;
begin
ZeroMemory(Buffer, BufferSize);
Result := BufferSize >= Subtable^.NumberOfServices * SizeOf(Pointer);
If Result Then
  begin
  Result := GetDriverList(DriverNameList, DriverAddressList, DriverSizeList);
  If Result Then
    begin
    Index := GetAddressOwner(DriverAddressList, DriverSizeList, Subtable^.ServiceTable);
    Result := Index >= 0;
    If Result Then
      begin
      DriverName := DriverNameList[Index];
      Result := (ExtractFileName(DriverNameList[Index]) = 'ntoskrnl.exe') Or (ExtractFileName(DriverNameList[Index]) = 'ntkrnlpa.exe');
      If Result Then
        begin
        Offset := Cardinal(Subtable^.ServiceTable) - Cardinal(DriverAddressList[Index]);
        L := ImageLoad(PAnsiChar(AnsiString(DriverName)), Nil);
        Result := Assigned(L);
        If Result Then
          begin
          ImageBase := L^.FileHeader^.OptionalHeader.ImageBase;
          pMap := ImageRVAtoVA(L^.FileHeader, L^.MappedAddress, Offset, Nil);
          Try
            ZeroMemory(Buffer, BufferSize);
            CopyMemory(Buffer, pMap, Subtable^.NumberOfServices * SizeOf(Pointer));
            For I := 0 To Subtable^.NumberOfServices - 1 Do
              Buffer^[I] := Pointer( Cardinal(Buffer^[I]) - ImageBase + Cardinal(DriverAddressList[Index]));
          Except
            Result := False;
            Error('Chyba pri kopirovani!');
            end;

          ImageUnload(L);
          end Else Error(Format('Nepodarilo se nacist %s! %s', [DriverName, LastErrorStr]));
        end Else Error('Modul neni ntoskrnl.exe!');
      end Else Error('Adresa nema vlastnika!');

    DriverNameList := Nil;
    DriverAddressList := Nil;
    DriverSizeList := Nil;
    end
  Else Error('Nepodarilo se ziskat seznam ovladacu!');
  end
Else Error('Buffer je prilis maly!');
end;

Function _SSDTGetOriginalAddresses(TableType:Integer; SubtableIndex:Integer; Subtable:PSERVICE_TABLE_ENTRY; Buffer:PAddressTable; BufferSize:Cardinal) : boolean;
{
  Vrati originalni adresy systemovych sluzeb ze zadane tabulky
  systemovych volani a jeji subtabulky.
}
begin
Result := False;
Case TableType Of
  TABLE_TYPE_NORMAL : begin
    If SubtableIndex = 0 Then
      Result := SSDTGetOriginalAddresses(Subtable, Buffer, BufferSize);
    end;
  TABLE_TYPE_SHADOW : begin
    If SubtableIndex = 0 Then
      Result := SSDTGetOriginalAddresses(Subtable, Buffer, BufferSize)
    Else If SubtableIndex = 1 Then
      Result := SSDTShadowGetOriginalAddresses(Subtable, Buffer, BufferSize);
    end;
  end;
end;


Function SSDTGetAllInfo(TableType:Integer; Info:PSSDTInfo) : Boolean;
{
  Zjisti vsechny mozne informace o zadane tabulce systemovych
  volani.
}
Var
  Size : Cardinal;
  I : Integer;
begin
ZeroMemory(Info, SizeOf(TSSDTInfo));
Result := _SSDTGetGeneralInfo(TableType, @Info^.Table, Info^.TableAddress);
If Result Then
  begin
  Info^.NumberOfSubtables := SSDTGetSubtablesCount;
  For I := 0 To Info^.NumberOfSubtables - 1 Do
    begin
    If Info^.Table.Subtables[I].NumberOfServices >= 65536 Then
      Continue;

    If Assigned(Info^.Table.Subtables[I].ServiceTable) Then
      begin
      Size := Info^.Table.Subtables[I].NumberOfServices * SizeOf(Pointer);
      Info^.Addresses[I] := MemAlloc(Size);
      Result := _SSDTGetAddressTable(TableType, I, Info^.Addresses[I], Size);
      Info^.AddressesRetrieved[I] := Result;
      end;

    If Info^.Table.Subtables[I].NumberOfServices > 0 Then
      begin
      Size := Info^.Table.Subtables[I].NumberOfServices * SizeOf(Pointer);
      Info^.OriginalAddresses[I] := MemAlloc(Size);
      Result := _SSDTGetOriginalAddresses(TableType, I, @Info^.Table.Subtables[I], Info^.OriginalAddresses[I], Size);
      Info^.OriginalAddressesRetrieved[I] := Result;
      end;

    If Assigned(Info^.Table.Subtables[I].CounterTable) Then
      begin
      Size := Info^.Table.Subtables[I].NumberOfServices * SizeOf(Cardinal);
      Info^.Counters[I] := MemAlloc(Size);
      Result := _SSDTGetCounterTable(TableType, I, Info^.Counters[I], Size);
      Info^.CountersRetrieved[I] := Result;
      end;

    If Assigned(Info^.Table.Subtables[I].ArgumentTable) Then
      begin
      Size := Info^.Table.Subtables[I].NumberOfServices * SizeOf(Byte);
      Info^.Arguments[I] := MemAlloc(Size);
      Result := _SSDTGetArgumentTable(TableType, I, Info^.Arguments[I], Size);
      Info^.ArgumentsRetrieved[I] := Result;
      end;
    end;
  end;
end;

Procedure FreeSSDTInfo(Info:PSSDTInfo);
{
  Uvolni pamet alokovanou pri uspesnem volani funkce SSDTGetAllInfo.
}
Var
  I : Integer;
  NumberOfFreeTables : Integer;
begin
NumberOfFreeTables := SSDTGetSubtablesCount;
For I := 0 To NumberOfFreeTables - 1  Do
  begin
  If Assigned(Info^.Addresses[I]) Then
    begin
    MemFree(Pointer(Info^.Addresses[I]));
    Info^.Addresses[I] := Nil;
    end;

  If Assigned(Info^.OriginalAddresses[I]) Then
    begin
    MemFree(Pointer(Info^.OriginalAddresses[I]));
    Info^.OriginalAddresses[I] := Nil;
    end;

  If Assigned(Info^.Counters[I]) Then
    begin
    MemFree(Pointer(Info^.Counters[I]));
    Info^.Counters[I] := Nil;
    end;

  If Assigned(Info^.Arguments[I]) Then
    begin
    MemFree(Pointer(Info^.Arguments[I]));
    Info^.Arguments[I] := Nil;
    end;
  end;

Zeromemory(Info, SizeOf(TSSDTInfo));
end;

Function SSDTDriverInit:Boolean;
{
  Nainstaluje ovladac ssdtinfo.sys do registru, nacte jej do jadra
  a pripoji se k jeho komunikacnimu zarizeni.
}
Var
  DriverFileName : WideString;
begin
DriverFileName := Format('%s%s', [ExtractFilePath(ParamStr(0)), 'ssdtinfo.sys']);
DriverInit('ssdtinfo', DriverFileName, 'ssdtinfo', [IOCTL_SSDTINFO_GENERAL, IOCTL_SSDTINFO_ADDRESSES, IOCTL_SSDTINFO_COUNTERS, IOCTL_SSDTINFO_ARGUMENTS]);
DriverLoad;
Result := DriverConnect;
If Not Result Then
  begin
  DriverUnload;
  DriverFinit;
  end;
end;

Procedure SSDTDriverFinit;
{
  Odpoji se od komunikacniho zarizeni ovladace ssdtinfo.sys, uvolni
  jej z pameti jadra a odinstaluje.
}
begin
DriverDisconnect;
DriverUnload;
DriverFinit;
end;

Initialization
_SSDTFunctionNames := Nil;
_ShadowFunctionNames := Nil;

Finalization
If Assigned(_SSDTFunctionNames) Then
  FreeAndNil(_SSDTFunctionNames);
If Assigned(_ShadowFunctionNames) Then
  FreeAndNil(_ShadowFunctionNames);

End.

