
/**
 * @file: utils.c
 *
 * Tento soubor implementuje nekolik ruznorodych rutin, ktere se tematicky
 * nevesly do jinych souboru. Rozsiruje pusobnost nekterych funkci i na
 * starsi verze Windows, ktere je jeste nativne nepodporuji (neexportuji).
 */

#include <ntddk.h>
#include "version.h"
#include "driver.h"
#include "utils.h"

// definice funkce PsGetProcessId pro Windows 2000 (vyse uz je exportovana)
typedef HANDLE (*PSGETPROCESSID)(PEPROCESS Process);
// definice funkce PsGetThreadId pro Windows 2000 (vyse uz je exportovana)
typedef HANDLE (*PSGETTHREADID)(PETHREAD Thread);

// Cislo verze aktualne beziciho OS
static ULONG VersionCode = VERSION_UNKNOWN;

// Udaje nutne pro zavedeni prenositelne verze PsGetProcessId
// (adresa exportu pro Windows XP a novejsi, offset na PID
// v ramci EPROCESS pro Windows 2000
static PSGETPROCESSID _PsGetProcessId = NULL;
static ULONG ProcessIdOffsetW2K = 0x9C;

// Udaje nutne pro zavedeni prenositelne verze PsGetThreadId
// (adresa exportu pro Windows XP a novejsi, offset na TID
// v ramci EPROCESS pro Windows 2000
static PSGETTHREADID _PsGetThreadId = NULL;
static ULONG ThreadIdOffsetW2K = 0x1e4;



/** Tato fnkce je prenositelnejsi verzi rutiny PsGetProcessId z Windows XP
 *  a novejsich verzi OS.
 *
 *  @param Process Adresa tela objektu procesu, jehoz PID chce volajici
 *  zjistit.
 *
 *  @return Funkce vraci PID ciloveho procesu. V pripade neuspechu vrati
 *  NULL.
 */
HANDLE GetProcessId(PEPROCESS Process)
{
  HANDLE Ret = NULL;
  KdPrint(("utils.c: GetProcessId(Process=0x%p)\n", Process));

  if (_PsGetProcessId == NULL) {
    ASSERT(VersionCode == VERSION_W2K);
    Ret =   *(PHANDLE)((PCHAR)Process + ProcessIdOffsetW2K);
  } else Ret = _PsGetProcessId(Process);

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


/** Tato funkce je prenositelnejsi verzi rutiny PsGetThreadId zname
 *  z Windows XP a novejsich verzi OS.
 *
 * @param Thread Adresa tela objektu ciloveho vlakna.
 *
 *  @return Rutina vraci TID ciloveho vlakna a NULL v pripade neuspechu.
 */
HANDLE GetThreadId(PETHREAD Thread)
{
  HANDLE Ret = NULL;
  KdPrint(("utils.c: GetThreadId(Thread=0x%p)\n", Thread));

  if (_PsGetThreadId == NULL) {
    ASSERT(VersionCode == VERSION_W2K);
    Ret =   *(PHANDLE)((PCHAR)Thread + ThreadIdOffsetW2K);
  } else Ret = _PsGetThreadId(Thread);

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



/** Tato rutina provadi kroky nutne pro spravne fungovani funkci ruzneho
 *  druhu (GetProcessId, GetThreadId).
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici uspech operace.
 */
NTSTATUS UtilsInit(VOID)
{
  UNICODE_STRING uProcName;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("utils.c: UtilsInit()\n"));

  VersionCode = GetVersionCode();
  if (VersionCode != VERSION_UNKNOWN) {
    Status = STATUS_SUCCESS;
    if (VersionCode != VERSION_W2K) {
      RtlInitUnicodeString(&uProcName, L"PsGetProcessId");
      _PsGetProcessId = (PSGETPROCESSID)MmGetSystemRoutineAddress(&uProcName);
      if (_PsGetProcessId != NULL) {
        RtlInitUnicodeString(&uProcName, L"PsGetThreadId");
        _PsGetThreadId = (PSGETTHREADID)MmGetSystemRoutineAddress(&uProcName);
        if (_PsGetThreadId == NULL) {
          KdPrint(("utils.c: UtilsInit(): Failed to get address of PsGetThreadId routine.\n"));
          Status = STATUS_NOT_FOUND;
        }
      } else {
        KdPrint(("utils.c: UtilsInit(): Failed to get address of PsGetProcessId routine.\n"));
        Status = STATUS_NOT_FOUND;
      }
    }
  } else Status = STATUS_NOT_SUPPORTED;

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


/** Rutina provadi uklid po modulu Utils.
 *
 * Protoze tento modul nijak primo nezasahuje do struktur jada, tato
 * funkce ve skutecnosti neprovadi zadnou operaci.
 */
VOID UtilsFinit(VOID)
{
  KdPrint(("utils.c: UtilsFinit()\n"));

  KdPrint(("utils.c: UtilsFinit(-)\n"));
  return;
}
