This is an old revision of the document!
Volcado de la memoria usada por un proceso usando Bash
Esta función en bash hace un volcado mediante “dd” en “/proc/PID/maps” para obtener todo lo que el proceso tiene mapeado a memoria. Este archivo hace referencia a una parte de lo denominado memoria virtual (mmap), contiendo las regiones de memoria actualmente asignadas.
La memoria virtual permite a cada proceso reclamar la memoria física disponible que está presente en la máquina. Es decir, cada proceso actúa como si fuera el único proceso que se ejecuta en el sistema operativo. Este enfoque tiene muchas ventajas, por ejemplo, ofrece una experiencia mucho mejor para el desarrollador, ya que simplifica las nuevas solicitudes de memoria. Además, mejora la seguridad, ya que aísla los procesos para que no puedan interferir entre sí. Por último, aumenta el rendimiento porque cuando se produce un error, sólo afecta a un único proceso sin añadir sobrecarga al resto de procesos. Por otro lado si la cantidad total de memoria virtual excede la memoria real disponible (incluyendo el espacio de intercambio) se ejecutará el famoso “out-of-memory killer”.
cat /proc/18923/maps 55ddd3e14000-55ddd3e16000 r--p 00000000 08:01 805987379 /usr/bin/sleep 55ddd3e16000-55ddd3e19000 r-xp 00002000 08:01 805987379 /usr/bin/sleep 55ddd3e19000-55ddd3e1a000 r--p 00005000 08:01 805987379 /usr/bin/sleep 55ddd3e1b000-55ddd3e1c000 r--p 00006000 08:01 805987379 /usr/bin/sleep 55ddd3e1c000-55ddd3e1d000 rw-p 00007000 08:01 805987379 /usr/bin/sleep 55ddd4b2b000-55ddd4b4c000 rw-p 00000000 00:00 0 [heap] 7f628dc00000-7f628dee9000 r--p 00000000 08:01 268699512 /usr/lib/locale/locale-archive 7f628e07a000-7f628e07d000 rw-p 00000000 00:00 0 7f628e07d000-7f628e09f000 r--p 00000000 08:01 537347961 /usr/lib/libc.so.6 7f628e09f000-7f628e1fa000 r-xp 00022000 08:01 537347961 /usr/lib/libc.so.6 7f628e1fa000-7f628e251000 r--p 0017d000 08:01 537347961 /usr/lib/libc.so.6 7f628e251000-7f628e255000 r--p 001d4000 08:01 537347961 /usr/lib/libc.so.6 7f628e255000-7f628e257000 rw-p 001d8000 08:01 537347961 /usr/lib/libc.so.6 7f628e257000-7f628e264000 rw-p 00000000 00:00 0 7f628e27c000-7f628e27e000 rw-p 00000000 00:00 0 7f628e27e000-7f628e27f000 r--p 00000000 08:01 537360952 /usr/lib/ld-linux-x86-64.so.2 7f628e27f000-7f628e2a5000 r-xp 00001000 08:01 537360952 /usr/lib/ld-linux-x86-64.so.2 7f628e2a5000-7f628e2af000 r--p 00027000 08:01 537360952 /usr/lib/ld-linux-x86-64.so.2 7f628e2af000-7f628e2b1000 r--p 00031000 08:01 537360952 /usr/lib/ld-linux-x86-64.so.2 7f628e2b1000-7f628e2b3000 rw-p 00033000 08:01 537360952 /usr/lib/ld-linux-x86-64.so.2 7ffcf746a000-7ffcf748b000 rw-p 00000000 00:00 0 [stack] 7ffcf7549000-7ffcf754d000 r--p 00000000 00:00 0 [vvar] 7ffcf754d000-7ffcf754f000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
- Dirección inicial y dirección final del mapeo: 55ddd3e14000-55ddd3e16000 : La salida del comando cat se ordena en base a esas direcciones, de menor a mayor.
- Mode (permisos): r–p : especifica qué acciones (lectura, escritua y ejecución) están disponibles en este mapeo y si es privado o compartido.
- Offset: 00002000 : es el desplazamiento inicial en bytes dentro del archivo que se mapea. Esto sólo es visible para los mapeos de archivos, de no ser así el offset es 0.
- Los ids mayor:menor: 08:01 : Estos IDs representan el dispositivo en el que está el archivo mapeado en forma de id mayor y menor. En el ejemplo anterior, 08:01 representa el id mayor y menor del disco duro que tiene el sistema de archivos raíz. Para las asignaciones que no son de archivos, esta columna muestra 00:00.
- ID de inodo del archivo mapeado: 805987379 : Sólo es válido para mapeos de archivos
- La ruta del archivo para ese mapeo: En el caso de que no se trate de un mapeo de archivos, este campo está vacío.
A continuación se muestra la función en bash para realizar el volcado de memoria de un proceso sin incluir las librerías compartidas o ficheros mapeados a disco. Para ello usamos las entradas del fichero maps con el valor de inodo “ 0 ”, que indica que no hay ningún inodo asociado a la región de memoria. A esa memoria sin inodo y por tanto sin ruta a fichero se denomina “anónima”. Una vez obtenidas las direcciones, se obtienen todas las regiones y mediante dd se extraen en el directorio donde se ejecute el comando. Los ficheros tendrán el prefijo del PID_mem_ y posteriormente la región de memoria y la extensión .bin. Para leer dichos ficheros binarios se puede usar xxd o el comando strings.
Volcado de memoria de un PID en concreto.
procdump() ( cat /proc/$1/maps | grep " 0 " | awk '{print $1}' | ( IFS="-" while read a b; do dd if=/proc/$1/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="$1_mem_$a.bin" done ) )
# Forma de uso. procdump 3456
Volcado de memoria de múltiples PIDs usando su nombre (basado en pidof).
procdump() ( for g in `pidof $1` do cat /proc/${g[@]}/maps | grep " 0 " | awk '{print $1}' | ( IFS="-" while read a b; do dd if=/proc/${g[@]}/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="${g[@]}_mem_$a.bin" done ) done )
# Forma de uso.
procdump nginx
A diferencia del anterior ejemplo que se limita a un solo PID, esta variante es útil con aplicaciones que suelen tener varios procesos, como Apache, Nginx, PHP, etc.
pidof nginx 107537 107536 1007 ps aux| grep -i nginx root 1007 0.0 0.4 23900 8852 ? Ss Jul07 0:00 nginx: master process /usr/bin/nginx -g pid /run/nginx.pid; error_log stderr; http 107536 0.0 0.4 24140 9592 ? S Aug01 0:02 nginx: worker process http 107537 0.0 0.5 24140 10364 ? S Aug01 1:17 nginx: worker process
Volcado de memoria de múltiples procesos hijo usando su PPID.
Esta variante es muy similar a la anterior, solo que ahora se usa “pgrep” para obtener los procesos hijos y también hace un volcado de ellos. Es útil en situaciones de hackeo de aplicaciones web. Por ejemplo una instancia Nginx ha sido vulnerada y se están ejecutando comandos. El volcado se realizará de todos los procesos hijos de Nginx (los denominados workers) y también el de todos los procesos hijos de dichos procesos. De esta manera, si un atacante está ejecutando comandos del sistema a partir del proceso Nginx (usando el usuario de Nginx), como puede ser una shell reversa con nc al exterior, se realizará también un volcado de la memoria de dicho comando nc.
procdump() ( # Parent process cat /proc/$1/maps | grep " 0 " | awk '{print $1}' | ( IFS="-" while read a b; do dd if=/proc/$1/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="$1_mem_$a.bin" done ) # Child processes for g in `pgrep -P $1 | xargs` do cat /proc/${g[@]}/maps | grep " 0 " | awk '{print $1}' | ( IFS="-" while read a b; do dd if=/proc/${g[@]}/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="${g[@]}_mem_$a.bin" done ) # If the child process in turn has other child processes, it also performs the dump if [[ $(pgrep -P ${g[@]} | xargs) ]]; then for h in `pgrep -P ${g[@]} | xargs` do cat /proc/${h[@]}/maps | grep " 0 " | awk '{print $1}' | ( IFS="-" while read a b; do dd if=/proc/${h[@]}/mem bs=$( getconf PAGESIZE ) iflag=skip_bytes,count_bytes skip=$(( 0x$a )) count=$(( 0x$b - 0x$a )) of="${g[@]}_${h[@]}_mem_$a.bin" done ) done fi done )
En este caso los ficheros pertenecientes al proceso hijo tiene la nomenclatura PPID_PID_mem_ y posteriormente la región de memoria y la extensión .bin. Para usarse, debe buscarse primeramente cual es el PID que nos interesa. En el caso de Nginx, sería el proceso con el usuario root que inicializa el resto de procesos hijos, en el ejemplo anterior sería el proceso 1007.
# Forma de uso. procdump 1007
Enlaces de interés: mostrar_memoria_real_utilizada_por_un_proceso