Click here to Skip to main content
15,070,111 members
Articles / Desktop Programming / MFC
Article
Posted 3 Sep 2003

Stats

99.3K views
1.4K downloads
20 bookmarked

Toolhelp32ReadProcessMemory

Rate me:
Please Sign up or sign in to vote.
3.50/5 (8 votes)
3 Sep 20033 min read
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

Share

About the Author

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

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

Comments and Discussions

 
GeneralOk. Very nice... Pin
VicMackey14-Sep-07 18:18
MemberVicMackey14-Sep-07 18:18 
GeneralNO WORK ON XP SP1 EITHER [pls remove] Pin
easter_200720-Feb-06 18:04
Membereaster_200720-Feb-06 18:04 
QuestionRe: NO WORK ON XP SP1 EITHER [pls remove] Pin
David Crow21-Feb-06 2:26
MemberDavid Crow21-Feb-06 2:26 
AnswerRe: NO WORK ON XP SP1 EITHER [pls remove] Pin
easter_200721-Feb-06 12:45
Membereaster_200721-Feb-06 12:45 
QuestionRe: NO WORK ON XP SP1 EITHER [pls remove] Pin
David Crow22-Feb-06 2:26
MemberDavid Crow22-Feb-06 2:26 
GeneralI am getting system error 8 (out of memory). Pin
ignoranceisbliss18-Jan-06 14:13
Memberignoranceisbliss18-Jan-06 14:13 
QuestionRe: I am getting system error 8 (out of memory). Pin
David Crow19-Jan-06 2:31
MemberDavid Crow19-Jan-06 2:31 
AnswerRe: I am getting system error 8 (out of memory). Pin
ignoranceisbliss19-Jan-06 11:07
Memberignoranceisbliss19-Jan-06 11:07 
GeneralRe: I am getting system error 8 (out of memory). Pin
ignoranceisbliss20-Jan-06 7:10
Memberignoranceisbliss20-Jan-06 7:10 
GeneralDonot work on Windows XP Pin
abc87621-May-04 8:35
Memberabc87621-May-04 8:35 
QuestionRe: Donot work on Windows XP Pin
David Crow21-May-04 8:58
MemberDavid Crow21-May-04 8:58 
GeneralRe: Donot work on Windows XP Pin
KANE541030-May-04 9:52
MemberKANE541030-May-04 9:52 
GeneralRe: Donot work on Windows XP Pin
David Crow31-May-04 9:17
MemberDavid Crow31-May-04 9:17 
GeneralRe: Donot work on Windows XP Pin
KANE541031-May-04 12:20
MemberKANE541031-May-04 12:20 
GeneralRe: Donot work on Windows XP Pin
David Crow1-Jun-04 2:34
MemberDavid Crow1-Jun-04 2:34 
GeneralRe: Donot work on Windows XP Pin
KANE54101-Jun-04 3:19
MemberKANE54101-Jun-04 3:19 
GeneralRe: Donot work on Windows XP Pin
David Crow1-Jun-04 3:32
MemberDavid Crow1-Jun-04 3:32 
GeneralRe: Donot work on Windows XP Pin
KANE54101-Jun-04 3:41
MemberKANE54101-Jun-04 3:41 
GeneralRe: Donot work on Windows XP Pin
David Crow1-Jun-04 3:55
MemberDavid Crow1-Jun-04 3:55 
GeneralRe: Donot work on Windows XP Pin
KANE54101-Jun-04 3:57
MemberKANE54101-Jun-04 3:57 
GeneralViewing modules Pin
Tom Wright6-Feb-04 11:18
MemberTom Wright6-Feb-04 11:18 
GeneralRe: Viewing modules Pin
David Crow3-May-04 5:27
MemberDavid Crow3-May-04 5:27 

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

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