Vider la mémoire d'un processus Linux dans un fichier

Réponses:

46

Je ne suis pas sûr de savoir comment vider toute la mémoire dans un fichier sans le faire plusieurs fois (si quelqu'un connaît un moyen automatisé d'obtenir que gdb le fasse, merci de me le faire savoir), mais les procédures suivantes fonctionnent pour tout lot de mémoire en supposant que vous le sachiez le pid:

$ cat /proc/[pid]/maps

Ce sera dans le format (exemple):

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

Choisissez un lot de mémoire (par exemple, 00621000-00622000), puis utilisez gdb en tant que racine pour l'attacher au processus et videz cette mémoire:

$ gdb --pid [pid]
(gdb) dump memory /root/output 0x00621000 0x00622000

Ensuite, analysez / root / output avec la commande strings, moins vous voulez le PuTTY sur tout votre écran.

James L
la source
1
Existe-t-il un moyen de le faire simplement en bash / sh sans gdb?
Programming4life
3
@ Programming4life gcore (1)
julian
51

J'ai fait un script qui accomplit cette tâche.

L'idée vient de la réponse de James Lawrie et de cet article: http://www.linuxforums.org/forum/programming-scripting/52375-reading-memory-other-processes.html#post287195

#!/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

mettre ceci dans un fichier (par exemple "dump-all-memory-of-pid.sh") et le rendre exécutable

usage: ./dump-all-memory-of-pid.sh [pid]

La sortie est imprimée dans des fichiers avec les noms suivants: pid-startaddress-stopaddress.dump

Les dépendances: gdb

A. Nilsson
la source
2
Impressionnant! Je viens de l'utiliser pour découvrir quel script une instance mystérieuse de bash était en cours d'exécution.
Tobia
Pourquoi recherchez-vous uniquement des plages avec des rw-pautorisations?
mxmlnkn
@mxmlnkn C'est data ( rw-p), les autres plages sont pour code ( r-xp). Si vous voulez un dump des deux, alors allez-y et échangez greppar exemple cat.
A. Nilsson
39

essayer

    gcore $pid

$pidest le nombre actuel du pid; pour plus d'informations, voir:info gcore

le dump peut prendre un peu de temps, et une partie de la mémoire peut ne pas être lisible, mais est assez bonne ... sachez aussi qu'il peut créer de gros fichiers, je viens de créer un fichier de 2 Go de cette façon ..

Puissance du Verseau
la source
1
Le gcoredumping est-il un fichier fragmenté?
CMCDragonkai
3

l'homme proc dit:

/ proc / [pid] / mem Ce fichier peut être utilisé pour accéder aux pages de la mémoire d'un processus via open (2), read (2) et lseek (2).

Peut-être que cela peut vous aider

Dom
la source
1
Cela ne suffit pas, la lecture d'un autre processus nécessite une combinaison de / proc / <pid> / {mem, * maps}, ptrace et de la gestion du signal pour éviter de suspendre le processus cible.
Tobu
@Tobu En effet . J'ai écrit un script de validation de concept .
Gilles 'SO- arrête d'être méchant'
3

J'ai également créé mon propre programme pour vider toute la mémoire du processus, elle est en C et peut donc être compilée de manière croisée sur Android, ce dont j'avais besoin.

Vous pouvez également spécifier une adresse IP et un port TCP. Code source ici .

Tal Aloni
la source
2

Solution pure bash:

procdump () 
{ 
    cat /proc/$1/maps | grep "rw-p" | awk '{print $1}' | ( IFS="-"
    while read a b; do
        count=$(( bd-ad ))
        ad=$(printf "%llu" "0x$a")
        bd=$(printf "%llu" "0x$b")
        dd if=/proc/$1/mem bs=1 skip=$ad count=$count of=$1_mem_$a.bin
    done )
}

Utilisation: PID procdump

pour un dépotoir plus propre:

procdump () 
{ 
    cat /proc/$1/maps | grep -Fv ".so" | grep " 0 " | awk '{print $1}' | ( IFS="-"
    while read a b; do
        ad=$(printf "%llu" "0x$a")
        bd=$(printf "%llu" "0x$b")
        dd if=/proc/$1/mem bs=1 skip=$ad count=$(( bd-ad )) of=$1_mem_$a.bin
    done )
}
Zibri
la source
Donc, d'après ce que j'ai compris, l'idée de nettoyage est que seuls les fichiers en mémoire ont une taille attachée à la région mémoire contrairement à la mémoire réelle de l'application, qui a la taille 0 (la taille réellement utilisée est inconnue du OS).
Mxmlnkn
Un problème que j'ai avec ce script est que la taille de bloc de 1 conduit à une bande passante de ~ 30 Ko / s trop lente comparée à l'utilisation d'une taille de bloc égale à la taille de la page (4096 pour moi) pour laquelle j'obtiens ~ 100 Mo / s! Voir ici . getconf PAGESIZEest utilisé pour obtenir la taille de la page et ensuite les adresses et les comptes sont divisés par elle.
mxmlnkn
0

Si vous souhaitez vider un segment de mémoire distinct du processus en cours sans créer un fichier core énorme (par exemple avec gcore), vous pouvez utiliser un petit outil à partir d' ici . Il existe également une ligne dans README si vous souhaitez transférer tous les segments lisibles dans des fichiers séparés.

Nopius
la source