/**
 * @file: listdll.peb.c
 *
 * Tento soubor obsahuje rutiny pro cteni bloku prostredi procesu (PEB)
 * a informaci o modulech, ktere procesor pouziva (LDR).
 */
#include <stdio.h>
#include <windows.h>
#include "common.h"
#include "moduleinfo.h"
#include "listdll-peb.h"

// Uchovava adresu rutiny NtQueryInformationProcess
static NTQUERYINFORMATIONPROCESS _NtQueryInformationProcess = NULL;



/** Zjisti adresu struktury PEB.
 *
 *  Rutina zjistuje adresu te struktury PEB, ktera je pro zkompilovanou
 *  binarku "nativni." Pri zkompilovani pro 32bit OS se jedna o PEB32
 *  (jiny PEB na 32bit OS ani neni), pri zkompilovani pro 64bit OS zjisti
 *  adresu struktury PEB64; i u procesu bezicich pod WOW64.
 *
 *  @param hProcess Handle procesu, ktere rutina pouzije pro cteni
 *  pameti.
 *
 *  @return Funkce vrati adresu struktury PEB v adresovem prostoru
 *  ciloveho procesu, nebo NULL v pripade neuspechu.
 */
static PVOID GetProcessPEBAddress(HANDLE hProcess)
{
  PVOID Ret = NULL;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  PROCESS_BASIC_INFORMATION pbi;
  DebugMsg(("listdll-peb.c: GetProcessPEBAddress(hProcess=0x%p)\n", hProcess));

  Status = _NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
  if (Status == STATUS_SUCCESS)
	Ret = pbi.PebBaseAddress;
  else DebugMsg(("listdll-peb.c: GetprocessPEBAddress(): NtQueryInformationProcess failed with status 0x%x\n", Status));

  DebugMsg(("listdll-peb.c: GetProcessPEBAddress(-):0x%p\n", Ret));
  return Ret;
}


/** Zjisti adresu struktury PEB, ktera slouzi pro emulaci prostredi
 *  WOW64 pro dany proces.
 *
 *  @param hProcess Handle procesu, ktere rutina pouzije pro cteni
 *  pameti.
 *
 *  @return Funkce vrati adresu struktury PEB v adresovem prostoru
 *  ciloveho procesu, nebo NULL v pripade neuspechu.
 */
static PVOID GetProcessPEBAddressWow64(HANDLE hProcess)
{
  PVOID Ret = NULL;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  PROCESS_BASIC_INFORMATION pbi;
  DebugMsg(("listdll-peb.c: GetProcessPEBAddressWow64(hProcess=0x%p)\n", hProcess));

  Status = _NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
  if (Status == STATUS_SUCCESS)
	Ret = (PCHAR)pbi.PebBaseAddress - 0x1000;
  else DebugMsg(("listdll-peb.c: GetprocessPEBAddressWow64(): NtQueryInformationProcess failed with status 0x%x\n", Status));

  DebugMsg(("listdll-peb.c: GetProcessPEBAddressWow64(-):0x%p\n", Ret));
  return Ret;
}

/** Nacte obsah struktury PEB ciloveho procesu.
 *
 *  Rutina zjistuje adresu struktury PEB pomoci GetProcessPEBAddress,
 *  pro obsah nacteneho bloku prostredi procesu plati tedy stejna 
 *  pravidla.
 *
 *  @param hProcess Handle procesu, o jehoz PEB se volajici zajima.
 *  @param Peb Adresa struktury PEB, kam funkce v pripade uspechu
 *  ulozi nactena data.
 *
 *  @return Funkce vraci v pripade uspechu hodnotu TRUE. Jinak vrati
 *  vzdy FALSE.
 */
static BOOL ReadProcessPEB(HANDLE hProcess, PPEB Peb)
{
  BOOL Ret = FALSE;
  PVOID PebAddress = NULL;
  SIZE_T BytesRead = 0;
  DebugMsg(("listdll-peb.c: ReadProcessPEB(hProcess=0x%p; Peb=0x%p)\n", hProcess, Peb));

  PebAddress = GetProcessPEBAddress(hProcess);
  Ret = PebAddress != NULL;
  if (Ret) {
    Ret = ReadProcessMemory(hProcess, PebAddress, Peb, sizeof(*Peb), &BytesRead);
    if (!Ret)
      DebugMsg(("listdll-peb.c: GetProcessPEB(): ReadProcessMemory failed with error %u\n", GetLastError()));
  } else DebugMsg(("listdll-peb.c: GetProcessPEB(): Failed to get address of the PEB structure\n"));

  DebugMsg(("listdll-peb.c: ReadProcessPEB(-):%u\n", Ret));
  return Ret;
}

/** Nacte obsah struktury PEB ciloveho procesu.
 *
 *  Nacte obsah 32bitoveho PEBu procesu pod WOW64.
 *
 *  @param hProcess Handle procesu, o jehoz PEB se volajici zajima.
 *  @param Peb Adresa struktury PEB, kam funkce v pripade uspechu
 *  ulozi nactena data.
 *
 *  @return Funkce vraci v pripade uspechu hodnotu TRUE. Jinak vrati
 *  vzdy FALSE.
 */
static BOOL ReadProcessPEBWow64(HANDLE hProcess, PPEB_WOW64 Peb)
{
  BOOL Ret = FALSE;
  PVOID PebAddress = NULL;
  SIZE_T BytesRead = 0;
  DebugMsg(("listdll-peb.c: ReadProcessPEBWow64(hProcess=0x%p; Peb=0x%p)\n", hProcess, Peb));

  PebAddress = GetProcessPEBAddressWow64(hProcess);
  Ret = PebAddress != NULL;
  if (Ret) {
    Ret = ReadProcessMemory(hProcess, PebAddress, Peb, sizeof(*Peb), &BytesRead);
    if (!Ret)
      DebugMsg(("listdll-peb.c: GetProcessPEBWow64(): ReadProcessMemory failed with error %u\n", GetLastError()));
  } else DebugMsg(("listdll-peb.c: GetProcessPEBWow64(): Failed to get address of the PEB structure\n"));

  DebugMsg(("listdll-peb.c: ReadProcessPEBWow64(-):%u\n", Ret));
  return Ret;
}

/** Nacte strukturu PEB_LDR_DATA z bloku prostredi procesu.
 *
 *  Funkce pocita, ze blok prostredi procesu zadavany v parametru Peb
 *  ma strukturu PEB32 na 32bit OS a PEB64 na 64bit OS. WOW64 nebere
 *  v uvahu.
 *
 *  @param hProcess Handle procesu, o jehoz PEB_LDR_DATA se volajici zajima.
 *  @param Peb Adresa struktury PEB, ze ktere rutina vycte adresu hledane
 *  struktury v adresovem prostoru ciloveho procesu.
 *  @param LdrData Adresa struktury PEB_LDR_DATA, kterou funkce v pripade uspechu
 *  vyplni nactenymi daty.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ReadProcessLdrData(HANDLE hProcess, PPEB Peb, PPEB_LDR_DATA LdrData)
{
  BOOL Ret = FALSE;
  SIZE_T BytesRead = 0;
  DebugMsg(("listdll-peb.c: ReadProcessLdrData(hProcess=0x%p; Peb=0x%p; LdrData=0x%p)\n", hProcess, Peb, LdrData));

  Ret = ReadProcessMemory(hProcess, Peb->Ldr, LdrData, sizeof(*LdrData), &BytesRead);
  if (!Ret)
    DebugMsg(("listdll-peb.c: ReadProcessLdrData(): ReadProcessMemory failed with error %u\n", GetLastError()));

  DebugMsg(("listdll-peb.c: ReadProcessLdrData(-):%u\n", Ret));
  return Ret;
}

/** Nacte strukturu PEB_LDR_DATA z bloku prostredi procesu.
 *
 *  Rutina slouzi k nacitani struktury PEB_LDR_DATA z adresy ulozene
 *  v 32bitovem PEBu procesu pod WOW64.
 *
 *  @param hProcess Handle procesu, o jehoz PEB_LDR_DATA se volajici zajima.
 *  @param Peb Adresa struktury PEB, ze ktere rutina vycte adresu hledane
 *  struktury v adresovem prostoru ciloveho procesu.
 *  @param LdrData Adresa struktury PEB_LDR_DATA, kterou funkce v pripade uspechu
 *  vyplni nactenymi daty.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ReadProcessLdrDataWow64(HANDLE hProcess, PPEB_WOW64 Peb, PPEB_LDR_DATA_WOW64 LdrData)
{
  BOOL Ret = FALSE;
  SIZE_T BytesRead = 0;
  DebugMsg(("listdll-peb.c: ReadProcessLdrDataWow64(hProcess=0x%p; Peb=0x%p; LdrData=0x%p)\n", hProcess, Peb, LdrData));

  Ret = ReadProcessMemory(hProcess, (PVOID)Peb->Ldr, LdrData, sizeof(*LdrData), &BytesRead);
  if (!Ret)
    DebugMsg(("listdll-peb.c: ReadProcessLdrDataWow64(): ReadProcessMemory failed with error %u\n", GetLastError()));

  DebugMsg(("listdll-peb.c: ReadProcessLdrDataWow64(-):%u\n", Ret));
  return Ret;
}

/** Nacte obsah struktury LDR_DATA_TABLE_ENTRY z adresoveho prostoru daneho procesu.
 *
 *  @param hProcess Handle ciloveho procesu.
 *  @param Address Adresa struktury LDR_DATA_TABLE_ENTRY v ramci ciloveho
 *  procesu.
 *  @param LdrModule Adresa struktury LDR_DATA_TABLE_ENTRY, kam funkce v
 *  pripade uspechu zapise data nactena z pameti ciloveho procesu.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ReadProcessLdrModule(HANDLE hProcess, PVOID Address, PLDR_DATA_TABLE_ENTRY LdrModule)
{
  BOOL Ret = FALSE;
  SIZE_T BytesRead = 0;
  DebugMsg(("listdll-peb.c: ReadProcessLdrModule(hProcess=0x%p; Address=0x%p; LdrModule=0x%p)\n", hProcess, Address, LdrModule));

  Ret = ReadProcessMemory(hProcess, Address, LdrModule, sizeof(*LdrModule), &BytesRead);
  if (!Ret)
    DebugMsg(("listdll-peb.c: ReadProcessLdrModule(): ReadProcessMemory failed with error %u, %u bytes read\n", GetLastError(), BytesRead));

  DebugMsg(("listdll-peb.c: ReadProcessLdrModule(-):%u\n", Ret));
  return Ret;
}

/** Nacte obsah struktury LDR_DATA_TABLE_ENTRY z adresoveho prostoru daneho procesu.
 *
 *  Rutina je urcena ke cteni techto struktur z procesu pod WOW64.
 *
 *  @param hProcess Handle ciloveho procesu.
 *  @param Address Adresa struktury LDR_DATA_TABLE_ENTRY v ramci ciloveho
 *  procesu.
 *  @param LdrModule Adresa struktury LDR_DATA_TABLE_ENTRY, kam funkce v
 *  pripade uspechu zapise data nactena z pameti ciloveho procesu.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ReadProcessLdrModuleWow64(HANDLE hProcess, PVOID Address, PLDR_DATA_TABLE_ENTRY_WOW64 LdrModule)
{
  BOOL Ret = FALSE;
  SIZE_T BytesRead = 0;
  DebugMsg(("listdll-peb.c: ReadProcessLdrModuleWow64(hProcess=0x%p; Address=0x%p; LdrModule=0x%p)\n", hProcess, Address, LdrModule));

  Ret = ReadProcessMemory(hProcess, Address, LdrModule, sizeof(*LdrModule), &BytesRead);
  if (!Ret)
    DebugMsg(("listdll-peb.c: ReadProcessLdrModuleWow64(): ReadProcessMemory failed with error %u\n", GetLastError()));

  DebugMsg(("listdll-peb.c: ReadProcessLdrModuleWow64(-):%u\n", Ret));
  return Ret;
}

/** Nacte z pameti ciloveho procesu plne jmeno souboru zadaneho modulu.
 *
 *  @param hProcess Handle ciloveho procesu.
 *  @param LdrModule Struktura LDR_DATA_TABLE_ENTRY obsahujici informace
 *  o cilovem modulu.
 *  @param NameBuffer Promenna, kterou funkce v pripade uspechu vyplni adresou
 *  na retezec Unicode obsahujici plne jmeno k cilovemu modulu. Tento retezec
 *  je nutne dealokovat pomoci rutiny FreeMem.
 *
 *  @return Funkce vrati TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ReadLdrModuleNameBuffer(HANDLE hProcess, PLDR_DATA_TABLE_ENTRY LdrModule, PWCHAR *NameBuffer)
{
  BOOL Ret = FALSE;
  SIZE_T BytesRead = 0;
  SIZE_T RequiredLength = 0;
  DebugMsg(("listdll-peb.c: ReadLdrModuleNameBuffer(hProcess=0x%p; LdrModule=0x%p; NameBuffer=0x%p)\n", hProcess, LdrModule, NameBuffer));

  *NameBuffer = NULL;
  RequiredLength = LdrModule->FullDllName.Length + sizeof(WCHAR);
  *NameBuffer = (PWCHAR)AllocMem(RequiredLength);
  Ret = *NameBuffer != NULL;
  if (Ret) {
    ZeroMemory(*NameBuffer, RequiredLength);
    Ret = ReadProcessMemory(hProcess, LdrModule->FullDllName.Buffer, *NameBuffer, LdrModule->FullDllName.Length, &BytesRead);
	if (!Ret) {
      DebugMsg(("listdll-peb.c: ReadLdrModuleNameBuffer: ReadProcessMemory(0x%p:%u) failed with error %u\n", LdrModule->FullDllName.Buffer, LdrModule->FullDllName.Length, GetLastError()));
      FreeMem(*NameBuffer);
      *NameBuffer = NULL;
	}
  } else DebugMsg(("listdll-peb.c: ReadLdrModuleNameBuffer(): Allocation of storage for name buffer failed\n"));

  DebugMsg(("listdll-peb.c: ReadLdrModuleNameBuffer(-):%u\n", Ret));
  return Ret;
}

/** Nacte z pameti ciloveho procesu plne jmeno souboru zadaneho modulu.
 *
 *  Rutina je urcena pro cteni jmen 32bitovych modulu z procesu pod WOW64.
 *
 *  @param hProcess Handle ciloveho procesu.
 *  @param LdrModule Struktura LDR_DATA_TABLE_ENTRY obsahujici informace
 *  o cilovem modulu.
 *  @param NameBuffer Promenna, kterou funkce v pripade uspechu vyplni adresou
 *  na retezec Unicode obsahujici plne jmeno k cilovemu modulu. Tento retezec
 *  je nutne dealokovat pomoci rutiny FreeMem.
 *
 *  @return Funkce vrati TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ReadLdrModuleNameBufferWow64(HANDLE hProcess, PLDR_DATA_TABLE_ENTRY_WOW64 LdrModule, PWCHAR *NameBuffer)
{
  BOOL Ret = FALSE;
  SIZE_T BytesRead = 0;
  SIZE_T RequiredLength = 0;
  DebugMsg(("listdll-peb.c: ReadLdrModuleNameBufferWow64(hProcess=0x%p; LdrModule=0x%p; NameBuffer=0x%p)\n", hProcess, LdrModule, NameBuffer));

  *NameBuffer = NULL;
  RequiredLength = LdrModule->FullDllNameLength + sizeof(WCHAR);
  *NameBuffer = (PWCHAR)AllocMem(RequiredLength);
  Ret = *NameBuffer != NULL;
  if (Ret) {
    ZeroMemory(*NameBuffer, RequiredLength);
    Ret = ReadProcessMemory(hProcess, (PVOID)LdrModule->FullDllNameBuffer, *NameBuffer, LdrModule->FullDllNameLength, &BytesRead);
	if (!Ret) {
      DebugMsg(("listdll-peb.c: ReadLdrModuleNameBufferWow64(): ReadProcessMemory(0x%x:%u) failed with error %u\n", LdrModule->FullDllNameBuffer, LdrModule->FullDllNameLength, GetLastError()));
      FreeMem(*NameBuffer);
      *NameBuffer = NULL;
	}
  } else DebugMsg(("listdll-peb.c: ReadLdrModuleNameBufferWow64(): Allocation of storage for name buffer failed\n"));

  DebugMsg(("listdll-peb.c: ReadLdrModuleNameBufferWow64(-):%u\n", Ret));
  return Ret;
}


/** Nacte seznam modulu ciloveho procesu pomoci metody cteni struktury PEB.
 *
 *  Rutina cte data pouze z "nativni" struktury PEB (pro 64bitove procesy
 *  z 64bit PEBu, nenacita PEB slozici pro emulaci WOW64).
 *
 *  @param hProcess Handle ciloveho procesu.
 *  @param ModuleList Promenna, kterou funkce v pripade uspechu vyplni
 *  adresou prvniho prvku seznamu modulu.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ListDllPEBGetModulesNative(HANDLE hProcess, PMODULE_INFO_ITEM *ModuleList)
{
  BOOL Ret = FALSE;
  PEB ProcessPEB;
  PVOID LdrModuleListStart = NULL;
  PVOID CurrentLdrModule = NULL;
  PEB_LDR_DATA ProcessLdrData;
  LDR_DATA_TABLE_ENTRY ProcessLdrModule;
  PMODULE_INFO_ITEM ModuleListEnd = NULL;
  PMODULE_INFO_ITEM ModuleInfoItem = NULL;
  PWCHAR ModuleNameBuffer = NULL;
  DebugMsg(("listdll-peb.c: ListDllPEBGetModulesNative(hProcess=0x%p; ModuleList=0x%p)\n", hProcess, ModuleList));

  *ModuleList = NULL;
    Ret = ReadProcessPEB(hProcess, &ProcessPEB);
	if (Ret) {
      Ret = ReadProcessLdrData(hProcess, &ProcessPEB, &ProcessLdrData);
      if (Ret) {
        LdrModuleListStart = ((PCHAR)ProcessPEB.Ldr + FIELD_OFFSET(PEB_LDR_DATA, InMemoryOrderModuleList));
        CurrentLdrModule = ProcessLdrData.InMemoryOrderModuleList.Flink;
        while (Ret && CurrentLdrModule != LdrModuleListStart) {
          CurrentLdrModule = CONTAINING_RECORD(CurrentLdrModule, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
          Ret = ReadProcessLdrModule(hProcess, CurrentLdrModule, &ProcessLdrModule);
		  if (Ret) {
            Ret = ReadLdrModuleNameBuffer(hProcess, &ProcessLdrModule, &ModuleNameBuffer);
			if (Ret) {
              ModuleInfoItem = ModuleInfoItemAlloc(ProcessLdrModule.DllBase, ProcessLdrModule.ImageSize, ModuleNameBuffer, ProcessLdrModule.FullDllName.Length);
			  Ret = ModuleInfoItem != NULL;
              if (Ret) {
                if (*ModuleList == NULL)
                  *ModuleList = ModuleInfoItem;
				else ModuleInfoItemInsert(ModuleListEnd, ModuleInfoItem);

				ModuleListEnd = ModuleInfoItem;
			  } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesNative(): Failed to allocate ModuleInfo structure\n"));

              FreeMem(ModuleNameBuffer);
			} else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesNative(): Failed to get module name\n"));

            CurrentLdrModule = ProcessLdrModule.InMemoryOrderLinks.Flink;
		  } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesNative(): Failed to read Ldr module structure\n"));
		}

		if (!Ret) {
		  if (*ModuleList != NULL) {
            ModuleInfoListFree(*ModuleList);
		    *ModuleList = NULL;
          }
        }
      } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesNative(): Failed to rad Ldr data of the target process\n"));
    } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesNative(): Failed to read PEB of the target process\n"));

  DebugMsg(("listdll-peb.c: ListDllPEBGetModulesNative(-):%u\n", Ret));
  return Ret;
}

/** Nacte seznam modulu ciloveho procesu pomoci metody cteni struktury PEB.
 *
 *  Rutina predpoklada, ze cilovy proces je emulovan pomoci WOW64. Cte
 *  data ze struktury PEB, kterou vytvari emulator pro sve ucely, tedy
 *  pro simulaci 32bit prostredi.
 *
 *  @param hProcess Handle ciloveho procesu.
 *  @param ModuleList Promenna, kterou funkce v pripade uspechu vyplni
 *  adresou prvniho prvku seznamu modulu.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
static BOOL ListDllPEBGetModulesWow64(HANDLE hProcess, PMODULE_INFO_ITEM *ModuleList)
{
  BOOL Ret = FALSE;
  PEB_WOW64 ProcessPEB;
  PVOID LdrModuleListStart = NULL;
  PVOID CurrentLdrModule = NULL;
  PEB_LDR_DATA_WOW64 ProcessLdrData;
  LDR_DATA_TABLE_ENTRY_WOW64 ProcessLdrModule;
  PMODULE_INFO_ITEM ModuleListEnd = NULL;
  PMODULE_INFO_ITEM ModuleInfoItem = NULL;
  PWCHAR ModuleNameBuffer = NULL;
  DebugMsg(("listdll-peb.c: ListDllPEBGetModulesWow64(hProcess=0x%p; ModuleList=0x%p)\n", hProcess, ModuleList));

  *ModuleList = NULL;
    Ret = ReadProcessPEBWow64(hProcess, &ProcessPEB);
	if (Ret) {
      Ret = ReadProcessLdrDataWow64(hProcess, &ProcessPEB, &ProcessLdrData);
      if (Ret) {
        LdrModuleListStart = ((PCHAR)ProcessPEB.Ldr + FIELD_OFFSET(PEB_LDR_DATA_WOW64, InMemoryOrderModuleList));
        CurrentLdrModule = (PVOID)ProcessLdrData.InMemoryOrderModuleList[0];
        while (Ret && CurrentLdrModule != LdrModuleListStart) {
          CurrentLdrModule = CONTAINING_RECORD(CurrentLdrModule, LDR_DATA_TABLE_ENTRY_WOW64, InMemoryOrderLinks);
          Ret = ReadProcessLdrModuleWow64(hProcess, CurrentLdrModule, &ProcessLdrModule);
		  if (Ret) {
            Ret = ReadLdrModuleNameBufferWow64(hProcess, &ProcessLdrModule, &ModuleNameBuffer);
			if (Ret) {
              ModuleInfoItem = ModuleInfoItemAlloc((PVOID)ProcessLdrModule.DllBase, ProcessLdrModule.ImageSize, ModuleNameBuffer, ProcessLdrModule.FullDllNameLength);
			  Ret = ModuleInfoItem != NULL;
              if (Ret) {
                if (*ModuleList == NULL)
                  *ModuleList = ModuleInfoItem;
				else ModuleInfoItemInsert(ModuleListEnd, ModuleInfoItem);

				ModuleListEnd = ModuleInfoItem;
			  } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesWow64(): Failed to allocate ModuleInfo structure\n"));

              FreeMem(ModuleNameBuffer);
			} else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesWow64(): Failed to get module name\n"));

            CurrentLdrModule = (PVOID)ProcessLdrModule.InMemoryOrderLinks[0];
		  } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesWow64(): Failed to read Ldr module structure\n"));
		}

		if (!Ret) {
		  if (*ModuleList != NULL) {
            ModuleInfoListFree(*ModuleList);
		    *ModuleList = NULL;
          }
        }
      } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesWow64(): Failed to rad Ldr data of the target process\n"));
    } else DebugMsg(("listdll-peb.c: ListDllPEBGetModulesWow64(): Failed to read PEB of the target process\n"));

  DebugMsg(("listdll-peb.c: ListDllPEBGetModulesWow64(-):%u\n", Ret));
  return Ret;
}


/** Nacte seznam modulu ciloveho procesu pomoci metody cteni struktury PEB.
 *
 *  Rutina nejprve zjisti, zda cilovy proces je emulovan pomoci WOW64 a
 *  precte seznam modulu z jeho "nativniho" PEBu (32bitoveho na 32bit OS,
 *  64bitoveho na 64bit OS). POkud je proces emulovan, precte jeste
 *  seznam modulu z jeho 32bitoveho PEBu a oba seznamy modulu spoji do
 *  jednoho.
 *
 *  @param PID Identifikator ciloveho procesu.
 *  @param ModuleList Promenna, kterou funkce v pripade uspechu vyplni
 *  adresou prvniho prvku seznamu modulu.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade neuspechu.
 */
BOOL ListDllPEBGetModules(DWORD PID, PMODULE_INFO_ITEM *ModuleList)
{
  BOOL Ret = FALSE;
  HANDLE hProcess = 0;
  BOOL Wow64 = FALSE;
  PMODULE_INFO_ITEM ModuleList1 = NULL;
  PMODULE_INFO_ITEM ModuleList2 = NULL;
  DebugMsg(("listdll-peb.c: ListDllPEBGetModules(PID=%u; ModuleList=0x%p)\n", PID, ModuleList));

  *ModuleList = NULL;
  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
  Ret = hProcess != NULL;
  if (Ret) {
    Ret = IsWow64Process(hProcess, &Wow64);
    if (Ret) {
      if (Wow64)
        Ret = ListDllPEBGetModulesWow64(hProcess, &ModuleList1);

      if (Ret) {
        Ret = ListDllPEBGetModulesNative(hProcess, &ModuleList2);
		if (Ret) {
          *ModuleList = ModuleList2;
		  while (ModuleList2->Next != NULL)
            ModuleList2 = ModuleList2->Next;

          ModuleList2->Next = ModuleList1;
		} else DebugMsg(("listdll-peb.c: ListDllPEBGetModules(): Failed to get list of native modules.\n"));
	  } else DebugMsg(("listdll-peb.c: ListDllPEBGetModules(): Failed to get list of WOW64 modules.\n"));
    } else DebugMsg(("listdll-peb.c: ListDllPEBGetModules(): IsWow64Process failed with error %u\n", GetLastError()));

    CloseHandle(hProcess);
  } else DebugMsg(("listdll-peb.c: ListDllPEBGetModules(): OpenProcess failed with error %u\n", GetLastError()));

  DebugMsg(("listdll-peb.c: ListDllPEBGetModules(-):%u\n", Ret));
  return Ret;
}

/** Inicializuje modul pro praci se strukturou PEB jinych procesu.
 *
 *  Funkce najde adresu rutiny NtQueryInformationProcess v knihovne
 *  ntdll.dll.
 *
 *  @return Funkce vrati TRUE v pripade uspechu a FALSE v pripade neuspechu.  
 */
BOOL ListDllPEBInit(VOID)
{
  BOOL Ret = FALSE;
  HMODULE hNtdll = NULL;
  DebugMsg(("listdll-peb.c: ListDllPEBInit()\n"));

  hNtdll = GetModuleHandleW(L"ntdll.dll");
  Ret = hNtdll != NULL;
  if (Ret) {
    _NtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)GetProcAddress(hNtdll, "NtQueryInformationProcess");
    Ret = _NtQueryInformationProcess != NULL;
	if (!Ret)
      DebugMsg(("listdll-peb.c: ListDllPEBInit(): GetProcAddress failed with error %u\n", GetLastError()));
  } else DebugMsg(("listdll-peb.c: ListDllPEBInit(): GetModulehandleW failed with error %u\n", GetLastError()));

  DebugMsg(("listdll-peb.c: ListDllPEBInit(-):%u\n", Ret));
  return Ret;
}


/** Uklidi po modulu pro praci s strukturami PEB cizich procesu.
 *
 *  Protoze pri inicializaci nedochazelo k modifikaci struktur procesu ani
 *  pouziti nejakeho slozitejsiho rozhrani, rutina neprovadi nic.
 */
VOID ListDllPEBFinit(VOID)
{
  DebugMsg(("listdll-peb.c: ListDllPEBFinit()\n"));

  DebugMsg(("listdll-peb.c: ListDllPEBFinit(-)\n"));
  return;
}
