Reading living process memory without interrupting it

Asked
Active3 hr before
Viewed126 times

7 Answers

readingprocess
90%

(I found it on this site https://serverfault.com/questions/173999/dump-a-linux-processs-memory-to-file),Since the 3.2 version of the kernel. You can use the process_vm_readv system call to read process memory without interruption., Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers ,Thanks for contributing an answer to Stack Overflow!

If you have root access and are on a linux system, you can use the following linux script (adapted from Gilles' excellent unix.stackexchange.com answer and the answer originally given in the question above but including SyntaxErrors and not being pythonic):

#!/usr/bin/env python

import re
import sys

def print_memory_of_pid(pid, only_writable = True):
   ""
" 
Run as root, take an integer PID and
return the contents of memory to STDOUT ""
"
memory_permissions = 'rw'
if only_writable
else 'r-'
sys.stderr.write("PID = %d" % pid)
with open("/proc/%d/maps" % pid, 'r') as maps_file:
   with open("/proc/%d/mem" % pid, 'r', 0) as mem_file:
   for line in maps_file.readlines(): #
for each mapped region
m = re.match(r '([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r][-w])', line)
if m.group(3) == memory_permissions:
   sys.stderr.write("\nOK : \n" + line + "\n")
start = int(m.group(1), 16)
if start > 0xFFFFFFFFFFFF:
   continue
end = int(m.group(2), 16)
sys.stderr.write("start = " + str(start) + "\n")
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
print chunk, # dump contents to standard output
else :
   sys.stderr.write("\nPASS : \n" + line + "\n")

if __name__ == '__main__': # Execute this code when run from the commandline.
try:
   assert len(sys.argv) == 2, "Provide exactly 1 PID (process ID)"
pid = int(sys.argv[1])
print_memory_of_pid(pid)
except(AssertionError, ValueError) as e:
   print "Please provide 1 PID as a commandline argument."
print "You entered: %s" % ' '.join(sys.argv)
raise e

If you save this as write_mem.py, you can run this (with python2.6 or 2.7) or early in python2.5 (if you add from __future__ import with_statement) as:

sudo python write_mem.py 1234 > pid1234_memory_dump
load more v
88%

If you have root access and are on a linux system, you can use the following linux script (adapted from Gilles' excellent unix.stackexchange.com answer and the answer originally given in the question above but including SyntaxErrors and not being pythonic):,Since the 3.2 version of the kernel. You can use the process_vm_readv system call to read process memory without interruption.,However, I believe you cannot avoid some kind of synchronization (perhaps with ptrace(2), as gdb does), since the process 1234 can (and does) alter its address space at any time (with mmap & related syscalls).,If you save this as write_mem.py, you can run this (with python2.6 or 2.7) or early in python2.5 (if you add from __future__ import with_statement) as:

If you have root access and are on a linux system, you can use the following linux script (adapted from Gilles' excellent unix.stackexchange.com answer and the answer originally given in the question above but including SyntaxErrors and not being pythonic):

#!/usr/bin/env python

import re
import sys

def print_memory_of_pid(pid, only_writable = True):
   ""
" 
Run as root, take an integer PID and
return the contents of memory to STDOUT ""
"
memory_permissions = 'rw'
if only_writable
else 'r-'
sys.stderr.write("PID = %d" % pid)
with open("/proc/%d/maps" % pid, 'r') as maps_file:
   with open("/proc/%d/mem" % pid, 'r', 0) as mem_file:
   for line in maps_file.readlines(): #
for each mapped region
m = re.match(r '([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r][-w])', line)
if m.group(3) == memory_permissions:
   sys.stderr.write("\nOK : \n" + line + "\n")
start = int(m.group(1), 16)
if start > 0xFFFFFFFFFFFF:
   continue
end = int(m.group(2), 16)
sys.stderr.write("start = " + str(start) + "\n")
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
print chunk, # dump contents to standard output
else :
   sys.stderr.write("\nPASS : \n" + line + "\n")

if __name__ == '__main__': # Execute this code when run from the commandline.
try:
   assert len(sys.argv) == 2, "Provide exactly 1 PID (process ID)"
pid = int(sys.argv[1])
print_memory_of_pid(pid)
except(AssertionError, ValueError) as e:
   print "Please provide 1 PID as a commandline argument."
print "You entered: %s" % ' '.join(sys.argv)
raise e

If you save this as write_mem.py, you can run this (with python2.6 or 2.7) or early in python2.5 (if you add from __future__ import with_statement) as:

sudo python write_mem.py 1234 > pid1234_memory_dump
ssize_t process_vm_readv(pid_t pid,
   const struct iovec * local_iov,
      unsigned long liovcnt,
      const struct iovec * remote_iov,
         unsigned long riovcnt,
         unsigned long flags);
load more v
72%

Why isn't cat able to print its own memory (/proc/self/mem)? And what is this strange “no such process” error when I try to print the shell's memory (/proc/$$/mem, obviously the process exists)? How can I read from /proc/$pid/mem, then?,If you try to read from the mem pseudo-file of another process, it doesn't work: you get an ESRCH (No such process) error.,A process running as root can read any process's memory, without needing to call ptrace, but the observed process must be stopped, or the read will still return ESRCH.,The program uses /proc/$pid/maps to find all of the mapped memory regions of the process, and then read those regions from /proc/$pid/mem, one page at a time. those pages are written to stdout or the IP address and TCP port you specified.

The way to find out what parts of the process memory are mapped is to read /proc/$pid/maps. This file contains one line per mapped region, looking like this:

08048000 - 08054000 r - xp 00000000 08: 01 828061 / bin / cat
08 c9b000 - 08 cbc000 rw - p 00000000 00: 00 0[heap]

Here's a proof-of-concept script that dumps the contents of its own memory.

#! /usr/bin/env python

import re
maps_file = open("/proc/self/maps", 'r')
mem_file = open("/proc/self/mem", 'rb', 0)
output_file = open("self.dump", 'wb')
for line in maps_file.readlines(): #
for each mapped region
m = re.match(r '([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
if m.group(3) == 'r': #
if this is a readable region
start = int(m.group(1), 16)
end = int(m.group(2), 16)
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
output_file.write(chunk) # dump contents to standard output
maps_file.close()
mem_file.close()
output_file.close()

Here's some sample C code to attach to a process and read a chunk its of mem file (error checking omitted):

sprintf(mem_file_name, "/proc/%d/mem", pid);
mem_fd = open(mem_file_name, O_RDONLY);
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
waitpid(pid, NULL, 0);
lseek(mem_fd, offset, SEEK_SET);
read(mem_fd, buf, _SC_PAGE_SIZE);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
load more v
65%

I would like to explore the memory of a living process, and when I do so, the process must not get disturbed - so attaching gdb to the process (which would stop it) is not an option. Therefore I would like to get this info from /proc/kcore (if you know of another way to do this please let me know). So I made a little experiment. I created a file called TEST with only "EXTRATESTEXTRA" inside. Then I opened it with less,The situation is different if the monitored process 1234 is not arbitrary, but if you could improve it to communicate somehow with the monitoring process.,I'm not sure to understand why do you ask this. And gdb is able to watch some location without stopping the process.,How can I read /proc/kmap to get the memory that belongs to a process which's pid I know ?

I would like to explore the memory of a living process, and when I do so, the process must not get disturbed - so attaching gdb to the process (which would stop it) is not an option. Therefore I would like to get this info from /proc/kcore (if you know of another way to do this please let me know). So I made a little experiment. I created a file called TEST with only "EXTRATESTEXTRA" inside. Then I opened it with less

$ less TEST

I got the PID of this process with

$ ps aux | grep TEST
user 7785 0.0 0.0 17944 992 pts / 8 S + 16: 15 0: 00 less TEST
user 7798 0.0 0.0 13584 904 pts / 9 S + 16: 16 0: 00 grep TEST

And then I used this script to create a dump of all files :

#!/bin/bash

grep rw - p / proc / $1 / maps | sed - n 's/^([0-9a-f]*)-([0-9a-f]*) .*$/1 2/p' |
   while read start stop;
do gdb--batch--pid $1 - ex "dump memory $1-$start-$stop.dump 0x$start 0x$stop";
done

(I found it on this site https://serverfault.com/questions/173999/dump-a-linux-processs-memory-to-file)

$ sudo. / dump_all_pid_memory.sh 7785

After this, I looked for "TRATESTEX" in all dumped files :

$ grep - a - o - e '...TRATESTEX...'.
/*.dump
./7785-00624000-00628000.dump:HEXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA
./7785-00b8f000-00bb0000.dump:EXTRATESTEXTRA

So I concluded that there must be an occurance of this string somewhere between 0x00624000 and 0x00628000 . Therefore I converted the offsets into decimal numbers and used dd to get the memory from /proc/kcore :

$ sudo dd
if = "/proc/kcore" of = "./y.txt"
skip = "0"
count = "1638400"
bs = 1
load more v
75%

Now _ _do_IRQ( ) checks whether it must really handle the interrupt. There are three cases in which nothing has to be done. These are discussed in the following list.,Interrupt handler flexibility is achieved in two distinct ways, as discussed in the following list.,Counter of unhandled interrupt occurrences on the IRQ line (for diagnostic use only).,The handler must execute with interrupts disabled.

    for (i = 0; i < NR_IRQS; i++)
       if (i + 32 != 128)
          set_intr_gate(i + 32, interrupt[i]);
    struct hw_interrupt_type i8259A_irq_type = {
       .typename = "XT-PIC",
       .startup = startup_8259A_irq,
       .shutdown = shutdown_8259A_irq,
       .enable = enable_8259A_irq,
       .disable = disable_8259A_irq,
       .ack = mask_and_ack_8259A,
       .end = end_8259A_irq,
       .set_affinity = NULL
    };
load more v
40%

I recently put together a little game memory cheat tool called MemDig. It can find the address of a particular game value (score, lives, gold, etc.) after being given that value at different points in time. With the address, it can then modify that value to whatever is desired.,And then to read or write:,The process will (and must) be stopped during this procedure, so do your reads/writes quickly and get out. The kernel will deliver the writes to the other process’ virtual memory.,The catch is that while you can open this file, you can’t actually read or write on that file without attaching to the process as a debugger. You’ll just get EIO errors. To attach, use ptrace() with PTRACE_ATTACH. This asynchronously delivers a SIGSTOP signal to the target, which has to be waited on with waitpid().

DWORD access = PROCESS_VM_READ |
   PROCESS_QUERY_INFORMATION |
   PROCESS_VM_WRITE |
   PROCESS_VM_OPERATION;
HANDLE proc = OpenProcess(access, FALSE, pid);
load more v
22%

Demo program 1: allocate memory without using it. ,OK. This is very bad. People lose long-running processes, lose weeks of computation, just because the kernel is an optimist.,Demo program 2: allocate memory and actually touch it all. ,Demo program 3: first allocate, and use later.

#include <asm /io.h>

   phys_addr = virt_to_phys(virt_addr);
   virt_addr = phys_to_virt(phys_addr);
   bus_addr = virt_to_bus(virt_addr);
   virt_addr = bus_to_virt(bus_addr);
load more v

Other "reading-process" queries related to "Reading living process memory without interrupting it"