I’m not sure how you dump all the memory to a file without doing this repeatedly (if anyone knows an automated way to get gdb to do this please let me know), but the following works for any one batch of memory assuming you know the pid:
$ cat /proc/[pid]/maps
This will be in the format (example):
00400000-00421000 r-xp 00000000 08:01 592398 /usr/libexec/dovecot/pop3-login 00621000-00622000 rw-p 00021000 08:01 592398 /usr/libexec/dovecot/pop3-login 00622000-0066a000 rw-p 00622000 00:00 0 [heap] 3e73200000-3e7321c000 r-xp 00000000 08:01 229378 /lib64/ld-2.5.so 3e7341b000-3e7341c000 r--p 0001b000 08:01 229378 /lib64/ld-2.5.so
Pick one batch of memory (so for example 00621000-00622000) then use gdb as root to attach to the process and dump that memory:
$ gdb --pid [pid] (gdb) dump memory /root/output 0x00621000 0x00622000
Then analyse /root/output with the strings command, less you want the PuTTY all over your screen.
The following quick-and-dirty python script dumps the memory of a process to stdout. This has the side effect of loading any swapped out page or mapped file. Call it as cat_proc_mem 123 456 789 where the arguments are process IDs.
This script is completely specific to Linux. It may be adaptable to other systems with a similar /proc structure (Solaris?), but forget about running it on e.g. *BSD. Even on Linux, you may need to change the definition of c_pid_t and the values of PTRACE_ATTACH and PTRACE_DETACH. This is a proof-of-principle script, not meant as an example of good programming practices. Use at your own risk.
Linux makes the memory of a process available as /proc/$pid/mem. Only certain address ranges are readable. These ranges can be found by reading the memory mapping information from the text file /proc/$pid/maps. The pseudo-file /proc/$pid/mem cannot be read by all processes that have the permission to read it: the reader process must have called ptrace(PTRACE_ATTACH, $pid)
#! /usr/bin/env python import ctypes, re, sys ## Partial interface to ptrace(2), only for PTRACE_ATTACH and PTRACE_DETACH. c_ptrace = ctypes.CDLL("libc.so.6").ptrace c_pid_t = ctypes.c_int32 # This assumes pid_t is int32_t c_ptrace.argtypes = [ctypes.c_int, c_pid_t, ctypes.c_void_p, ctypes.c_void_p] def ptrace(attach, pid): op = ctypes.c_int(16 if attach else 17) #PTRACE_ATTACH or PTRACE_DETACH c_pid = c_pid_t(pid) null = ctypes.c_void_p() err = c_ptrace(op, c_pid, null, null) if err != 0: raise SysError, 'ptrace', err ## Parse a line in /proc/$pid/maps. Return the boundaries of the chunk ## the read permission character. def maps_line_range(line): m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line) return [int(m.group(1), 16), int(m.group(2), 16), m.group(3)] ## Dump the readable chunks of memory mapped by a process def cat_proc_mem(pid): ## Apparently we need to ptrace(PTRACE_ATTACH, $pid) to read /proc/$pid/mem ptrace(True, int(pid)) ## Read the memory maps to see what address ranges are readable maps_file = open("/proc/" + pid + "/maps", 'r') ranges = map(maps_line_range, maps_file.readlines()) maps_file.close() ## Read the readable mapped ranges mem_file = open("/proc/" + pid + "/mem", 'r', 0) for r in ranges: if r[2] == 'r': mem_file.seek(r[0]) chunk = mem_file.read(r[1] - r[0]) print chunk, mem_file.close() ## Cleanup ptrace(False, int(pid)) if __name__ == "__main__": for pid in sys.argv[1:]: cat_proc_mem(pid)
In this case, we are going to get dump information of a running apache. Append below code and execute.
#!/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
Get the pid of your apache process.
pgrep -uroot apache2
Dump the process’s memory
mkdir /tmp/apache_dump && cd /tmp/apache_dump sh /path/to/dump-all-memory-of-pid.sh <PID>
grep all of the dump files for something that you expect to be in the apache config file.
grep DocumentRoot*
open the matched dump file(s) in vim and search for the string.
vim 24374-7f159d56c000-7f159d72c000.dump
Search by typing “/”, eg “/DocumentRoot”, then simply copy out the text that you want.
Thank me later.