
/**
 * @file: listdll-vm.c
 *
 * Tento modul zjistuje seznamy modulu cizich procesu prostrednictvim
 * nativni funkce NtQueryVirtualMemory a rutiny Windows API VirtualQueryEx.
 */

#include <stdio.h>
#include <windows.h>
#include "common.h"
#include "moduleinfo.h"
#include "listdll-vm.h"


// Uchovava adresu funkce NtQueryVirutalMemory
static NTQUERYVIRTUALMEMORY _NtQueryVirtualMemory = NULL;



/** Zjisti seznam modulu ciloveho procesu pomoci spravce virtualni pameti.
 *
 *  Rutina vyuziva moznosti funkce VirtualQueryEx ke zjisteni oblasti
 *  pameti, kde se nachazi pametove mapovane soubory typu SEC_IMAGE
 *  (soubory PE). Pro zisteni jejich jmen pouziva nativni funkci
 *  NtQueryVirtualMemory.
 *
 *  @param PID Identifikator ciloveho procesu.
 *  @param ModuleList Adresa promenne, kam funkce v pripade uspechu zapise
 *  adresu prvniho prvku seznamu modulu ciloveho procesu.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade 
 *  neuspechu.
 */
BOOL ListDllVMGetModules(DWORD PID, PMODULE_INFO_ITEM *ModuleList)
{
  BOOL Ret = FALSE;
  HANDLE hProcess = NULL;
  PVOID BaseAddress = NULL;
  MEMORY_BASIC_INFORMATION mbi;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  SIZE_T InfoLength = 0;
  PUNICODE_STRING ImageName = NULL;
  SIZE_T ImageSize = 0;
  PVOID ImageBase = (PVOID)0x1;
  PMODULE_INFO_ITEM ModuleInfoItem = NULL;
  PMODULE_INFO_ITEM ModuleListEnd = NULL;
  DebugMsg(("listdll-vm.c: ListDllVMGetModules(PID=%u; ModuleList=0x%p)\n", PID, ModuleList));

  *ModuleList = NULL;
  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PID);
  Ret = hProcess != NULL;
  if (Ret) {
    do {
      InfoLength = VirtualQueryEx(hProcess, BaseAddress, &mbi, sizeof(mbi));
      Ret = InfoLength > 0;
      if (Ret) {
        BaseAddress = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
        if (mbi.State == MEM_COMMIT && mbi.Type == MEM_IMAGE) {
          if (mbi.AllocationBase != ImageBase) {
            if (ImageName != NULL) {
              ModuleInfoItem = ModuleInfoItemAlloc(ImageBase, ImageSize, ImageName->Buffer, ImageName->Length);
              if (ModuleInfoItem != NULL) {
                if (*ModuleList == NULL)
                  *ModuleList = ModuleInfoItem;
				else ModuleInfoItemInsert(ModuleListEnd, ModuleInfoItem);

                ModuleListEnd = ModuleInfoItem;
              }

              FreeMem(ImageName);
              ImageName = NULL;
              ImageSize = 0;
            }

            ImageName = (PUNICODE_STRING)AllocMem(1024);
            Ret = ImageName != NULL;
            if (Ret) {
              Status = _NtQueryVirtualMemory(hProcess, mbi.AllocationBase, MEMORY_MAPPED_FILE_NAME, ImageName, 1024, NULL);
              if (Status == STATUS_SUCCESS) {
                ImageBase = mbi.AllocationBase;
                ImageSize = mbi.RegionSize;
              } else DebugMsg(("listdll-vm.c: ListDllVMGetModules(): ERROR: NtQueryVirtualMemory: 0x%x\n", Status));
            } else DebugMsg(("listdll-vm.c: ListDllVMGetModules(): ERROR: HeapAlloc: %u\n", GetLastError()));
          } else ImageSize += mbi.RegionSize;
        }
      }
    } while (Ret);
    Ret = TRUE;

    if (ImageName != NULL) {
      ModuleInfoItem = ModuleInfoItemAlloc(ImageBase, ImageSize, ImageName->Buffer, ImageName->Length);
      if (ModuleInfoItem != NULL) {
        if (*ModuleList == NULL)
          *ModuleList = ModuleInfoItem;
        else ModuleInfoItemInsert(ModuleListEnd, ModuleInfoItem);
      }

      FreeMem(ImageName);
	}

    CloseHandle(hProcess);
  } else DebugMsg(("listdll-vm.c: ListDllVMGetModules(): ERROR: OpenProcess: %i\n", GetLastError()));

  DebugMsg(("listdll-vm.c: ListDllVMGetModules(-):%u, *ModuleList=0x%p\n", Ret, *ModuleList));
  return Ret;
}



/** Inicializuje modul pro ziskavani seznamu modulu procesu pomoci
 *  sluzeb spravce virtualni pameti.
 *
 *  Rutina najde funkci NtQueryVirutalMemory v knihovne ntdll.dll.
 *
 *  @return Funkce vraci TRUE v pripade uspechu a FALSE v pripade
 *  neuspechu.
 */
BOOL ListDllVMInit(VOID)
{
  BOOL Ret = FALSE;
  HANDLE hNtdll = NULL;
  DebugMsg(("listdll-vm.c: ListDllVMInit()\n"));

  hNtdll = GetModuleHandleW(L"ntdll.dll");
  Ret = hNtdll != NULL;
  if (Ret) {
    _NtQueryVirtualMemory = (NTQUERYVIRTUALMEMORY)GetProcAddress(hNtdll, "NtQueryVirtualMemory");
    Ret = _NtQueryVirtualMemory != NULL;
    if (!Ret)
      DebugMsg(("listdll-vm.c: ListDllVMInit(): ERROR: GetProcAddress(NtQueryVirtualMemory): %i\n", GetLastError()));
    } else DebugMsg(("listdll-vm.c: ListDllVMInit(): ERROR: GetModuleHandle(ntdll.dll): %i\n", GetLastError()));

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


/** Uklidi po modulu ziskavajicimu seznam modulu procesu pomoci sluzeb
 *  spravce virtualni pameti.
 *
 *  Protoze pri inicializaci dochazi pouze ke cteni adresoveho prostoru
 *  procesu, neni co uklizet.
 */
VOID ListDllVMFinit(VOID)
{
  DebugMsg(("ListDllVMFInit()\n"));

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