Speichern Sie den Speicher eines Linux-Prozesses in einer Datei

Antworten:

46

Ich bin mir nicht sicher, wie Sie den gesamten Speicher in eine Datei speichern können, ohne dies wiederholt zu tun (wenn jemand eine automatisierte Methode kennt, um GDB dazu zu bringen, lassen Sie es mich bitte wissen), aber das Folgende funktioniert für einen Stapel Speicher, vorausgesetzt, Sie wissen es die pid:

$ cat /proc/[pid]/maps

Dies wird im Format (Beispiel) sein:

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

Wählen Sie eine Speichercharge aus (z. B. 00621000-00622000), und verwenden Sie dann gdb als Root, um eine Verbindung zum Prozess herzustellen und diesen Speicher zu sichern:

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

Analysieren Sie dann / root / output mit dem Befehl strings, und Sie möchten PuTTY nicht auf dem gesamten Bildschirm sehen.

James L
quelle
1
Gibt es eine Möglichkeit, dies in nur Bash / Sh ohne GDB zu tun?
Programming4life
3
@ Programming4life gcore (1)
Juli
51

Ich habe ein Skript erstellt, das diese Aufgabe erfüllt.

Die Idee stammt von James Lawries Antwort und diesem Beitrag: 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

stelle dies in eine Datei (zB "dump-all-memory-of-pid.sh") und mache es ausführbar

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

Die Ausgabe erfolgt in Dateien mit folgenden Namen: pid-startaddress-stopaddress.dump

Abhängigkeiten: gdb

A. Nilsson
quelle
2
Genial! Ich habe es nur verwendet, um herauszufinden, welches Skript auf einer mysteriösen Bash-Instanz ausgeführt wurde.
Tobia
Warum greifen Sie nur mit Berechtigungen nach Bereichen und geben sie frei rw-p?
mxmlnkn
@mxmlnkn Das sind data ( rw-p), die anderen Bereiche sind für code ( r-xp). Wenn Sie einen Dump von beiden wollen, dann gehen Sie vor und tauschen Sie grepfür zB cat.
A. Nilsson
39

Versuchen

    gcore $pid

wo $pidist die tatsächliche Anzahl der PID; Weitere Informationen finden Sie unter:info gcore

Es kann einige Zeit dauern, bis der Speicherauszug erstellt wird, und ein Teil des Speichers ist möglicherweise nicht lesbar, aber ausreichend. Beachten Sie, dass große Dateien erstellt werden können. Ich habe gerade eine 2-GB-Datei auf diese Weise erstellt.

Wassermann Power
quelle
1
Gibt es gcoreeine Sparse-Datei?
CMCDragonkai
3

Mann proc sagt:

/ proc / [pid] / mem Mit dieser Datei kann über open (2), read (2) und lseek (2) auf die Seiten des Speichers eines Prozesses zugegriffen werden.

Vielleicht kann es dir helfen

Dom
quelle
1
Dies ist nicht ausreichend, da zum Lesen eines anderen Prozesses eine Kombination aus / proc / <pid> / {mem, * maps}, ptrace und einer gewissen Signalbehandlung erforderlich ist, um ein Aufhängen des Zielprozesses zu vermeiden.
Tobu
@ Tobu In der Tat . Ich habe ein Proof-of-Concept-Skript geschrieben .
Gilles 'SO - hör auf böse zu sein'
3

Ich habe mein eigenes Programm erstellt, um auch den gesamten Prozessspeicher zu sichern. Es befindet sich in C, sodass es auf Android überspielt werden kann, was ich auch brauchte.

Sie können auch die IP-Adresse und den TCP-Port angeben. Quellcode hier .

Tal Aloni
quelle
2

Reine bash Lösung:

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 )
}

Verwendung: procdump PID

für eine sauberere Müllkippe:

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
quelle
Soweit ich weiß, besteht die Idee hinter dem Cleaner - Dump darin, dass im Gegensatz zum eigentlichen Anwendungsspeicher, der die Größe 0 hat, nur In - Memory - Dateien eine Größe an den Speicherbereich angehängt haben (da die tatsächlich verwendete Größe dem nicht bekannt ist) OS).
mxmlnkn
Ein Problem, das ich mit diesem Skript habe, ist, dass die Blockgröße von 1 zu einer Bandbreite von unannehmbar langsamen ~ 30kB / s führt, verglichen mit der Verwendung einer Blockgröße, die der Seitengröße (4096 für mich) entspricht, für die ich ~ 100MB / s bekomme! Sehen Sie hier . getconf PAGESIZEwird verwendet, um die Seitengröße zu erhalten, und dann werden die Adressen und Zählwerte durch diese geteilt.
mxmlnkn
0

Wenn Sie ein separates Speichersegment des laufenden Prozesses sichern möchten, ohne eine große Kerndatei (z. B. mit gcore) zu erstellen, können Sie von hier aus ein kleines Tool verwenden . Es gibt auch einen Einzeiler in README, wenn Sie alle lesbaren Segmente in separate Dateien speichern möchten.

Nopius
quelle