C++ - How to I get the base address of a process (.exe)

RafaelK
RafaelK used Ask the Experts™
on
I want to use ReadProcessMemory. It needs the "base address" as a second parameter. I have the process handle. How to I get the base address (HMODULE)?

I have tried calling VirtualQueryEx with the second parameter set to NULL. It returns 28 (is successful), but the information in the struct is garbage. The base address is always 0. I have tried EnumProcessModules but it only gives the DLLs that that application has loaded.

I want to obtain the address from within my program.

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
Call GetModuleHandle(NULL).  It returns the HMODULE (load address) of the EXE.  See http://msdn.microsoft.com/en-us/library/ms683199.aspx

Author

Commented:
That will not work. I want to get the base address of another process. Not my own base address.

So i have another application running, e.g. "calc.exe". I want to obtain its base address, not my own.
Commented:
The image address is embedded in the EXE's PE header.  EXEs are not designed to be relocated (they omit relocation info), so the PE load address is also the actual load address.  All you need to do is scarf the load address from the PE header.  Easy.

See the following code snippet.
ULONG_PTR _GetModuleImageAddress(const CString& strPath)
{
  HANDLE hFile;
  HANDLE hMap;
  ULONG_PTR ulImageBase = 0;

  if ((hFile = ::CreateFile((LPCTSTR)strPath,
      GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
      NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
    DTRACE(_T("Cannot open %s, err=%d\n"),
      (LPCTSTR)strPath, ::GetLastError());
    return 0;
  }

  if ((hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL))
      == NULL) {
    DTRACE(_T("Cannot create file mapping of %s, err=%d\n"),
      (LPCTSTR)strPath, ::GetLastError());
    ::CloseHandle(hFile);
    return 0;
  }

  PBYTE pData;
  
  //
  // Read the 1st 8192 bytes of the PE image
  //
  if ((pData = (PBYTE)::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 8192)) == NULL) {
    DTRACE(_T("Cannot map view of %s, err=%d\n"),
      (LPCTSTR)strPath, ::GetLastError());
    ::CloseHandle(hMap);
    ::CloseHandle(hFile);
    return 0;
  }

  //
  // Find the PE/PE+ header
  //
  // IMAGE_NT_SIGNATURE (0x00004550) 'PE00'
  // IMAGE_FILE_MACHINE_I386 (0x014c)
  // IMAGE_FILE_MACHINE_AMD64 (0x8664)
  //
  PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pData;
  if (pDos->e_magic == IMAGE_DOS_SIGNATURE) {
#ifdef _WIN64
# define IMAGE_FILE_MACHINE_xxx IMAGE_FILE_MACHINE_AMD64
    PIMAGE_NT_HEADERS64 pHdr = (PIMAGE_NT_HEADERS64)
      (((PBYTE)(pDos)) + pDos->e_lfanew);
#else
# define IMAGE_FILE_MACHINE_xxx IMAGE_FILE_MACHINE_I386
    PIMAGE_NT_HEADERS32 pHdr = (PIMAGE_NT_HEADERS32)
      (((PBYTE)(pDos)) + pDos->e_lfanew);
#endif
    //
    // Sanity: Does the PE header start no further than
    // the start of page 1, and the 'PE' header matches,
    // and the 32bit/64bit header matches?
    //
    if (((PBYTE)pHdr - pData) <= 4096 && pHdr->Signature == IMAGE_NT_SIGNATURE && pHdr->FileHeader.Machine == IMAGE_FILE_MACHINE_xxx) {
      //
      // Snarf the default base load address
      //
      ulImageBase = pHdr->OptionalHeader.ImageBase;
    }
  } else {
    DTRACE(_T("Cannot find the load address of PE in %s\n"),
      (LPCTSTR)strPath);
  }

  if (!::UnmapViewOfFile(pData)) {
    DTRACE(_T("UnmapViewOfFile(\"%s\") failed.\n"),
      (LPCTSTR)strPath);
  }
  if (!::CloseHandle(hMap)) {
    DTRACE(_T("CloseHandle of the file mapping object failed.\n"));
  }
  ::CloseHandle(hFile);

  return ulImageBase;
}

Open in new window

Author

Commented:
Sweet, thank you very much :)

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial