
/**
 * @file object_header.c
 *
 * Tento soubor implementuje rutiny pracujici s hlavickou objektu (OBJECT_HEADER) a
 * jejimi podstrukturami. Jedna se o kod nizsi urovne, ktery ke sve praci nepouziva
 * zamky na objektech ani jine zpusoby synchronizace.
 */

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

// Tabulka offsetu jednotlivych podhlavicek (OBJECT_HEADER_XXX_INFO). Pouze pro Windows 7
static UCHAR *_ObpInfoMaskToOffset = NULL;

// Tabulka prekladu indexu na telo objektu typu. Pouze pro Windows 7
static POBJECT_TYPE *_ObpTypeIndexTable = NULL;

// Cislo verze operacniho systému, na ktere ovladac prave bezi
static ULONG VersionCode = VERSION_UNKNOWN;



/** Najde pole ObpInfoMaskToOffset a zapise jeho adresu do promenne _ObpInfoMaskToOffset.
 * 
 * Pole ObpInfoMaskToOffset slouzi k prekladu hodnot v polozce InfoMask struktury 
 * OBJECT_HEADER na offsety jednotlivych podhlavicek (OBJECT_HEADER_XXX_INFO). Funkce
 * adresu tohoto pole najde technikou pattern-matchingu ve funkci ObQueryNameInfo.
 *
 * Rutina pracuje pouze na Windows 7, na starsich verzich Windows se offsety podhlavicek
 * pocitaji jinym zpusobem (polozka InfoMask neni v hlavicce pritomna).
 *
 * @return Vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.
 */
static NTSTATUS OHFindObpInfoMaskToOffset(VOID)
{
  LONG i = 0;
  PUCHAR buf = NULL;
  PVOID Address = NULL;
  UNICODE_STRING uObQueryNameInfo;
  NTSTATUS status = STATUS_UNSUCCESSFUL;;
  KdPrint(("object_header.c: OHFindObpInfoMaskToOffset()\n"));

  RtlInitUnicodeString(&uObQueryNameInfo, L"ObQueryNameInfo");
  buf = (PCHAR)MmGetSystemRoutineAddress(&uObQueryNameInfo);
  if (buf != NULL) {
    for (i = 0; i < 0x40; ++i) {
      if (buf[0] == 0x48 && buf[1] == 0x8D) {
        // x64
        Address = (PVOID)((PCHAR)(buf + 7) + (*(PLONG32)&buf[3]));
        break;
      } else if (buf[0] == 0x0F && buf[1] == 0xB6 && buf[2] == 0x89) {
        // x86
        Address = *(PVOID *)((PVOID)&buf[3]);
        break;
      }

      ++buf;
    }

    if (Address != NULL) {
      _ObpInfoMaskToOffset = (UCHAR *)Address;
      KdPrint(("object_header.c: OHFindObpInfoMaskToOffset(): Variable address 0x%p\n", Address));
      status = STATUS_SUCCESS;
    } else status = STATUS_UNSUCCESSFUL;
  } else status = STATUS_NOT_FOUND;

  KdPrint(("object_header.c: OHFindObpInfoMaskToOffset(-):0x%x\n", status));
  return status;
}


/** Zjisti adresu pole ObpTypeIndexTable a zapise ji do promenne _ObpTypeIndexTable.
 *
 * Pole ObpTypeIndexTable slouzi na Windows 7 k prekladu indexu typu objektu na prislusny
 * objekt typu (strukturu OBJECT_TYPE). Na starsich verzich teto tabulky neni zapotrebi,
 * protoze se odkaz na typ objektu nachazi primo ve strukture OBJECT_HEADER. Na Windows 7
 * se v hlavicce objektu nachazi pouze index typu.
 *
 * Funkce najde adresu pole ObpTypeIndexTable pomoci techniky pattern-matching na rutine
 * ObGetObjectType.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.
 */
static NTSTATUS OHFindObpTypeIndexTable(VOID)
{
  LONG i = 0;
  PUCHAR buf = NULL;
  PVOID Address = NULL;
  UNICODE_STRING uObGetObjectType;
  NTSTATUS status = STATUS_UNSUCCESSFUL;;
  KdPrint(("object_header.c: OHFindObpTypeIndexTable()\n"));

  RtlInitUnicodeString(&uObGetObjectType, L"ObGetObjectType");
  buf = (PCHAR)MmGetSystemRoutineAddress(&uObGetObjectType);
  if (buf) {
    for (i = 0; i < 0x20; ++i) {
      if (buf[0] == 0x48 && buf[1] == 0x8D) {
        // x64
        Address = (PVOID)((PCHAR)(buf + 7) + (*(PLONG32)&buf[3]));
        break;
      } else if (buf[0] == 0x8B && buf[1] == 0x04 && buf[2] == 0x85) {
        // x86
        Address = *(PVOID *)((PVOID)&buf[3]);
        break;
      }

      ++buf;
    }

    if (Address != NULL) {
      _ObpTypeIndexTable = (POBJECT_TYPE *)Address;
      KdPrint(("object_header.c: OHFindObpTypeIndexTable(): Variable address 0x%p\n", Address));
      status = STATUS_SUCCESS;
    } else status = STATUS_UNSUCCESSFUL;
  } else status = STATUS_NOT_FOUND;

  KdPrint(("object_header.c: OHFindObpTypeIndexTable(-):0x%x\n", status));
  return status;
}



/** Vrati pocet referenci na objekt.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vraci pocet referenci na cilovy objekt, tedy hodnotu polozky PointerCount
 * ve strukture OBJECT_HEADER.
 */
ULONG_PTR OHGetPointerCount(PVOID ObjectHeader)
{
  ULONG_PTR Ret = (ULONG)-1;
  KdPrint(("object_header.c: OHGetPointerCount(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KGetPointerCount(ObjectHeader); break;
    case VERSION_WXP: Ret = OHWXPGetPointerCount(ObjectHeader); break;
    case VERSION_W2K3: Ret = OHW2K3GetPointerCount(ObjectHeader); break;
    case VERSION_VISTA: Ret = OHVistaGetPointerCount(ObjectHeader); break;
    case VERSION_W7: Ret = OHW7GetPointerCount(ObjectHeader); break;
    default:
      KdPrint(("object_header.c: OHGetPointerCount(): This system version is not supported.\n"));
      break;
  }

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


/** Vrati pocet handle odkazujicich na cilovy objekt.
 *
 * @param ObjectHeader Hlavicka objektu, ktery volajiciho zajima.
 *
 * @return Funkce vraci pocet handle odkazujicich na dany objekt. Tato informace je
 * ulozena v polozce HandleCount struktury OBJECT_HEADER.
 */
ULONG_PTR OHGetHandleCount(PVOID ObjectHeader)
{
  ULONG_PTR Ret = (ULONG)-1;
  KdPrint(("object_header.c: OHGetHandleCount(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KGetHandleCount(ObjectHeader); break;
    case VERSION_WXP: Ret = OHWXPGetHandleCount(ObjectHeader); break;
    case VERSION_W2K3: Ret = OHW2K3GetHandleCount(ObjectHeader); break;
    case VERSION_VISTA: Ret = OHVistaGetHandleCount(ObjectHeader); break;
    case VERSION_W7: Ret = OHW7GetHandleCount(ObjectHeader); break;
    default:
      KdPrint(("object_header.c: OHGetHandleCount(): This system version is not supported.\n"));
      break;
  }

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


/** Vrati adresu tela objektu typu pro cilovy objekt.
 *
 * Funkce v pripade Windows starsich nez Windows 7 vrati primo hodnotu polozky ObjectType
 * ve strukture OBJECT_HEADER prislusneho objektu. Na Windows 7 provede preklad indexu
 * typu pomoci pole ObpTypeIndexTable.
 *
 * Vraceny objekt typu neni oeraci nijak ovlivnen, nedochazi ani k zvyseni poctu referenci
 * na nej.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vraci adresu tela objektu typu pro dany objekt. Funkce by nemela nikdy
 * vratit neplatnou adresu nebo hodnotu NULL.
 */
POBJECT_TYPE OHGetObjectType(PVOID ObjectHeader)
{
  POBJECT_TYPE Ret = NULL;
  KdPrint(("object_header.c: OHGetObjectType(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K: Ret = (POBJECT_TYPE)OHW2KGetType(ObjectHeader); break;
    case VERSION_WXP: Ret = (POBJECT_TYPE)OHWXPGetType(ObjectHeader); break;
    case VERSION_W2K3: Ret = (POBJECT_TYPE)OHW2K3GetType(ObjectHeader); break;
    case VERSION_VISTA: Ret = (POBJECT_TYPE)OHVistaGetType(ObjectHeader); break;
    case VERSION_W7: Ret = (POBJECT_TYPE)OHW7GetType(ObjectHeader); break;
    default:
      KdPrint(("object_header.c: OHGetObjectType(): This system version is not supported.\n"));
      break;
  }

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


/** Rutina vrati offset na podhlavicku OBJECT_HEADER_NAME_INFO.
 *
 * Offset je vracen jako kladna hodnota. Volajici jej musi odecist od poctaku struktury
 * OBJECT_HEADER, aby ziskal adresu struktury OBJECT_HEADER_NAME_INFO.
 *
 * Na Windows starsich nez Windows 7 je rutina implementovana tak, ze pouze vrati hodnotu
 * polozky NameInfoOffset ve strukture OBJECT_HEADER. Na Windows 7 dochazi k prekladu pres
 * pole InfoMaskToOffset.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vraci offset struktury OBJECT_HEADER_NAME_INFO vzhledem k hlavicce
 * daneho objektu (struktura OBJECT_HEADER). Pokud objekt tuto podhlavicku nema, funkce
 * vrati nulu.
 */
ULONG OHGetNameInfoOffset(PVOID ObjectHeader)
{
  ULONG InfoMask = 0;
  ULONG Ret = (ULONG)0;
  KdPrint(("object_header.c: OHGetNameInfoOffset(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KGetNameInfoOffset(ObjectHeader); break;
    case VERSION_WXP: Ret = OHWXPGetNameInfoOffset(ObjectHeader); break;
    case VERSION_W2K3: Ret = OHW2K3GetNameInfoOffset(ObjectHeader); break;
    case VERSION_VISTA: Ret = OHVistaGetNameInfoOffset(ObjectHeader); break;
    case VERSION_W7: 
      InfoMask = OHGetInfoMask(ObjectHeader);
      if ((InfoMask & INFOMASK_HEADER_NAME_INFO) > 0)
        Ret = OHW7GetNameInfoOffset(ObjectHeader); 

      break;
    default:
      KdPrint(("object_header.c: OHGetNameInfoOffset(): This system version is not supported.\n"));
      break;
  }

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


/** Rutina vrati offset na podhlavicku OBJECT_HEADER_HANDLE_INFO.
 *
 * Offset je vracen jako kladna hodnota. Volajici jej musi odecist od poctaku struktury
 * OBJECT_HEADER, aby ziskal adresu struktury OBJECT_HANDLE_NAME_INFO.
 *
 * Na Windows starsich nez Windows 7 je rutina implementovana tak, ze pouze vrati hodnotu
 * polozky HandleInfoOffset ve strukture OBJECT_HEADER. Na Windows 7 dochazi k prekladu pres
 * pole InfoMaskToOffset.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vraci offset struktury OBJECT_HEADER_HANDLE_INFO vzhledem k hlavicce
 * daneho objektu (struktura OBJECT_HEADER). Pokud dany objekt tuto podhlavicku nema,
 * funkce vrati nulu.
 */
 ULONG OHGetHandleInfoOffset(PVOID ObjectHeader)
{
  ULONG InfoMask = 0;
  ULONG Ret = (ULONG)0;
  KdPrint(("object_header.c: OHGetHandleInfoOffset(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KGetHandleInfoOffset(ObjectHeader); break;
    case VERSION_WXP: Ret = OHWXPGetHandleInfoOffset(ObjectHeader); break;
    case VERSION_W2K3: Ret = OHW2K3GetHandleInfoOffset(ObjectHeader); break;
    case VERSION_VISTA: Ret = OHVistaGetHandleInfoOffset(ObjectHeader); break;
    case VERSION_W7: 
      InfoMask = OHGetInfoMask(ObjectHeader);
      if ((InfoMask & INFOMASK_HEADER_HANDLE_INFO) > 0)
        Ret = OHW7GetHandleInfoOffset(ObjectHeader); 

      break;
    default:
      KdPrint(("object_header.c: OHGetHandleInfoOffset(): This system version is not supported.\n"));
      break;
  }

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


/** Rutina vrati offset na podhlavicku OBJECT_HEADER_QUOTA_INFO.
 *
 * Offset je vracen jako kladna hodnota. Volajici jej musi odecist od poctaku struktury
 * OBJECT_HEADER, aby ziskal adresu struktury OBJECT_HEADER_QUOTA_INFO.
 *
 * Na Windows starsich nez Windows 7 je rutina implementovana tak, ze pouze vrati hodnotu
 * polozky QuotaInfoOffset ve strukture OBJECT_HEADER. Na Windows 7 dochazi k prekladu pres
 * pole InfoMaskToOffset.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vraci offset struktury OBJECT_HEADER_QUOTA_INFO vzhledem k hlavicce
 * daneho objektu (struktura OBJECT_HEADER). Pokud dany objekt tuto podhlavicku nema,
 * funkce vrati nulu.
 */
ULONG OHGetQuotaInfoOffset(PVOID ObjectHeader)
{
  ULONG InfoMask = 0;
  ULONG Ret = (ULONG)0;
  KdPrint(("object_header.c: OHGetQuotaInfoOffset(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KGetQuotaInfoOffset(ObjectHeader); break;
    case VERSION_WXP: Ret = OHWXPGetQuotaInfoOffset(ObjectHeader); break;
    case VERSION_W2K3: Ret = OHW2K3GetQuotaInfoOffset(ObjectHeader); break;
    case VERSION_VISTA: Ret = OHVistaGetQuotaInfoOffset(ObjectHeader); break;
    case VERSION_W7: 
      InfoMask = OHGetInfoMask(ObjectHeader);
      if ((InfoMask & INFOMASK_HEADER_QUOTA_INFO) > 0)
        Ret = OHW7GetQuotaInfoOffset(ObjectHeader); 

      break;
    default:
      KdPrint(("object_header.c: OHGetQuotaInfoOffset(): This system version is not supported.\n"));
      break;
  }

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


/** Vrati priznaky hlavicky ciloveho objektu.
 *
 * Funkce pouze vrati hodnotu pole Flags struktury OBJECT_HEADER.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vrati hodnotu pole Flags ve strukture OBJECT_HEADER ciloveho objektu.
 */
ULONG OHGetFlags(PVOID ObjectHeader)
{
  ULONG Ret = (ULONG)-1;
  KdPrint(("object_header.c: OHGetFlags(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KGetFlags(ObjectHeader); break;
    case VERSION_WXP: Ret = OHWXPGetFlags(ObjectHeader); break;
    case VERSION_W2K3: Ret = OHW2K3GetFlags(ObjectHeader); break;
    case VERSION_VISTA: Ret = OHVistaGetFlags(ObjectHeader); break;
    case VERSION_W7: Ret = OHW7GetFlags(ObjectHeader); break;
    default:
      KdPrint(("object_header.c: OHGetFlags(): This system version is not supported.\n"));
      break;
  }

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


/** Funkce vrati odkaz na strukturu obsahujici parametry pouzite pri vytvareni objektu.
 *
 * Rutina funguje pouze na objekty, ktere operacni system prave vytvari. Pro ostatni
 * vraci hodnotu NULL.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Vraci adresu struktury s parametry vytvareni objektu. V pripade, ze objekt
 * jiz prosel celou fazi vytvareni, tato struktura jiz neni v pameti pritomna a funkce
 * vraci hodnotu NULL.
 */
PVOID OHGetObjectCreateInfo(PVOID ObjectHeader)
{
  ULONG Flags = 0;
  PVOID Ret = NULL;
  KdPrint(("object_header.c: OHGetObjectCreateInfo(ObjectHeader=0x%p)\n", ObjectHeader));

  Flags = OHGetFlags(ObjectHeader);
  if (Flags != (ULONG)-1 && (Flags & OB_FLAG_NEW_OBJECT) > 0) {
    switch (VersionCode) {
      case VERSION_W2K: Ret = OHW2KGetObjectCreateInfo(ObjectHeader); break;
      case VERSION_WXP: Ret = OHWXPGetObjectCreateInfo(ObjectHeader); break;
      case VERSION_W2K3: Ret = OHW2K3GetObjectCreateInfo(ObjectHeader); break;
      case VERSION_VISTA: Ret = OHVistaGetObjectCreateInfo(ObjectHeader); break;
      case VERSION_W7: Ret = OHW7GetObjectCreateInfo(ObjectHeader); break;
      default:
        KdPrint(("object_header.c: OHGetObjectCreateInfo(): This system version is not supported.\n"));
        break;
    }
  }

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


/** Funkce vraci adresu popisovace zabezpeceni zadaneho objektu.
 *
 * #param ObjectHeader Adresa hlavicky ciloveho objektu.
 *
 * #return Funkce vrati adresu popisovace zabezpeceni ciloveho objektu. Pokud se objekt
 * nachazi ve fazi vytvareni (coz signalizuje nultym bitem polozky Flags nastavenym na 1),
 * popisovac zabezpeceni neni jeste pritomen a funkce vraci NULL.
 */
PSECURITY_DESCRIPTOR OHGetSecurityDescriptor(PVOID ObjectHeader)
{
  ULONG Flags = 0;
  PSECURITY_DESCRIPTOR Ret = NULL;
  KdPrint(("object_header.c: OHGetSecurityDescriptor(ObjectHeader=0x%p)\n", ObjectHeader));

  Flags = OHGetFlags(ObjectHeader);
  if (Flags != (ULONG)-1 && (Flags & OB_FLAG_NEW_OBJECT) == 0) {
    switch (VersionCode) {
      case VERSION_W2K: Ret = OHW2KGetSecurityDescriptor(ObjectHeader); break;
      case VERSION_WXP: Ret = OHWXPGetSecurityDescriptor(ObjectHeader); break;
      case VERSION_W2K3: Ret = OHW2K3GetSecurityDescriptor(ObjectHeader); break;
      case VERSION_VISTA: Ret = OHVistaGetSecurityDescriptor(ObjectHeader); break;
      case VERSION_W7: Ret = OHW7GetSecurityDescriptor(ObjectHeader); break;
      default:
        KdPrint(("object_header.c: OHGetSecurityDescriptor(): This system version is not supported.\n"));
        break;
    }
  }

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


/** Funkce vraci hodnotu InfoMask.
 *
 * Funkce na windows 7 vraci hodnotu polozky InfoMask struktury OBJECT_HEADER. Tato
 * hodnota se spolu s polem ObpInfoMaskToOffset pouziva k urceni pritomnosti a offsetu
 * jednotlivych podhlavicek objektu. Na Starsich verzich Windows funkce vzdy vraci -1,
 * protoze se dana polozka v hlavicce objektu nenachazi.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vraci hodnotu polozky InfoMask v hlavicce objektu. Na Windows 7 by mela
 * vzdy uspet a vratit platnou hodnotu. Na starsich verzich Windows vraci vzdy hodnotu -1.
 */
ULONG OHGetInfoMask(PVOID ObjectHeader)
{
  ULONG Ret = (ULONG)-1;
  KdPrint(("object_header.c: OHGetInfoMask(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W7: Ret = OHW7GetInfoMask(ObjectHeader) & 0xFF; break;
    default:
      KdPrint(("object_header.c: OHGetInfoMask(): This system version is not supported.\n"));
      break;
  }

  KdPrint(("object_header.c: OHGetInfoMask(-):0x%x\n", ObjectHeader));
  return Ret;
}


/** Vrati offset podhlavicky OBJECT_HEADER_PROCESS_INFO.
 *
 * Tato podhlavicka se nachazi pouze na Windows 7 a novejsich verzich operacniho systemu.
 * Obsahuje odkaz na exklizivni proces objektu. Na starsich verzich Windows se tato
 * struktura nevyskytuje, a proto funkce vraci v tomto pripade hodnotu 0.
 *
 * Vracenz offset je treba odecist od pocatku strukturz OBJECT_HEADER, aby volajici
 * ziskal adresu podhlavicky OBJECT_HEADER_PROCESS_INFO.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Vraci offset podhlavicky OBJECT_HEADER_PROCESS_INFO vzhledem k hlavicce objektu.
 * V pripade, ze je vyvolana na starsich Windows nez Windows 7, funkce vraci vzdy nulu.
 * Nulu vraci take v pripade, ze dany objekt tuto podhlavicku neobsahuje.
 */
ULONG OHGetProcessInfoOffset(PVOID ObjectHeader)
{
  ULONG InfoMask = 0;
  ULONG Ret = (ULONG)0;
  KdPrint(("object_header.c: OHGetProcessInfoOffset(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W7: 
      InfoMask = OHGetInfoMask(ObjectHeader);
      if ((InfoMask & INFOMASK_HEADER_PROCESS_INFO) > 0)
        Ret = OHW7GetProcessInfoOffset(ObjectHeader); 
      break;
    default:
      Ret = 0;
      break;
  }
  
  KdPrint(("object_header.c: OHGetProcessInfoOffset(-):%u\n", Ret));
  return Ret;
}


/** Vraci offset hlavicky OBJECT_HEADER_CREATOR_INFO.
 *
 * Pokud objekt touto hlavicou disponuje, jeji offset je vzdy 0x10, tedy nachazi se
 * ihned pred strukturou OBJECT_HEADER. Na Windows Vista a starsich systemech lze pritomnost
 * teto hlavicky detekovat diky priznaku OB_FLAG_CREATOR_INFO v polozce Flags struktury
 * OBJECT_HEADER. Na Windows 7 je nutne podivat se na nulty bit polozky InfoMask.
 *
 * Podhlavicka OBJECT_HEADER_CREATOR_INFO obsahuje informace o tom, kdo dany objekt
 * vytvoril. Dale obsahuje odkaz na spojovy seznam vsech objektu daneho typu.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 *
 * @return Funkce vraci offset podhlavicky OBJECT_HEADER_CREATOR_INFO relativni vzhledem
 * k zacatku (az na znamenko) struktury OBJECT_HEADER. Pokud objekt touto hlavickou nedisponuje,
 * funkce vrati nulu. Pro ziskani adresy podhlavicky je nutne offset odecist od adresy struktury
 * hlavicky objektu.
 */
ULONG OHGetCreatorInfoOffset(PVOID ObjectHeader)
{
  ULONG Flags = 0;
  ULONG InfoMask = 0;
  ULONG Ret = 0;
  KdPrint(("object_header.c: OHGetCreatorInfoOffset(ObjectHeader=0x%p)\n", ObjectHeader));

  switch (VersionCode) {
    case VERSION_W2K:
    case VERSION_WXP:
    case VERSION_W2K3:
    case VERSION_VISTA:
      Flags = OHGetFlags(ObjectHeader);
      if ((Flags & OB_FLAG_CREATOR_INFO) > 0)
        Ret = 0x10;

      break;
    case VERSION_W7:
      InfoMask = OHGetInfoMask(ObjectHeader);
      if ((InfoMask & INFOMASK_HEADER_CREATOR_INFO) > 0)
        Ret = 0x10;

      break;
    default:
      KdPrint(("object_header.c: OHGetCreatorInfoOffset(): This version of Windows is not supported.\n"));
      break;
  }

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


/** Vraci adresu zadane podhlavicky daneho objektu.
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 * @param HeaderType Specifikuje typ podhlavicky, jejiz adresu si volajici preje ziskat.
 *   @value OB_HEADER_NAME_INFO Podhlavicka OBJECT_HEADER_NAME_INFO
 *   @value OB_HEADER_HANDLE_INFO Podhlavicka OBJECT_HEADER_HANDLE_INFO
 *   @value OB_HEADER_QUOTA_INFO Podhlavicka OBJECT_HEADER_QUOTA_INFO
 *   @value OB_HEADER_CREATOR_INFO Podhlavicka OBJECT_HEADER_CREATOR_INFO
 *   @value OB_HEADER_PROCESS_INFO Podhlavicka OBJECT_HEADER_PROCESS_INFO (pouze Windows 7).
 *
 * @return Funkce vraci adresu zadane podhlavicky zadaneho objektu. Pokud objekt takovou
 * podhlavicku nema, funkce vrati hodnotu NULL.
 */
PVOID OHGetInfoHeader(PVOID ObjectHeader, ULONG HeaderType)
{
  PVOID Ret = NULL;
  ULONG Offset = 0;
  KdPrint(("object_header.c: OHGetInfoHeader(ObjectHeader=0x%p; HeaderType=%u)\n", ObjectHeader, HeaderType));

  switch (HeaderType) {
    case OH_HEADER_NAME_INFO: Offset = OHGetNameInfoOffset(ObjectHeader); break;
    case OH_HEADER_QUOTA_INFO: Offset = OHGetQuotaInfoOffset(ObjectHeader); break;
    case OH_HEADER_HANDLE_INFO: Offset = OHGetHandleInfoOffset(ObjectHeader); break;
    case OH_HEADER_CREATOR_INFO: Offset = OHGetCreatorInfoOffset(ObjectHeader); break;
    case OH_HEADER_PROCESS_INFO: Offset = OHGetProcessInfoOffset(ObjectHeader); break;
    default:
      KdPrint(("object_header.c: OHGetInfoHeader(): This version of Windows is not supported.\n"));
  }

  if (Offset > 0)
    Ret = (PVOID)((PCHAR)ObjectHeader - Offset);

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


/** Vraci velikost zadane podhlavicky daneho objektu. v bajtech
 *
 * @param ObjectHeader Hlavicka ciloveho objektu.
 * @param HeaderType Specifikuje typ podhlavicky, jejiz velikost si volajici preje ziskat.
 *   @value OB_HEADER_NAME_INFO Podhlavicka OBJECT_HEADER_NAME_INFO
 *   @value OB_HEADER_HANDLE_INFO Podhlavicka OBJECT_HEADER_HANDLE_INFO
 *   @value OB_HEADER_QUOTA_INFO Podhlavicka OBJECT_HEADER_QUOTA_INFO
 *   @value OB_HEADER_CREATOR_INFO Podhlavicka OBJECT_HEADER_CREATOR_INFO
 *   @value OB_HEADER_PROCESS_INFO Podhlavicka OBJECT_HEADER_PROCESS_INFO (pouze Windows 7).
 *
 * @return Funkce vraci adresu velikost podhlavicky zadaneho objektuv bajtech. 
 * Pokud objekt takovou podhlavicku nema, funkce vrati nulu.
 */
ULONG OHGetInfoHeaderSize(PVOID ObjectHeader, ULONG HeaderType)
{
  ULONG Ret = 0;
  KdPrint(("object_header.c: OHGetInfoHeaderSize(ObjectHeader=0x%p; HeaderType=%u)\n", ObjectHeader, HeaderType));

  switch (VersionCode) {
    case VERSION_W2K: {
      switch (HeaderType) {
        case OH_HEADER_NAME_INFO: Ret = sizeof(OBJECT_HEADER_NAME_INFO_W2K); break;
        case OH_HEADER_HANDLE_INFO: Ret = sizeof(OBJECT_HEADER_HANDLE_INFO); break;
        case OH_HEADER_QUOTA_INFO: Ret = sizeof(OBJECT_HEADER_QUOTA_INFO_W2K); break;
        case OH_HEADER_CREATOR_INFO: Ret = sizeof(OBJECT_HEADER_CREATOR_INFO_W2K); break;
        case OH_HEADER_PROCESS_INFO: Ret = 0; break;
        default:
          KdPrint(("object_header.c: OHGetInfoHeaderSize(): This info header is not supported.\n"));
          break;
      }
    }

    case VERSION_WXP: {
      switch (HeaderType) {
        case OH_HEADER_NAME_INFO: Ret = sizeof(OBJECT_HEADER_NAME_INFO_WXP); break;
        case OH_HEADER_HANDLE_INFO: Ret = sizeof(OBJECT_HEADER_HANDLE_INFO); break;
        case OH_HEADER_QUOTA_INFO: Ret = sizeof(OBJECT_HEADER_QUOTA_INFO_WXP); break;
        case OH_HEADER_CREATOR_INFO: Ret = sizeof(OBJECT_HEADER_CREATOR_INFO_WXP); break;
        case OH_HEADER_PROCESS_INFO: Ret = 0; break;
        default:
          KdPrint(("object_header.c: OHGetInfoHeaderSize(): This info header is not supported.\n"));
          break;
      }
    }

    case VERSION_W2K3: {
      switch (HeaderType) {
        case OH_HEADER_NAME_INFO: Ret = sizeof(OBJECT_HEADER_NAME_INFO_W2K3); break;
        case OH_HEADER_HANDLE_INFO: Ret = sizeof(OBJECT_HEADER_HANDLE_INFO); break;
        case OH_HEADER_QUOTA_INFO: Ret = sizeof(OBJECT_HEADER_QUOTA_INFO_W2K3); break;
        case OH_HEADER_CREATOR_INFO: Ret = sizeof(OBJECT_HEADER_CREATOR_INFO_W2K3); break;
        case OH_HEADER_PROCESS_INFO: Ret = 0; break;
        default:
          KdPrint(("object_header.c: OHGetInfoHeaderSize(): This info header is not supported.\n"));
          break;
      }
    }

    case VERSION_VISTA: {
      switch (HeaderType) {
        case OH_HEADER_NAME_INFO: Ret = sizeof(OBJECT_HEADER_NAME_INFO_VISTA); break;
        case OH_HEADER_HANDLE_INFO: Ret = sizeof(OBJECT_HEADER_HANDLE_INFO); break;
        case OH_HEADER_QUOTA_INFO: Ret = sizeof(OBJECT_HEADER_QUOTA_INFO_VISTA); break;
        case OH_HEADER_CREATOR_INFO: Ret = sizeof(OBJECT_HEADER_CREATOR_INFO_VISTA); break;
        case OH_HEADER_PROCESS_INFO: Ret = 0; break;
        default:
          KdPrint(("object_header.c: OHGetInfoHeaderSize(): This info header is not supported.\n"));
          break;
      }
    }

    case VERSION_W7: {
      switch (HeaderType) {
        case OH_HEADER_NAME_INFO: Ret = sizeof(OBJECT_HEADER_NAME_INFO_W7); break;
        case OH_HEADER_HANDLE_INFO: Ret = sizeof(OBJECT_HEADER_HANDLE_INFO); break;
        case OH_HEADER_QUOTA_INFO: Ret = sizeof(OBJECT_HEADER_QUOTA_INFO_W7); break;
        case OH_HEADER_CREATOR_INFO: Ret = sizeof(OBJECT_HEADER_CREATOR_INFO_W7); break;
        case OH_HEADER_PROCESS_INFO: Ret = sizeof(OBJECT_HEADER_PROCESS_INFO_W7); break;
        default:
          KdPrint(("object_header.c: OHGetInfoHeaderSize(): This info header is not supported.\n"));
          break;
      }
    }
  }

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


/** Vraci adresu hlavicky objektu, tedy adresu struktury OBJECT_HEADER.
 *
 * @param Object Adresa tela objektu, jehoz hlavicku volajici pozaduje.
 *
 * @return Funkce vraci adresu hlavicky (struktury OBJECT_HEADER) pro dany objekt. Funkce
 * by nikdy nemela selhat.
 */
PVOID OHGetObjectHeader(PVOID Object)
{
  PVOID Ret = NULL;
  KdPrint(("object_header.c: OHGetObjectHeader(Object=0x%p)\n", Object));

  switch (VersionCode) {
    case VERSION_W2K: Ret = (PVOID)((PCHAR)Object - sizeof(OBJECT_HEADER_W2K)); break;
    case VERSION_WXP: Ret = (PVOID)((PCHAR)Object - sizeof(OBJECT_HEADER_WXP)); break;
    case VERSION_W2K3: Ret = (PVOID)((PCHAR)Object - sizeof(OBJECT_HEADER_W2K3)); break;
    case VERSION_VISTA: Ret = (PVOID)((PCHAR)Object - sizeof(OBJECT_HEADER_VISTA)); break;
    case VERSION_W7: Ret = (PVOID)((PCHAR)Object - sizeof(OBJECT_HEADER_W7)); break;
    default:
      KdPrint(("object_header.c: OHGetObjectHeader(): This version of Windows is not supported.\n"));
      break;
  }

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


/** Vraci hodnotu polozky Directory ve strukture OBJECT_HEADER_NAME_INFO.
 *
 * Funkce nezvysuje nalezenemu objektu adresare pocet referenci.
 *
 * @param InfoHeader Adresa struktury OBJECT_HEADER_NAME_INFO.
 *
 * @return Vraci adresu tela objektu adresare, do ktereho objekt patri.
 */
PVOID OHNameInfoGetDirectory(PVOID InfoHeader)
{
  PVOID Ret = NULL;

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KNameInfoGetDirectory(InfoHeader);  break;
    case VERSION_WXP: Ret = OHWXPNameInfoGetDirectory(InfoHeader); break;
    case VERSION_W2K3: Ret = OHW2K3NameInfoGetDirectory(InfoHeader); break;
    case VERSION_VISTA: Ret = OHVistaNameInfoGetDirectory(InfoHeader); break;
    case VERSION_W7: Ret = OHW7NameInfoGetDirectory(InfoHeader); break;
    default:
      break;
  }

  return Ret;
}


/** Funkce vraci adresu struktury UNICODE_STRING, ktera obsahuje jmeno objektu.
 *
 * Rutina se strukturou UNICODE_STRING neprovadi zadne operace. Nedochazi k zadnym
 * hlubokym kopiim.
 *
 * @param InfoHeader Adresa hlavicky OBJECT_HEADER_NAME_INFO.
 *
 * @return Funkce vraci adresu struktury UNICODE_STRING, ktera uchovava jmeno objektu.
 */
PUNICODE_STRING OHNameInfoGetName(PVOID InfoHeader)
{
  PUNICODE_STRING Ret = NULL;

  switch (VersionCode) {
    case VERSION_W2K: Ret = &((POBJECT_HEADER_NAME_INFO_W2K)InfoHeader)->Name; break;
    case VERSION_WXP: Ret = &((POBJECT_HEADER_NAME_INFO_WXP)InfoHeader)->Name; break;
    case VERSION_W2K3: Ret = &((POBJECT_HEADER_NAME_INFO_W2K3)InfoHeader)->Name; break;
    case VERSION_VISTA: Ret = &((POBJECT_HEADER_NAME_INFO_VISTA)InfoHeader)->Name; break;
    case VERSION_W7: Ret = &((POBJECT_HEADER_NAME_INFO_W7)InfoHeader)->Name; break;
    default:
      break;
  }

  return Ret;
}


/** Funkce vraci hodnotu polozky PagedPoolCharge z podhlavicky OBJECT_HEADER_QUOTA_INFO.
 *
 * @param InfoHeader Adresa hlavicky OBJECT_HEADER_QUOTA_INFO ciloveho objektu.
 *
 * @return Funkce vraci hodnotu polozky PagedPoolCharge struktury OBJECT_HEADER_QUOTA_INFO.
 */
ULONG32 OHQuotaInfoGetPagedPoolCharge(PVOID InfoHeader)
{
  ULONG32 Ret = 0;

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KQuotaInfoGetPagedPoolCharge(InfoHeader);  break;
    case VERSION_WXP: Ret = OHWXPQuotaInfoGetPagedPoolCharge(InfoHeader); break;
    case VERSION_W2K3: Ret = OHW2K3QuotaInfoGetPagedPoolCharge(InfoHeader); break;
    case VERSION_VISTA: Ret = OHVistaQuotaInfoGetPagedPoolCharge(InfoHeader); break;
    case VERSION_W7: Ret = OHW7QuotaInfoGetPagedPoolCharge(InfoHeader); break;
    default:
      break;
  }

  return Ret;
}


/** Funkce vraci hodnotu polozky NonPagedPoolCharge z podhlavicky OBJECT_HEADER_QUOTA_INFO.
 *
 * @param InfoHeader Adresa hlavicky OBJECT_HEADER_QUOTA_INFO ciloveho objektu.
 *
 * @return Funkce vraci hodnotu polozky NonPagedPoolCharge struktury OBJECT_HEADER_QUOTA_INFO.
 */
 ULONG32 OHQuotaInfoGetNonPagedPoolCharge(PVOID InfoHeader)
{
  ULONG32 Ret = 0;

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KQuotaInfoGetNonPagedPoolCharge(InfoHeader); break;
    case VERSION_WXP: Ret = OHWXPQuotaInfoGetNonPagedPoolCharge(InfoHeader); break;
    case VERSION_W2K3: Ret = OHW2K3QuotaInfoGetNonPagedPoolCharge(InfoHeader); break;
    case VERSION_VISTA: Ret = OHVistaQuotaInfoGetNonPagedPoolCharge(InfoHeader); break;
    case VERSION_W7: Ret = OHW7QuotaInfoGetNonPagedPoolCharge(InfoHeader);  break;
    default:
      break;
  }

  return Ret;
}


/** Funkce vraci hodnotu polozky SecurityDescriptorCharge z podhlavicky OBJECT_HEADER_QUOTA_INFO.
 *
 * @param InfoHeader Adresa hlavicky OBJECT_HEADER_QUOTA_INFO ciloveho objektu.
 *
 * @return Funkce vraci hodnotu polozky SecurityDescriptorCharge struktury OBJECT_HEADER_QUOTA_INFO.
 */
ULONG32 OHQuotaInfoGetSecurityDescriptorCharge(PVOID InfoHeader)
{
  ULONG32 Ret = 0;

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KQuotaInfoGetSecurityDescriptorCharge(InfoHeader); break;
    case VERSION_WXP: Ret = OHWXPQuotaInfoGetSecurityDescriptorCharge(InfoHeader); break;
    case VERSION_W2K3: Ret = OHW2K3QuotaInfoGetSecurityDescriptorCharge(InfoHeader); break;
    case VERSION_VISTA: Ret = OHVistaQuotaInfoGetSecurityDescriptorCharge(InfoHeader); break;
    case VERSION_W7: Ret = OHW7QuotaInfoGetSecurityDescriptorCharge(InfoHeader); break;
    default:
      break;
  }

  return Ret;
}


/** Funkce vraci PID procesu, ktery dany objekt vytvoril. Funkce pouze zkopiruje hodnotu
 * CreatorUniqueProcessId z podhlavicky OBJECT_HEADER_CREATOR_INFO.
 *
 * @param InfoHeader Adresa podhlavicky OBJECT_HEADER_CREATOR_INFO.
 *
 * @return Funkce vraci hodnotu polozky CreatorUniqueProcessId struktury OBJECT_HEADER_CREATOR_INFO.
 */
HANDLE OHCreatorInfoGetCreatorUniqueProcessId(PVOID InfoHeader)
{
  HANDLE Ret = NULL;

  switch (VersionCode) {
    case VERSION_W2K: Ret = OHW2KCreatorInfoGetCreatorUniqueProcess(InfoHeader); break;
    case VERSION_WXP: Ret = OHWXPCreatorInfoGetCreatorUniqueProcess(InfoHeader); break;
    case VERSION_W2K3: Ret = OHW2K3CreatorInfoGetCreatorUniqueProcess(InfoHeader); break;
    case VERSION_VISTA: Ret = OHVistaCreatorInfoGetCreatorUniqueProcess(InfoHeader); break;
    case VERSION_W7: Ret = OHW7CreatorInfoGetCreatorUniqueProcess(InfoHeader); break;
    default:
      break;
  }

  return Ret;
}


/** Funkce vraci exklizivni proces daneho objektu.
 *
 * Rutina vraci adresu tela procesu, ktery plni roli exklizivniho procesu pro dany objekt.
 * Pokud dany objekt (aktualne, nebo vubec) nema exklizivni proces, funkce vrati hodnotu
 * NULL.
 *
 * @param Header Adresa hlavicky ciloveho objektu.
 *
 * @return Funkce vrati adresu tela exkluzivniho procesu pro objekt, nebo hodnotu NULL.
 */
PEPROCESS OHGetEcxlusiveProcess(PVOID Header)
{
  ULONG Flags = 0;
  PVOID InfoMask = NULL;
  PEPROCESS Ret = NULL;

  Flags = OHGetFlags(Header);
  if ((Flags & OB_FLAG_EXCLUSIVE_OBJECT) > 0) {
    switch (VersionCode) {
      case VERSION_W2K:
      case VERSION_WXP:
      case VERSION_W2K3:
      case VERSION_VISTA: 
        InfoMask = OHGetInfoHeader(Header, OH_HEADER_QUOTA_INFO);
        if (InfoMask != NULL) {
          switch (VersionCode) {
            case VERSION_W2K: Ret = OHW2KQuotaInfoGetExclusiveProcess(InfoMask);  break;
            case VERSION_WXP: Ret = OHWXPQuotaInfoGetExclusiveProcess(InfoMask); break;
            case VERSION_W2K3: Ret = OHW2K3QuotaInfoGetExclusiveProcess(InfoMask); break;
            case VERSION_VISTA: Ret = OHVistaQuotaInfoGetExclusiveProcess(InfoMask); break;
          }
        }

        break;

      case VERSION_W7:
        InfoMask = OHGetInfoHeader(Header, OH_HEADER_PROCESS_INFO); 
        if (InfoMask != NULL)
          Ret = OHW7ProcessInfoGetExclusiveProcess(InfoMask);
        break;

      default:
        break;
	}
  }

  return Ret;
}



/** Provadi inicializaci modulu pro praci s hlavickami a podhlavickami objektu.
 *
 * Na Windows starsich nez Windows 7 rutina pouze naplni promennou VersionCode cislem
 * verze operacniho systemu, na kterem ovladac bezi. Na Windows 7 take najde adresy
 * pole ObpTypeIndexTable a ObpInfoMaskToOffset.
 *
 * @return Rutina vraci hodnotu NTSTATUS, ktera indikuje jeji uspech ci neuspech.
 */
NTSTATUS OHInit(VOID)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("object_header.c: OHInit()\n"));

  VersionCode = GetVersionCode();
  if (VersionCode != VERSION_UNKNOWN) {
    Status = STATUS_SUCCESS;
    if (VersionCode == VERSION_W7) {
      Status = OHFindObpInfoMaskToOffset();
      if (NT_SUCCESS(Status))
        Status = OHFindObpTypeIndexTable();
    }
  } else Status = STATUS_NOT_SUPPORTED;

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


/** Provede uklid po modulu pro praci s hlavickami objektu.
 *
 * Jelikoz tento modul nijak nezasahuje do datovych struktur spravce objektu ani do jadra,
 * rutina neprovadi nic.
 */
VOID OHFinit(VOID)
{
  KdPrint(("object_header.c: OHInit()\n"));

  KdPrint(("object_header.c: OHFinit(-)\n"));
  return;
}
