
/**
 * @file: main.c
 *
 * Hlavni soubor programu Ntqueryobject, ktery slouzi k zistakvani ruznych
 * informaci a udaju o objektech exekutivy. Program k tomuto ucelu vyuziva
 * nativni funkci NtQueryObject.
 *
 * Syntax:
 *  ntqueryobject --get-info <PID> <Handle>  Zjisti informace o objektu,
 *                                           na ktery odkazuje handle 
 *                                           <Handle> v procesu s ID <PID>
 *  ntqueryobject --list-types               Vypise ruzne informace a
 *                                           statistiky o jednotlivych
 *                                           typech objektu.
 *  ntqueryobject --list-handles <PID>       Vypise seznam handle patrici
 *                                           procesu s ID <PID>.
 */

#include <stdio.h>
#include <windows.h>
#include "..\shared\common.h"
#include "queryobject.h"


/** Vypise seznam handle zadaneho procesu.
 *
 *  @param TargetProcess PID ciloveho procesu.
 */
VOID ListHandles(IN DWORD TargetProcess)
{
  HANDLE hObject = NULL;
  LONG i = 0;
  PSYSTEM_HANDLE_INFORMATION_EX shi = NULL;
  POBJECT_BASIC_INFORMATION obi = NULL;
  POBJECT_TYPE_INFORMATION oti = NULL;
  POBJECT_NAME_INFORMATION oni = NULL;
  BOOL Res = FALSE;
  HANDLE hTarget = NULL;
  DebugMsg(("ListHandles(TargetProcess=%u)\n", TargetProcess));

  hTarget = OpenTargetProcess(TargetProcess);
  if (hTarget != NULL) {
    Res = EnumHandles(&shi);
    if (Res) {
      for (i = 0; i < (LONG)shi->NumberOfHandles; ++i) {
        if (shi->Handles[i].UniqueProcessId != TargetProcess)
          continue;

        hObject = DuplicateObject(hTarget, (HANDLE)shi->Handles[i].HandleValue);
        Res = hObject != NULL;
        if (Res) {
          Res = QueryObjectInfo(hObject, &obi, &oti, &oni);
          if (Res) {
            printf("0x%p: %S %S\n", shi->Handles[i].HandleValue, oti->TypeName.Buffer, oni->Name.Buffer);
            FreeMem(obi);
            FreeMem(oti);
            FreeMem(oni);
           } else printf("Nepodarilo se ziskat informace o handle %u:0x%p\n", TargetProcess, shi->Handles[i].HandleValue);
		
		  CloseHandle(hObject);
        } else printf("Nepodarilo se duplikovat handle %u:0x%p\n", TargetProcess, shi->Handles[i].HandleValue);
      }

      FreeMem(shi);
    } else printf("Nepodarilo se ziskat seznam handle\n");

    CloseTargetProcess(hTarget);
  } else printf("Nepodarilo se ziskat pristup k procesu %u\n", TargetProcess);

  DebugMsg(("ListHandles(-)\n"));
  return;
}


/** Vypise informace o typu objektu (ze struktury OBJECT_TYPE_INFORMATION).
 *
 *  @param TypeInfo Adresa struktury OBJECT_TYPE_INFORMATION, jejiz obsah
 *  si volajici preje zobrazit.
 */
VOID PrintTypeInformation(POBJECT_TYPE_INFORMATION TypeInfo)
{
  DebugMsg(("PrintTypeInformation(TypeInfo=0x%p)\n", TypeInfo));

  printf("Nazev typu:                            %S\n", TypeInfo->TypeName.Buffer);
  printf("Celkovy pocet objektu:                 %u\n", TypeInfo->TotalNumberOfObjects);
  printf("Max. pocet objektu:                    %u\n", TypeInfo->HighWaterNumberOfObjects);
  printf("Celkovy pocet handle:                  %u\n", TypeInfo->TotalNumberOfHandles);
  printf("HMax. pocet handle:                    %u\n", TypeInfo->HighWaterNumberOfHandles);
  printf("Uziti strankovaneho fondu:             %u\n", TypeInfo->DefaultPagedPoolCharge);
  printf("Uziti nestrankovaneho fondu:           %u\n", TypeInfo->DefaultNonPagedPoolCharge);
  printf("Uzivany pametovy fond:                 %u\n", TypeInfo->PoolType);
  printf("Vyuziti tabulek handle:                %u\n", TypeInfo->TotalHandleTableUsage);
  printf("Max. vyuziti tabulek handle:           %u\n", TypeInfo->HighWaterHandleTableUsage);
  printf("Celkove vyuziti strankovaneho fondu:   %u\n", TypeInfo->TotalPagedPoolUsage);
  printf("Max. vyuziti strankovaneho fondu:      %u\n", TypeInfo->HighWaterPagedPoolUsage);
  printf("Celkove vyuziti nestrankovaneho fondu: %u\n", TypeInfo->TotalNonPagedPoolUsage);
  printf("Max. vyuziti nestrankovaneho fondu:    %u\n", TypeInfo->HighWaterNonPagedPoolUsage);
  printf("Vyuziti pameti pro jmena:              %u\n", TypeInfo->TotalNamePoolUsage);
  printf("Max. vyuziti pameti pro jmena:         %u\n", TypeInfo->HighWaterNamePoolUsage);

  DebugMsg(("PrintTypeInformation(-)\n"));
  return;
}


/** Vypise zakladni informace o objektu (ze struktury OBJECT_BASIC_INFORMATION).
 *
 *  @param BasicInfo Adresa struktury OBJECT_BASIC_INFORMATION, jejiz
 *  obsah chce volajici zobrazit.
 */
VOID PrintBasicInformation(POBJECT_BASIC_INFORMATION BasicInfo)
{
  DebugMsg(("PrintBasicInformation(BasicInfo=0x%p)\n", BasicInfo));

  printf("Atributy:             0x%x\n", BasicInfo->Attributes);
  printf("Pristupova parava:    0x%x\n", BasicInfo->GrantedAccess);
  printf("Pocet handle:         %u\n", BasicInfo->HandleCount);
  printf("Pocet odkazu:         %u\n", BasicInfo->PointerCount);
  printf("Strankkovany fond:    %u\n", BasicInfo->PagedPoolCharge);
  printf("Nestrankovany fond:   %u\n", BasicInfo->NonPagedPoolCharge);

  DebugMsg(("PrintBasicInformation(-)\n"));
  return;
}


/** Zobrazi jmeno objektu ulozene ve struktury OBJECT_NAME_INFORMATION.
 *
 *  @param NameInfo Adresa struktury OBJECT_NAME_INFORMATION, jejiz obsah
 *  si volajici preje zobrazit.
 */
VOID PrintNameInformation(POBJECT_NAME_INFORMATION NameInfo)
{
  DebugMsg(("PritNameInformation(NameInfo=0x%p)\n", NameInfo));

  printf("Jmeno:       %S\n", NameInfo->Name.Buffer);

  DebugMsg(("PritNameInformation(-)\n"));
  return;
}


/** Zobrazi informace o zadanem objektu exekutivy.
 *
 *  @param TargetProcess PID procesu, ktery handle vedouci na objekt 
 *  vlastni.
 *  @param ObjectHandle Hodnota handle ciloveho objektu v kontextu daneho
 *  procesu.
 */
VOID PrintObjectInfo(DWORD TargetProcess, HANDLE ObjectHandle)
{
  BOOL Res = FALSE;
  HANDLE hObject = NULL;
  HANDLE hTarget = NULL;
  POBJECT_BASIC_INFORMATION obi;
  POBJECT_TYPE_INFORMATION oti;
  POBJECT_NAME_INFORMATION oni;
  DebugMsg(("PrintObjectInfo(TargetProcess=%u; ObjectHandle=0x%p)\n", TargetProcess, ObjectHandle));

  hTarget = OpenTargetProcess(TargetProcess);
  if (hTarget != NULL) {
    hObject = DuplicateObject(hTarget, ObjectHandle);
    Res = hObject != NULL;
    if (Res) {
      Res = QueryObjectInfo(hObject, &obi, &oti, &oni);
      if (Res) {
        printf("PID procesu:      %u\n", TargetProcess);
		printf("Handle:           0x%x\n", ObjectHandle);
		printf("\n");
		printf("Zakladni udaje\n");
        printf("========================================\n");
        PrintBasicInformation(obi);
		printf("\n");
		printf("Informace o typu objektu\n");
        printf("========================================\n");
		PrintTypeInformation(oti);
		printf("\n");
		printf("Jmeno objektu\n");
        printf("========================================\n");
		PrintNameInformation(oni);
        FreeMem(obi);
        FreeMem(oti);
        FreeMem(oni);
      } else printf("Nepodarilo se ziskat informace o handle %u:0x%p\n", TargetProcess, ObjectHandle);
		
      CloseHandle(hObject);
    } else printf("Nepodarilo se duplikovat handle %u:0x%p\n", TargetProcess, ObjectHandle);

    CloseTargetProcess(hTarget);
  } else printf("Nepodarilo se ziskat pristup k procesu %u\n", TargetProcess);

  DebugMsg(("PrintObjectInfo(-)\n"));
  return;
}


/** Zobrazi informace a statistiky o vsech typech objektu.
 */
VOID ListTypes(VOID)
{
  LONG i = 0;
  BOOL Res = FALSE;
  POBJECT_TYPE_INFORMATION TypeInfo = NULL;
  POBJECT_TYPES_INFORMATION TypesInfo = NULL;
  DebugMsg(("ListTypes()\n"));
  
  Res = QueryObjectTypesInfo(&TypesInfo);
  if (Res) {
    printf("Pocet druhu objektu: %u\n", TypesInfo->NumberOfTypes);
    printf("=====================================\n");
    TypeInfo = (POBJECT_TYPE_INFORMATION)((PCHAR)TypesInfo + ALIGN_UP(sizeof(*TypesInfo), ULONG_PTR));
    for (i = 0; i < TypesInfo->NumberOfTypes; ++i) {
      PrintTypeInformation(TypeInfo);
      printf("\n");
	  TypeInfo = (POBJECT_TYPE_INFORMATION)((PCHAR)(TypeInfo + 1) + ALIGN_UP(TypeInfo->TypeName.MaximumLength, ULONG_PTR));
    }

    FreeMem(TypesInfo);
  } else printf("Nepodarilo se ziskat informace o typech objektu\n");

  DebugMsg(("ListTypes(-)\n"));
  return;
}



/** Hlavni funkce programu. Na zaklade argumentu prikazove radky
 *  vypise urcite informace o objektu (objektech) exekutivy.
 *
 * @param argc Pocet argumentu prikazove radky (vcetne nazvu souboru).
 * @param argv Pole retezcu argumentu prikazove radky.
 */
int main(int argc, char **argv)
{
  BOOL Ret = FALSE;
  DWORD PID = 0;
  HANDLE Handle = 0;
  PCHAR HandleStr = 0;
  PCHAR PIDStr = NULL;
  PCHAR Command = NULL;

  Ret = CommonInit();
  if (Ret) {
    Ret = QueryObjectInit();
    if (Ret) {
      switch (argc) {
	    case 4:
          Command = argv[1];
		  PIDStr = argv[2];
		  PID = strtol(PIDStr, NULL, 0);
		  HandleStr = argv[3];
		  Handle = (HANDLE)strtol(HandleStr, NULL, 0);
          if (strncmp(Command, "--get-info", strlen("--get-info")) == 0)
            PrintObjectInfo(PID, Handle);
          break;

	    case 3:
          Command = argv[1];
		  PIDStr = argv[2];
		  PID = strtol(PIDStr, NULL, 0);
          if (strncmp(Command, "--list-handles", strlen("--list-handles")) == 0)
            ListHandles(PID);
          break;

	    case 2:
          Command = argv[1];
          if (strncmp(Command, "--list-types", strlen("--list-types")) == 0)
            ListTypes();
		  break;
      }

      QueryObjectFinit();
	} else printf("Pri inicializaci doslo k chybe\n");

    CommonFinit();
  } else printf("Pri inicializaci doslo k chybe\n");

  return 0;
}
