/proc/$pid/maps
/proc/$pid/memmuestra el contenido de la memoria de $ pid mapeado de la misma manera que en el proceso, es decir, el byte en el desplazamiento x en el pseudoarchivo es el mismo que el byte en la dirección x en el proceso. Si una dirección no está asignada en el proceso, la lectura del desplazamiento correspondiente en el archivo devuelve EIO(error de entrada / salida). Por ejemplo, dado que la primera página de un proceso nunca se asigna (por lo que la eliminación de la referencia a un NULLpuntero falla de manera limpia en lugar de acceder involuntariamente a la memoria real), leer el primer byte /proc/$pid/memsiempre produce un error de E / S.
La manera de averiguar qué partes de la memoria de proceso están mapeadas es leer /proc/$pid/maps. Este archivo contiene una línea por región asignada, con este aspecto:
08048000-08054000 r-xp 00000000 08:01 828061 /bin/cat
08c9b000-08cbc000 rw-p 00000000 00:00 0 [heap]
Los dos primeros números son los límites de la región (direcciones del primer byte y el byte después del último, en hexa). La siguiente columna contiene los permisos, luego hay información sobre el archivo (desplazamiento, dispositivo, inodo y nombre) si se trata de una asignación de archivo. Consulte la proc(5)página de manual o Understanding Linux / proc / id / maps para obtener más información.
Aquí hay un script de prueba de concepto que volca el contenido de su propia memoria.
#! /usr/bin/env python
import re
maps_file = open("/proc/self/maps", 'r')
mem_file = open("/proc/self/mem", 'r', 0)
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
print chunk, # dump contents to standard output
maps_file.close()
mem_file.close()
/proc/$pid/mem
Si intentas leer el mempseudoarchivo de otro proceso, no funciona: obtienes un ESRCHerror (No hay tal proceso).
Los permisos en /proc/$pid/mem( r--------) son más liberales de lo que debería ser el caso. Por ejemplo, no debería poder leer la memoria de un proceso setuid. Además, tratar de leer la memoria de un proceso mientras el proceso lo modifica podría darle al lector una visión inconsistente de la memoria, y lo que es peor, había condiciones de carrera que podían rastrear versiones anteriores del kernel de Linux (de acuerdo con este hilo lkml , aunque yo No sé los detalles). Por lo tanto, se necesitan verificaciones adicionales:
- El proceso que desea leer
/proc/$pid/memdebe adjuntarse al proceso usando ptracecon la PTRACE_ATTACHbandera. Esto es lo que hacen los depuradores cuando comienzan a depurar un proceso; también es lo que stracehace a las llamadas al sistema de un proceso. Una vez que el lector haya terminado de leer /proc/$pid/mem, debe separarse llamando ptracecon la PTRACE_DETACHbandera.
- El proceso observado no debe estar ejecutándose. Normalmente, la llamada
ptrace(PTRACE_ATTACH, …)detendrá el proceso de destino (envía una STOPseñal), pero hay una condición de carrera (la entrega de la señal es asíncrona), por lo que el rastreador debe llamar wait(como se documenta en ptrace(2)).
Un proceso que se ejecuta como root puede leer la memoria de cualquier proceso, sin necesidad de llamar ptrace, pero el proceso observado debe detenerse o la lectura aún regresará ESRCH.
En la fuente del kernel de Linux, el código que proporciona entradas por proceso /procestá en fs/proc/base.c, y la función para leer /proc/$pid/memes mem_read. La verificación adicional es realizada por check_mem_permission.
Aquí hay un código C de muestra para adjuntar a un proceso y leer un fragmento de su memarchivo (se omite la comprobación de errores):
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);
Ya publiqué un script de prueba de concepto para descargar /proc/$pid/memen otro hilo .