
/**
 * @file pprocess.c
 *
 * Implementace modulu pro praci s chranenymi procesy.
 */

#include <ntifs.h>
#include "version.h"
#include "pprocess.h"


// Uchovava offset pole Flags2 (kde je i priznak rozhodujici o chranenem
// procesu) v ramci struktury EPROCESS
static ULONG EProcessFlags2Offset = 0;

// Pozice priznaku chranenho procesu v poli Flags2 struktury EPROCESS
#define PROTECTED_PROCESS_BIT          11



/** Nastavi bit rozhodujici o chranenem procesu na 1. Cilovy proces se pro
 *  system bude jevit jako chraneny proces.
 *
 *  @param ProcessId PID ciloveho procesu.
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech
 *  operace.
 */
NTSTATUS ProcessProtect(HANDLE ProcessId)
{
  ULONG Value = 0;
  PULONG pflags = NULL;
  PEPROCESS EProc = NULL;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("pprocess.c: ProcessProtect(ProcessId=%u)\n", ProcessId));

  Status = PsLookupProcessByProcessId(ProcessId, &EProc);
  if (NT_SUCCESS(Status)) {
    pflags = (PULONG)((PCHAR)EProc + EProcessFlags2Offset); 
    Value = *pflags;
    Value |= (ULONG_PTR)(1 << PROTECTED_PROCESS_BIT);
    *pflags = Value;
    ObDereferenceObject(EProc);
  }

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


/** Zmeni chraneny proces na nechraneny. Nastavi bit rozhodujici o chranenem
 *  procesu na nulu.
 *
 *  @param ProcessId PID ciloveho procesu.
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.
 */
NTSTATUS ProcessUnprotect(HANDLE ProcessId)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  PEPROCESS EProc = NULL;
  PULONG pflags = NULL;
  ULONG Value = 0;
  KdPrint(("pprocess.c: ProcessUnprotect(ProcessId=%u)\n", ProcessId));

  Status = PsLookupProcessByProcessId(ProcessId, &EProc);
  if (NT_SUCCESS(Status)) {
    pflags = (PULONG)((PCHAR)EProc + EProcessFlags2Offset); 
    Value = *pflags;
    Value &= (ULONG_PTR) ~(1 << PROTECTED_PROCESS_BIT);
    *pflags = Value;
    ObDereferenceObject(EProc);
  }

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


/** Zjisti, zda je cilovy proces chraneny proces.
 *
 *  @param ProcessId PID ciloveho procesu.
 *  @param Result Adresa promenne, kam funkce v pripade uspechu zapise TRUE,
 *  pokud je cilovy proces chraneny proces a FALSE, pokud chraneny neni.
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.  
 */
NTSTATUS ProcessIsProtected(HANDLE ProcessId, PBOOLEAN Result)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  PEPROCESS EProc = NULL;
  PULONG pflags = NULL;
  KdPrint(("pprocess.c: ProcessIsProtected(ProcessId=%u; Result=0x%p)\n", ProcessId, Result));

  Status = PsLookupProcessByProcessId(ProcessId, &EProc);
  if (NT_SUCCESS(Status)) {
    pflags = (PULONG)((PCHAR)EProc + EProcessFlags2Offset); 
    *Result = ((*pflags & (1 << PROTECTED_PROCESS_BIT)) != 0);
    ObDereferenceObject(EProc);
  }

  KdPrint(("pprocess.c: ProcessIsProtected(-):0x%x, *Result=%u\n", Status, *Result));
  return Status;
}


/** Inicializuje modul pro praci s chranenymi procesy.
 *
 *  Funkce na zaklade verze OS zjisti offset pole Flags2 v ramci
 *  struktury EPROCESS.
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neupsech
 *  operace.
 */
NTSTATUS PProcessInit(VOID)
{
  ULONG VersionCode = VERSION_UNKNOWN;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("pprocess.c: PProcessInit()\n"));

  if (sizeof(PVOID) == 8) {
    switch (GetVersionCode()) {
      case VERSION_W7:
        EProcessFlags2Offset = 0x43c;
        Status=STATUS_SUCCESS;
        break;
  
      case VERSION_VISTA:
        EProcessFlags2Offset = 0x36C;
        Status=STATUS_SUCCESS;
        break;

      default:
        Status = STATUS_NOT_SUPPORTED;
        break;
    }
  } else if (sizeof(PVOID) == 4) {
    switch (GetVersionCode()) {
      case VERSION_VISTA:
        EProcessFlags2Offset = 0x224;
        Status = STATUS_SUCCESS;
        break;

      case VERSION_W7:
        EProcessFlags2Offset = 0x26C;
        Status = STATUS_SUCCESS;
        break;
    }
  } else Status = STATUS_NOT_SUPPORTED;

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

/** Provede uklid po modulu pro praci s chranenymi procesy.
 *
 *  Protoze tento modul behem sve inicializace nijak nezasahuje do
 *  jadra operacniho systemu, rutina nedela nic.
 */
VOID PProcessFinit(VOID)
{
  KdPrint(("pprocess.c: PProcessFinit()\n"));

  KdPrint(("pprocess.c: PProcessFinit(-)\n"));
  return;
}
