Дамп памяти процесса Linux в файл

52

Можно ли записать текущую память, выделенную для процесса (с помощью PID) в файл? Или читать это как-то?

Fragsworth
источник
Вы можете использовать мой сценарий проверки концепции, который читает /proc/$pid/mem.
Жиль "ТАК - перестань быть злым"
1
Вы также можете прочитать superuser.com/questions/236390/… и использовать вместо этого gcore.
Саймон Эугстер

Ответы:

46

Я не уверен, как вы выгружаете всю память в файл, не делая этого многократно (если кто-то знает автоматический способ заставить GDB сделать это, пожалуйста, дайте мне знать), но следующее работает для любой партии памяти, если вы знаете, пид:

$ cat /proc/[pid]/maps

Это будет в формате (пример):

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

Выберите одну порцию памяти (например, 00621000-00622000), затем используйте gdb в качестве пользователя root для подключения к процессу и выведите эту память:

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

Затем проанализируйте / root / output с помощью команды strings, но вы не хотите использовать PuTTY по всему экрану.

Джеймс Л
источник
1
Есть ли способ сделать это в Bash / Sh без GDB?
Programming4life
3
@ Programming4life gcore (1)
Джулиан,
51

Я сделал скрипт, который выполняет эту задачу.

Идея взята из ответа Джеймса Лори и этого поста: 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

поместите это в файл (например, "dump-all-memory-of-pid.sh") и сделайте его исполняемым

использование: ./dump-all-memory-of-pid.sh [pid]

Вывод распечатывается в файлы с именами: pid-startaddress-stopaddress.dump

зависимости: gdb

А. Нильссон
источник
2
Потрясающие! Просто использовал его, чтобы узнать, какой скрипт запускает таинственный экземпляр bash.
Тобиа
Почему вы работаете только с диапазонами с rw-pразрешениями?
mxmlnkn
@mxmlnkn Это data ( rw-p), остальные диапазоны для кода ( r-xp). Если вы хотите получить дамп обоих, тогда идите и обменивайтесь, grepнапример cat.
А. Нильссон
39

пытаться

    gcore $pid

где $pidактуальный номер пид; для получения дополнительной информации см .:info gcore

для создания дампа может потребоваться некоторое время, и некоторая память может быть не читаемой, но достаточно хорошей ... имейте в виду, что она может создавать большие файлы, я только что создал файл 2 ГБ таким образом ...

Водолей Сила
источник
1
Является ли gcoreдемпинг разреженного файла?
CMCDragonkai
3

man proc говорит:

/ proc / [pid] / mem Этот файл может использоваться для доступа к страницам памяти процесса через open (2), read (2) и lseek (2).

Может быть, это может помочь вам

Дом
источник
1
Этого недостаточно, для чтения другого процесса требуется сочетание / proc / <pid> / {mem, * maps}, ptrace и некоторой обработки сигналов, чтобы избежать зависания целевого процесса.
Тобу
@ Тобу Действительно . Я написал сценарий для проверки концепции .
Жиль "ТАК - перестань быть злым"
3

Я также создал свою собственную программу для выгрузки всей памяти процесса, она находится на C, чтобы ее можно было кросс-компилировать для Android, что мне и было нужно.

Вы также можете указать IP-адрес и порт TCP. Исходный код здесь .

Таль Алони
источник
2

Чистое решение 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 )
}

Использование: procdump PID

для более чистой свалки:

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
источник
Итак, из того, что я понимаю, идея чистого дампа заключается в том, что только файлы в памяти имеют размер, прикрепленный к области памяти, в отличие от фактической памяти приложения, которая имеет размер 0 (так как фактически используемый размер неизвестен ОПЕРАЦИОННЫЕ СИСТЕМЫ).
mxmlnkn
Одна проблема, с которой я сталкиваюсь с этим сценарием, состоит в том, что размер блока 1 приводит к полосе пропускания неприемлемо медленной ~ 30 кБ / с по сравнению с использованием размера блока, равного размеру страницы (для меня 4096), для которого я получаю ~ 100 МБ / с! Смотрите здесь . getconf PAGESIZEиспользуется для получения размера страницы, а затем адреса и количество делятся на нее.
mxmlnkn
1

Инструмент для вывода процесса на стандартный вывод, pcat / memdump:

Майкл Спрингер
источник
Этот устарел (удален по запросу сопровождающего); В любом случае я установил старый пакет, и он завершился с ошибкой «Ошибка ввода / вывода; вы использовали GCC с заголовочными файлами другой машины?».
Тобу
0

Если вы хотите сбросить отдельный сегмент памяти запущенного процесса без создания огромного файла ядра (скажем, с помощью gcore), вы можете использовать небольшой инструмент здесь . В README также есть однострочная строка, если вы хотите сбросить все читаемые сегменты в отдельные файлы.

Nopius
источник