Linux proc(5)
страница человека говорит мне , что /proc/$pid/mem
«может быть использована для доступа к страницам памяти процесса». Но простая попытка использовать его только дает мне
$ cat /proc/$$/mem /proc/self/mem
cat: /proc/3065/mem: No such process
cat: /proc/self/mem: Input/output error
Почему не cat
может распечатать свою собственную память ( /proc/self/mem
)? И что это за странная ошибка «нет такого процесса», когда я пытаюсь распечатать память оболочки ( /proc/$$/mem
очевидно, процесс существует)? Как я могу читать с /proc/$pid/mem
, тогда?
Ответы:
/proc/$pid/maps
/proc/$pid/mem
показывает содержимое памяти $ pid, отображенной так же, как и в процессе, т. е. байт со смещением x в псевдофайле совпадает с байтом по адресу x в процессе. Если адрес не отображается в процессе, чтение из соответствующего смещения в файле возвращаетEIO
(Ошибка ввода / вывода). Например, поскольку первая страница в процессе никогда не отображается (так что разыменованиеNULL
указателя завершается ошибкой, а не непреднамеренно обращается к фактической памяти), чтение первого байта/proc/$pid/mem
всегда приводит к ошибке ввода-вывода.Чтобы узнать, какие части памяти процесса отображаются, нужно прочитать
/proc/$pid/maps
. Этот файл содержит одну строку для каждой отображаемой области, выглядит так:Первые два числа являются границами области (адреса первого байта и байта после последнего в гекса). В следующем столбце содержатся разрешения, затем есть некоторая информация о файле (смещение, устройство, индекс и имя), если это сопоставление файла. См.
proc(5)
Справочную страницу или Понимание Linux / proc / id / maps для получения дополнительной информации.Вот сценарий проверки концепции, который выгружает содержимое своей собственной памяти.
/proc/$pid/mem
Если вы попытаетесь прочитать
mem
псевдофайл другого процесса, это не сработает: вы получитеESRCH
ошибку (Нет такого процесса).Права на
/proc/$pid/mem
(r--------
) более либеральны, чем должно быть. Например, вы не должны иметь возможность читать память процесса setuid. Кроме того, попытка прочитать память процесса во время его изменения может дать читателю непоследовательное представление о памяти, и, что еще хуже, были условия гонки, которые могли отследить более старые версии ядра Linux (согласно этому потоку lkml , хотя я не знаю деталей). Поэтому необходимы дополнительные проверки:/proc/$pid/mem
должен присоединиться к процессу , используяptrace
сPTRACE_ATTACH
флагом. Это то, что делают отладчики, когда начинают отлаживать процесс; это также то, чтоstrace
относится к системным вызовам процесса. Как только читатель закончит чтение/proc/$pid/mem
, он должен отключиться, позвонивptrace
сPTRACE_DETACH
флагом.ptrace(PTRACE_ATTACH, …)
останавливает целевой процесс (он посылаетSTOP
сигнал), но есть условие гонки (доставка сигнала асинхронная), поэтому трассировщик должен вызыватьwait
(как описано вptrace(2)
).Процесс, выполняющийся от имени пользователя root, может читать память любого процесса без необходимости вызова
ptrace
, но наблюдаемый процесс должен быть остановлен, иначе чтение все равно вернетсяESRCH
.В исходном коде ядра Linux код, предоставляющий записи для каждого процесса,
/proc
находится внутриfs/proc/base.c
, а функция для чтения/proc/$pid/mem
-mem_read
. Дополнительная проверка выполняетсяcheck_mem_permission
.Вот некоторый пример кода C для присоединения к процессу и чтения фрагмента его
mem
файла (проверка ошибок пропущена):Я уже разместил проверочный скрипт для создания дампа
/proc/$pid/mem
в другом потоке .источник
/proc/$pid/mem
напрямую (с помощьюcat
или сdd
чем-либо еще) не работает. Прочитайте мой ответ./proc/self/mem
. Процесс может читать свое собственное пространство памяти просто отлично, он читает пространство памяти другого процесса, которое требуетPTRACE_ATTACH
.process_vm_readv()
системным вызовом (Linux 3.2).ESRCH
ошибку в этом сценарии.Эта команда (из gdb) надежно выгружает память:
Дампы могут быть большими, используйте,
-o outfile
если в вашем текущем каталоге недостаточно места.источник
При выполнении
cat /proc/$$/mem
переменная$$
оценивается с помощью bash, который вставляет свой собственный pid. Затем выполняется,cat
который имеет другой pid. В конечном итоге выcat
пытаетесь прочитать память оbash
родительском процессе. Поскольку непривилегированные процессы могут только читать свое собственное пространство памяти, ядру это запрещается.Вот пример:
Обратите внимание, что
$$
оценивается в 17823. Давайте посмотрим, что это за процесс.Это моя текущая оболочка.
Здесь снова
$$
оценивается 17823, который является моей оболочкой.cat
не могу прочитать память моей оболочкиисточник
$pid
есть. Как я объясняю в своем ответе, чтение памяти другого процесса требует от вас его отслеживания.$$
когда пишешь (и читаешь)$pid
?$$
и положить$pid
в конце. Я перенес это в мою голову, не осознавая этого. Весь мой ответ должен касаться$$
, а не$pid
.Вот небольшая программа, которую я написал на C:
Использование:
Программа использует / proc / $ pid / maps, чтобы найти все отображенные области памяти процесса, а затем прочитать эти области из / proc / $ pid / mem, по одной странице за раз. эти страницы записываются на стандартный вывод или IP-адрес и порт TCP, которые вы указали.
Код (протестирован на Android, требуются права суперпользователя):
источник
write to stdout
сразу вышеfwrite(..., stdout)
. См. Programmers.stackexchange.com/questions/119600/…