La página de manual de Linuxproc(5)
me dice que /proc/$pid/mem
"se puede usar para acceder a las páginas de la memoria de un proceso". Pero un intento directo de usarlo solo me da
$ cat /proc/$$/mem /proc/self/mem
cat: /proc/3065/mem: No such process
cat: /proc/self/mem: Input/output error
¿Por qué no cat
puede imprimir su propia memoria ( /proc/self/mem
)? ¿Y cuál es este extraño error de "no hay tal proceso" cuando intento imprimir la memoria del shell ( /proc/$$/mem
, obviamente, el proceso existe)? ¿Cómo puedo leer /proc/$pid/mem
, entonces?
Respuestas:
/proc/$pid/maps
/proc/$pid/mem
muestra 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 devuelveEIO
(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 unNULL
puntero falla de manera limpia en lugar de acceder involuntariamente a la memoria real), leer el primer byte/proc/$pid/mem
siempre 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: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.
/proc/$pid/mem
Si intentas leer el
mem
pseudoarchivo de otro proceso, no funciona: obtienes unESRCH
error (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:/proc/$pid/mem
debe adjuntarse al proceso usandoptrace
con laPTRACE_ATTACH
bandera. Esto es lo que hacen los depuradores cuando comienzan a depurar un proceso; también es lo questrace
hace a las llamadas al sistema de un proceso. Una vez que el lector haya terminado de leer/proc/$pid/mem
, debe separarse llamandoptrace
con laPTRACE_DETACH
bandera.ptrace(PTRACE_ATTACH, …)
detendrá el proceso de destino (envía unaSTOP
señal), pero hay una condición de carrera (la entrega de la señal es asíncrona), por lo que el rastreador debe llamarwait
(como se documenta enptrace(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
/proc
está enfs/proc/base.c
, y la función para leer/proc/$pid/mem
esmem_read
. La verificación adicional es realizada porcheck_mem_permission
.Aquí hay un código C de muestra para adjuntar a un proceso y leer un fragmento de su
mem
archivo (se omite la comprobación de errores):Ya publiqué un script de prueba de concepto para descargar
/proc/$pid/mem
en otro hilo .fuente
/proc/$pid/mem
directamente (ya sea concat
o condd
cualquier otra cosa) no funciona. Lee mi respuesta./proc/self/mem
. Un proceso puede leer su propio espacio de memoria bien, está leyendo el espacio de memoria de otro proceso que requierePTRACE_ATTACH
.process_vm_readv()
llamada al sistema (Linux 3.2).ESRCH
error en este escenario.Este comando (de gdb) volca la memoria de manera confiable:
Los volcados pueden ser grandes, úselos
-o outfile
si su directorio actual no tiene suficiente espacio.fuente
Cuando ejecuta
cat /proc/$$/mem
la variable$$
es evaluada por bash que inserta su propio pid. Luego ejecuta locat
que tiene un pid diferente. Terminascat
tratando de leer la memoria debash
su proceso padre. Dado que los procesos no privilegiados solo pueden leer su propio espacio de memoria, el núcleo lo niega.Aquí hay un ejemplo:
Tenga en cuenta que se
$$
evalúa a 17823. Veamos qué proceso es ese.Es mi caparazón actual.
Aquí nuevamente se
$$
evalúa a 17823, que es mi caparazón.cat
No puedo leer el espacio de memoria de mi shell.fuente
$pid
sea. Como explico en mi respuesta, leer la memoria de un proceso diferente requiere que lo trates.$$
cuando escribes (y lees)$pid
?$$
y poniendo$pid
al final. Lo transpuse en mi cabeza sin darme cuenta. Toda mi respuesta debería referirse$$
, no$pid
.Aquí hay un pequeño programa que escribí en C:
Uso:
El programa usa / proc / $ pid / maps para encontrar todas las regiones de memoria mapeadas del proceso, y luego lee esas regiones de / proc / $ pid / mem, una página a la vez. esas páginas se escriben en stdout o la dirección IP y el puerto TCP que especificó.
Código (probado en Android, requiere permisos de superusuario):
fuente
write to stdout
inmediatamente arribafwrite(..., stdout)
. Ver programmers.stackexchange.com/questions/119600/…