
/**
 * @file: main.c
 *
 * Hlavni soubor programu Dllhide. Obsahuje veskery kod nutny pro plne fungovani
 * programu. Duvodem umisteni vseho (az na nekolik definic) do jednoho .c souboru
 * je male mnozstvi kodu a celkova jednoduchost celeho programu.
 *
 * Program Dllhide se pokusi pomoci manipulaci se strukturou Bloku prostredi
 * procesu skryt vsechny informace o svem hlavnim modulu. Kryti je efektivni
 * proti aplikace ListDll pri pouziti metod --peb a --toolhelp.
 *
 * Po skryti sveho hlavniho modulu program ceka na libovolnou klavesu a nasledne
 * se sam ukonci.
 *
 * Program nepracuje spravne pod WOW64.
 */

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



/** Zjisti adresu Bloku prostredi procesu.
 *
 *  @return Funkce vrati adresu Bloku prostredi procesu aktualniho procesu. Tuto
 *  informaci vycte ze struktury TEB aktualniho vlakna. Rutina aplikuje ruzne
 *  pristupy podle toho, zda aplikace bezi na 32bitove ci 64bitove verzi OS.
 */
PPEB GetPebAddress(VOID)
{
  PPEB Ret = NULL;
  DebugMsg(("main.c: GetPebAddress()\n"));

  #ifdef _AMD64_
  // Adresa struktury PEB je na GS:[0x60]
  Ret = (PVOID)__readgsqword(0x60);
  #else
  // Adresa struktury PEB je na FS:[0x30]
  Ret = (PVOID)__readfsdword(0x30);
  #endif

  DebugMsg(("main.c: GetPebAddress(-):0x%p\n", Ret));
  return Ret;
}


/** Najde strukturu LDR_DATA_TABLE_ENTRY popisujici modul na zadane virtualni
 *  adrese.
 *
 *  @param ModuleBase Bazova (virtualni) adresa ciloveho modulu.
 *  @param Peb Adresa Bloku prostredi procesu.
 *
 *  @return Funkce vraci adresu struktury LDR_DATA_TABLE_ENTRY popisujici cilovy
 *  modul. V pripade neuspechu vrati NULL.
 */
PLDR_DATA_TABLE_ENTRY GetModuleEntry(PVOID ModuleBase, PPEB Peb)
{
  PLDR_DATA_TABLE_ENTRY Tmp = NULL;
  PPEB_LDR_DATA LdrData = NULL;
  PLDR_DATA_TABLE_ENTRY Ret = NULL;
  DebugMsg(("main.c: GetModuleEntry(ModuleBase=0x%p; Peb=0x%p)\n", ModuleBase, Peb));

  LdrData = Peb->Ldr;
  Tmp = CONTAINING_RECORD(LdrData->InMemoryOrderModuleList.Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  while (&Tmp->InMemoryOrderLinks != &LdrData->InMemoryOrderModuleList) {
    if (Tmp->DllBase == ModuleBase) {
      Ret = Tmp;
      break;
	}

    Tmp = CONTAINING_RECORD(Tmp->InMemoryOrderLinks.Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  }

  DebugMsg(("main.c: GetModuleEntry(-):0x%p\n", Ret));
  return Ret;
}


/** Pomocna funkce, ktera dela presne to same, co rutina RemoveEntryList exportovana
 *  hlavnim modulem jadra a pouzivana pri programovani ovladacu – odstrani zadanou
 *  polozku z obousmerneho cyklickeho seznamu.
 *
 *  @param Adresa polozky, ktera ma byt ze seznamu odstranena.
 */
VOID RemoveEntryList(PLIST_ENTRY Entry)
{
  Entry->Flink->Blink = Entry->Blink;
  Entry->Blink->Flink = Entry->Flink;
  Entry->Flink = Entry;
  Entry->Blink = Entry;

  return;
}


/** Skryje modul reprezentovany strukturou LDR_DATA_TABLE_ENTRY.
 *
 *  Skryti je provedeno tak, ze dana struktura je vyjmuta ze seznamu InMemoryOrderModuleList,
 *  InLoadOrderModuleList a InInitializationOrderModuleList. Pozor, nemusi byt pritomna ve vsech
 *  seznamech. Zalezi zrejme na tom, jakym zpusobem byl modul danou strukturou reprezentovany
 *  nacten do pameti procesu.
 *
 *  @param Adresa struktury LDR_DATA_TABLE_ENTRY popisujici cilovy modul.
 */
VOID HideModule(PLDR_DATA_TABLE_ENTRY ModuleEntry)
{
  DebugMsg(("main.c: HideModule(ModuleEntry=0x%p)\n", ModuleEntry));

  RemoveEntryList(&ModuleEntry->InMemoryOrderLinks);
  if (ModuleEntry->InLoadOrderLinks.Flink != NULL)
    RemoveEntryList(&ModuleEntry->InLoadOrderLinks);

  if (ModuleEntry->InInitializationOrderLinks.Flink != NULL)
    RemoveEntryList(&ModuleEntry->InInitializationOrderLinks);

  DebugMsg(("main.c: HideModule(-)\n"));
  return;
}



/** Hlavni rutina programu ListDll.
 *
 *  Rutina nejprve provede inicializaci, nasledne zjisti bazovou adresu hlavniho
 *  modulu procesu a tento modul skryje ze struktur Bloku prostredi procesu. Pak
 *  ceka na stisk libovolne klavesy.
 */
int main(int argc, char **argv)
{
  PPEB Peb = NULL;
  PLDR_DATA_TABLE_ENTRY ModuleEntry = NULL;
  PVOID ModuleToHide = NULL;
  
  if (CommonInit()) {
  printf("Demonstrace skryvani modulu procesu\n");
  ModuleToHide = (PVOID)GetModuleHandleW(NULL);
    printf("Program se pokusi skryt svuj vlastni .exe modul z Bloku prostredi procesu\n");
    printf("Adresa tohoto modulu je 0x%p\n", ModuleToHide);

    Peb = GetPebAddress();
    printf("Adresa Bloku prostredi procesu je 0x%p\n", Peb);
    
	ModuleEntry = GetModuleEntry(ModuleToHide, Peb);
    printf("Adresa datove struktury LDR_DATA_TABLE_ENTRY popisujici .exe soubor aplikace je 0x%p\n", ModuleEntry);
    
	HideModule(ModuleEntry);
    printf("Hlavni modul procesu byl uspesne skryt. Presvecte se o tom pomoci aplikace ListDll\n");
    
    getchar();

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

  return 0;
}
