Click here to Skip to main content
Licence 
First Posted 3 Sep 2003
Views 68,823
Bookmarked 18 times

Toolhelp32ReadProcessMemory

By | 3 Sep 2003 | Article
How to use the Toolhelp32ReadProcessMemory() function

Sample Image - ReadProcessMemory.jpg

Introduction

This article is a brief explanation of how to use the Toolhelp32ReadProcessMemory() API.  Most of the time, peeking into another process' memory space is not necessary.  However, for more advanced applications, or for a late-night debugging session, there just might be some benefit in being able to see the heap of another process.

The "snapshot"

The toolhelp functions make use of a snapshot to access process, thread, module, and heap lists in the system.  To quote MSDN:

"The lists in system memory change when processes are started and ended, threads are created and destroyed, executable modules are loaded and unloaded from system memory, and heaps are created and destroyed.  The use of information from a snapshot prevents inconsistencies.  Otherwise, changes to a list could possibly cause a thread to incorrectly traverse the list or cause an access violation (a GP fault).  For example, if an application traverses the thread list while other threads are created or terminated, information that the application is using to traverse the thread list might become outdated and could cause an error for the application traversing the list."

That pretty much says it all.  The snapshot is but a brief moment in time.

Depending on the privilege level of the process requesting the snapshot, the CreateToolhelp32Snapshot() function might return an error 5, which indicates access denied.

Getting a process handle

The first parameter to Toolhelp32ReadProcessMemory() is a handle to a process.  This can be obtained in a variety of fashions.  Since I was already in the toolhelp API, I used the Process32First() and Process32Next() functions.  These two functions make use of the aforementioned snapshot.

PROCESSENTRY32 ProcessEntry = {0};
HANDLE hProcessSnapshot;

hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE != hProcessSnapshot)
{    
    ProcessEntry.dwSize = sizeof(PROCESSENTRY32);

    if (Process32First(hProcessSnapshot, &ProcessEntry) != FALSE)
    {        
        do        
        {            
            // save ProcessEntry.th32ProcessID for use later

        } while (Process32Next(hProcessSnapshot, 
                    &ProcessEntry) != FALSE);
    }

    CloseHandle(hProcessSnapshot);
}

EnumProcesses() is yet another way of getting a process handle.

Getting the starting address and size of a heap block

The second and third parameters to Toolhelp32ReadProcessMemory() are the starting address of the heap block and its size.  To obtain those, I first used Heap32ListFirst() and Heap32ListNext() to iterate through each of the process' heap lists.  Note that some processes have a few while others have several dozen (e.g., Outlook had 40).  For each list, I used Heap32First() and Heap32Next() to iterate through the blocks themselves. 

Note that we are getting another snapshot, this time of a particular process' heap list.

Because of thread injection, the locking of the blocks, and just the sheer number of blocks that might exist, this could be a painfully slow process.  The HeapEntry.dwFlags variable can be used to filter out certain types of blocks (e.g., free, fixed, moveable).

HANDLE hHeapSnapshot;
HEAPLIST32 HeapList = {0};
HEAPENTRY32 HeapEntry = {0};

hHeapSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, 
    dwProcessId);
if (INVALID_HANDLE_VALUE != hHeapSnapshot)
{
    HeapList.dwSize = sizeof(HEAPLIST32);

    if (Heap32ListFirst(hHeapSnapshot, &HeapList) != FALSE)
    {        
        do        
        {            
            HeapEntry.dwSize = sizeof(HEAPENTRY32);    

            if (Heap32First(&HeapEntry, HeapList.th32ProcessID, 
                 HeapList.th32HeapID) != FALSE)            
            {
                do                
                {   
                    // save HeapEntry.dwAddress and 
                    // HeapEntry.dwBlockSize for use later
                
                } while (Heap32Next(&HeapEntry) != FALSE);            
            }            
            else                
                break;

        } while (Heap32ListNext(hHeapSnapshot, &HeapList) != FALSE);    
    }        
    
    CloseHandle(hHeapSnapshot);
}

Accessing the block

With the process identifier, starting address of the heap block and the size of the heap block, we are now ready to copy the memory into a buffer, and display it in some fashion (note: for simplicity, all formatting code is not shown).  In the demo code, I used an edit control.

LPBYTE pBuffer;
BYTE byte;
DWORD dwBytesRead,
      dwBlock,
      dwOffset;
CString strLine,
        strArr;

pBuffer = new BYTE[dwBlockSize];

if (Toolhelp32ReadProcessMemory(dwProcessId, (LPCVOID) dwBaseAddress, 
    pBuffer, dwBlockSize, &dwBytesRead) == TRUE)
{
    // go through the entire block
    for (dwBlock = 0; dwBlock < dwBlockSize; dwBlock += 16)
    {
        strLine.Format("[%08x]:  ", dwBaseAddress + dwBlock);

        strArr.Empty();

        // we'll use 16 bytes per line
        for (dwOffset = 0; dwOffset < 16; dwOffset++)        
        {
            byte = *(pBuffer + dwBlock + dwOffset);
            
            strLine.Format("%02x ", byte);                        

            // account for non-printable characters
           if (32 <= byte && byte < 127)                
               strArr += byte;            
           else                
               strArr += '·';
        }

        strLine = "  " + strArr + "\r\n";
    }
}

delete [] pBuffer;

That's the bulk of it.  Depending on the size of the block being displayed, it might take bit to go through it all. 

There are various ways of displaying this sort of data.  This particular style reminds me of the days when Windows was still a text-base shell!

Notes

When I started putting this article together earlier in the week, I did not find any articles on CP that showed how to use the Toolhelp32ReadProcessMemory() API.  I found a few sites that mentioned it in various languages, though.  An article by weariless demonstrating VirtualQueryEx() and ReadProcessMemory() was recently contributed.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

DavidCrow

Software Developer (Senior)
Pinnacle Business Systems
United States United States

Member


The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.
 
HTTP 404 - File not found
Internet Information Services


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralOk. Very nice... PinmemberVicMackey18:18 14 Sep '07  
GeneralNO WORK ON XP SP1 EITHER [pls remove] Pinmembereaster_200718:04 20 Feb '06  
QuestionRe: NO WORK ON XP SP1 EITHER [pls remove] PinmemberDavidCrow2:26 21 Feb '06  
AnswerRe: NO WORK ON XP SP1 EITHER [pls remove] Pinmembereaster_200712:45 21 Feb '06  
QuestionRe: NO WORK ON XP SP1 EITHER [pls remove] PinmemberDavidCrow2:26 22 Feb '06  
GeneralI am getting system error 8 (out of memory). Pinmemberignoranceisbliss14:13 18 Jan '06  
QuestionRe: I am getting system error 8 (out of memory). PinmemberDavidCrow2:31 19 Jan '06  
AnswerRe: I am getting system error 8 (out of memory). Pinmemberignoranceisbliss11:07 19 Jan '06  
GeneralRe: I am getting system error 8 (out of memory). Pinmemberignoranceisbliss7:10 20 Jan '06  
GeneralDonot work on Windows XP PinmemberM.Shoaib Khan8:35 21 May '04  
QuestionRe: Donot work on Windows XP PinmemberDavidCrow8:58 21 May '04  
GeneralRe: Donot work on Windows XP PinsussS. R.9:52 30 May '04  
GeneralRe: Donot work on Windows XP PinmemberDavidCrow9:17 31 May '04  
GeneralRe: Donot work on Windows XP PinsussS. R.12:20 31 May '04  
GeneralRe: Donot work on Windows XP PinmemberDavidCrow2:34 1 Jun '04  
GeneralRe: Donot work on Windows XP PinsussS. R.3:19 1 Jun '04  
GeneralRe: Donot work on Windows XP PinmemberDavidCrow3:32 1 Jun '04  
GeneralRe: Donot work on Windows XP PinsussS. R.3:41 1 Jun '04  
GeneralRe: Donot work on Windows XP PinmemberDavidCrow3:55 1 Jun '04  
GeneralRe: Donot work on Windows XP PinsussS. R.3:57 1 Jun '04  
GeneralViewing modules PinmemberTom Wright11:18 6 Feb '04  
GeneralRe: Viewing modules PinmemberDavidCrow5:27 3 May '04  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120517.1 | Last Updated 4 Sep 2003
Article Copyright 2003 by DavidCrow
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid