
/**
 * @fie: ssdt.c
 *
 * Tento modul obsahuje nekolik funkci pro praci s tabulkou systemovych
 * volani hlavniho modulu jadra. Modul neumi pracovat se stinovou tabulkou
 * systemovych volani, ac by se teto funkcionality dalo dosahnout snadnym
 * zobecnenim prislusnych funkci.
 */


#include <ntddk.h>
#include "cr0trick.h"
#include "ssdt.h"



// Struktura tabulky systemovych volani
typedef struct _SSDT_ENTRY
{
  // Pole adres systemovych sluzeb
  PULONG DispatchBase;
  // Pole adres pro citace jednotlivych systemovych volani (obvykle NULL)
  PULONG CounterBase;
  // Pocet systemovych sluzeb
  ULONG  DispatchCount;
  // Pole poctu argumentu jednotlivych systemovych sluzeb
  PCHAR ParamTable;
} SSDT_ENTRY, *PSSDT_ENTRY;

// Odkaz na tabulku systemovych volani hlavniho modulu jadra
static PSSDT_ENTRY SDT = NULL;



/** Vrati pocet argumentu dane systemove sluzby.
 *
 * @param Index Index cilove systemove sluzby.
 *
 * @return Funkce vrati pocet argumentu dane systemove sluzby.
 */
CHAR GetNumberOfArguments(IN ULONG Index)
{
  CHAR Ret = 0;
  PCHAR ParamBase = NULL;
  KdPrint(("ssdt.c: GetNumberOfArguments(Index=%u)\n", Index));

  Ret = SDT->ParamTable[Index];

  KdPrint(("ssdt.c: GetNumberOfArguments(-):%u\n", Ret));
  return Ret;
}



/** Zjisti pocet systemovych sluzeb tabulky systemovych volani modulu
 *  jadra.
 *
 * @return Funkce vrati pocet systemovych sluzeb tabulky systemovych
 * volani jadra.
 */
ULONG GetNumberOfServices(VOID)
{
  ULONG Ret = 0;
  KdPrint(("ssdt.c: GetNumberOfServices()\n"));

  Ret = SDT->DispatchCount;

  KdPrint(("ssdt.c: GetNumberOfServices(-):%u\n", Ret));
  return Ret;
}


/** Vrati adresu zadane systemove sluzby.
 *
 * @param Index Cislo cilove systemove sluzby.
 *
 * @return Funkce vrati adresu zadane systemove sluzby.
 */
PVOID GetServiceAddress(IN ULONG Index)
{
  PVOID Ret = NULL;
  KdPrint(("ssdt.c: GetServiceAddress(Index=%u)\n", Index));

  Ret = (PVOID)SDT->DispatchBase[Index];

  KdPrint(("ssdt.c: GetServiceAddress(-):0x%p\n", Ret));
  return Ret;
}


/** Zmeni adresu dane systemove sluzby.
 *
 * @param Index Cislo systemove sluzby, jejiz adresu chce volajici zmenit.
 * @param NewAddress Nova adresa cilove systemove sluzby.
 *
 * @return Funkce vraci hodnotu adresy systemove sluzby pred jeji zmenou.
 */
PVOID SetServiceAddress(IN ULONG Index, PVOID NewAddress)
{
  PVOID pServiceAddress = NULL;
  PVOID Ret = NULL;
  KdPrint(("ssdt.c: SetServiceAddress(Index=%u; NewAddress=0x%p)\n", Index, NewAddress));

  pServiceAddress = &SDT->DispatchBase[Index];
  CR0TrickBegin();
  Ret = (PVOID)InterlockedExchange((PLONG)pServiceAddress, (LONG)NewAddress);
  CR0TrickEnd();

  KdPrint(("ssdt.c: SetServiceAddress(-):0x%p\n", Ret));
  return Ret;
}



/** Inicializuje modul pro praci s tabulkou systemovych volani hlavniho
 *  modulu jadra.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech
 * operace.
 */
NTSTATUS SSDTInit(VOID)
{
  UNICODE_STRING u;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("ssdt.c: SSDTInit()\n"));

  RtlInitUnicodeString(&u, L"KeServiceDescriptorTable");
  SDT = (PSSDT_ENTRY)MmGetSystemRoutineAddress(&u);
  if (SDT != NULL)
    Status = STATUS_SUCCESS;

  KdPrint(("ssdt.c: SSDTInit(-):0x%x\n", Status));
  return Status;
}


/** Provadi uklid po modulu pro praci s tabulkou systemovych volani hlavniho
 * modulu jadra.
 *
 * Jelikoz tento modul sam o sobe (pri inicializaci) nezasahuje do struktur
 * jadra, tato rutina neprovadi zadnou operaci.
 */
VOID SSDTFinit(VOID)
{
  KdPrint(("ssdt.c: SSDTFinit()\n"));

  KdPrint(("ssdt.c: SSDTFinit(-)\n"));
  return;
}
