Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Reading another process's memory 2

Status
Not open for further replies.

logiclrd

Programmer
Oct 21, 2000
184
CA
The following thread revisited a previous question I answered a long time ago in the QBasic programming forum:

thread314-395032

The issue at hand is reading (and possibly writing) the memory of a process given only its process ID. I asked around when the question was originally asked and was told that the API calls [tt]OpenProcess[/tt] and [tt]ReadProcessMemory[/tt] could be used, but I didn't actually try it myself, and so I couldn't be much more precise than that.

At the request of mthibault, I have looked more deeply into the issue, and have succeeded in this task (it is actually a lot simpler than it might seem from the outside).

The process ID is the DWORD value identifying the process. It is the number listed by the Task Manager in NT-based versions of Windows, and it is not an operating system handle. You can retrieve an operating system handle to the process from the process ID using [tt]OpenProcess[/tt].

[tt]OpenProcess[/tt] takes 3 parameters: permissions requested, inheritability, and the process ID itself. There are a number of permissions and they are listed on the MSDN page for [tt]OpenProcess[/tt]. The flag used in this example is [tt]PROCESS_VM_READ[/tt], which grants read access to the process's virtual memory space (through [tt]ReadProcessMemory[/tt]). Other flags of interest are [tt]PROCESS_VM_WRITE[/tt] and [tt]SYNCHRONIZE[/tt], the latter of which allows the handle to be used in [tt]Wait*[/tt] API functions (e.g. [tt]WaitForSingleObject[/tt]) to block until the process exits.

Once the process has been successfully opened and the handle has been retrieved, [tt]ReadProcessMemory[/tt] can be used to get blocks of memory. It takes the handle and a buffer to fill, and returns a logically true value if the operation was successful.

I haven't investigated how to retrieve a map of the process's virtual memory, though I'm sure this is possible as many debuggers do it. However, the following example maps out the memory simply by trying to read all of it. It groups together unreadable pages into a single line of the form &quot;<n> unreadable pages starting at <address>&quot;, and it displays a hex dump (32 bytes per row) of readable pages. If you pipe the output to a file, be aware that the resulting file will be approximately 2.5 times the size of the process's virtual memory, which includes all DLLs it has loaded.

Anyway, without further ado, here is source code that runs [tt]notepad.exe[/tt] and outputs its entire memory space:
[tt]
#include <windows.h>
#include <stdio.h>

#define PAGE_SIZE 4096

void dump_page_hex(unsigned char *page, char *baseAddr);

int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;

memset(&si, 0, sizeof(si));
si.cb = sizeof(si);

CreateProcess(&quot;x:\\windows\\system32\\notepad.exe&quot;, &quot;&quot;, NULL, NULL, FALSE,
0, NULL, &quot;x:\\windows&quot;, &si, &pi);

HANDLE hProcess =
OpenProcess(PROCESS_VM_READ,
FALSE,
pi.dwProcessId);

ASSERT(hProcess && (hProcess != INVALID_HANDLE_VALUE));

unsigned char page[PAGE_SIZE];
int unreadable_pages = 0;

for (__int64 baseAddr=0; (baseAddr & 0x80000000) == 0; baseAddr += PAGE_SIZE)
{
if (!ReadProcessMemory(hProcess, (char *)baseAddr, page, PAGE_SIZE, NULL))
unreadable_pages++;
else
{
if (unreadable_pages)
printf(&quot;%d unreadable pages starting at %08p\n&quot;,
unreadable_pages, baseAddr - unreadable_pages*PAGE_SIZE),
unreadable_pages = 0;

dump_page_hex(page, (char *)baseAddr);
}
}
}

void dump_page_hex(unsigned char *page, char *baseAddr)
{
int bytes_left = PAGE_SIZE;

while (bytes_left)
{
int bytes_this_scan = 32;

if (bytes_this_scan > bytes_left)
bytes_this_scan = bytes_left;

bytes_left -= bytes_this_scan;

printf(&quot;%08p: &quot;, baseAddr);

while (bytes_this_scan--)
{
printf(&quot;%02X&quot;, *page);
page++, baseAddr++;
if ((bytes_this_scan & 7) == 0)
printf(&quot; &quot;);
}

printf(&quot;\n&quot;);
}
printf(&quot;\n&quot;);
}
[/tt]
 
Sweet! thanks logiclrd. I can't wait to get a chance to play around with this. I'm sure crackers and the like would be interested in this kind of thing but I hope it will have practical uses too, like finders pointers to values so you can link two applications from different vendors, and maybe this will help me if I go back to reverse engineering Terragen. :)

Very gracious of you, thanks again!

-thibault
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top