Как восстановить удаленный двоичный исполняемый файл запущенного процесса

Он документирован (для POSIX) в Разделе 2.9.1 Простые команды базовой спецификации The Open Group.  Там много текста; я обращаю ваше внимание на последний абзац:

Если есть имя команды, выполнение должно продолжаться, как описано в Поиск и выполнение команды.  Если имя команды отсутствует, но команда содержит подстановку команды, команда завершается со статусом выхода последней выполненной подстановки команды.  В противном случае команда завершается с нулевым статусом выхода.

Так, например,

   Command                                         Exit Status
$ FOO=BAR                                   0 (but see also the note from icarus, below)
$ FOO=$(bar)                                Exit status from "bar"
$ FOO=$(bar) baz                            Exit status from "baz"
$ foo $(bar)                                Exit status from "foo"

Так работает и bash.  Но см. также раздел "Не все так просто" в конце.

phk, в своем вопросе Назначения подобны командам со статусом выхода, за исключением случаев, когда происходит замена команды?, предлагает

... кажется, что задание само по себе считается командой... с нулевым значением выхода, но которая применяется перед правой частью присваивания (например, вызов подстановки команды...)

Это не такой уж ужасный способ взглянуть на это.  Грубая схема для определения статуса возврата простой команды (не содержащей ;, &, |, && или ||) такова:

  • Просканируйте строку слева направо, пока не достигнете конца или командного слова (обычно имени программы).
  • Если вы видите присвоение переменной, статус возврата для этой строки может быть просто 0.
  • Если вы видите подстановку команды - т.е. $(...) - возьмите статус выхода из этой команды.
  • Если вы достигли фактической команды (не в подстановке команды), возьмите статус выхода из этой команды.
  • Статус возврата для строки - последний встреченный номер.
    Замены команд как аргументы к команде, например, foo $(bar), не считаются; вы получаете статус выхода из foo.  Перефразируя нотацию phk, поведение здесь такое

    temporary_variable = EXECUTE("bar" )
    overall_exit_status = EXECUTE("foo", temporary_variable )
    

Но это небольшое упрощение.  Общий статус возврата из

A=$(cmd1)  B=$(cmd2)  C=$(cmd3)  D=$(cmd4)  E=mc2

- это статус выхода из cmd4.  Присвоение E=, которое происходит после присваивания D= не устанавливает общий статус выхода в 0.

icarus, в своем ответе на вопрос phk, поднимает важный вопрос: переменные могут быть установлены как readonly.  Предпоследний абзац в Разделе 2.9.1 стандарта POSIX гласит:

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

поэтому, если вы скажете

readonly A
C=Garfield A=Felix T=Tigger

что статус возврата равен 1.  Не имеет значения, если строки Garfield, Felix, и/или Tigger заменяются командными подстановками - но см. примечания ниже.

Раздел 2.8.1 Последствия ошибок оболочки содержит еще одну кучу текста, и таблица, и заканчивается

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

Некоторые детали имеют смысл, некоторые нет:

  • Присвоение A= иногда прерывает командную строку, как, по-видимому, указано в последнем предложении.  В приведенном выше примере C установлено на Garfield, но T не установлено. (и, конечно, не задан A).
  • Similarly, C=$(cmd1) A=$(cmd2) T=$(cmd3) выполняет cmd1 но не cmd3.
    Но, в моих версиях bash (которые включают 4.1.X и 4.3.X), он выполняет cmd2.  (Кстати, это еще больше подрывает интерпретацию phk о том. что значение выхода из присваивания применяется перед правой частью присваивания.)

Но вот сюрприз:

В моих версиях bash,

readonly A
C=something A=something T=something cmd0

does execute cmd0.  В частности,

C=$(cmd1)   A=$(cmd2)   T=$(cmd3)   cmd0

выполняет cmd1 и cmd3 но не cmd2.  (Обратите внимание, что это противоположно его поведению при отсутствии команды).  И он устанавливает T (а также C) в окружение cmd0.  Интересно, не является ли это ошибкой в bash?


Не все так просто:

В первом абзаце этого ответа говорится о "простых командах".  В спецификации сказано:

"Простая команда" - это последовательность необязательных назначений переменных и перенаправлений, в любой последовательности, за которой по желанию следуют слова и перенаправления, завершается оператором управления.

Это утверждения, подобные тем, что приведены в моем первом блоке примеров:

$ FOO=BAR
$ FOO=$(bar)
$ FOO=$(bar) baz
$ foo $(bar)

первые три из них включают присваивание переменных, а последние три включают подстановки команд.

Но некоторые присваивания переменных не так просты.  bash(1) говорит:

Операторы присваивания могут также появляться в качестве аргументов для alias, declare, typeset, export, readonly, и local встроенные команды (команды declaration).

Для export, спецификация POSIX гласит:

EXIT STATUS

    0
      Все операнды имен были успешно экспортированы.
    >0
      По крайней мере одно имя не удалось экспортировать, или была указана опция -p и произошла ошибка.

И POSIX не поддерживает local, но bash(1) говорит:

Ошибкой является использование local не внутри функции.  Статус возврата равен 0, если local не используется вне функции, или имя является недопустимым, или имя является переменной, доступной только для чтения.

Читая между строк, мы видим, что такие команды декларации, как

export FOO=$(bar)

и

local FOO=$(bar)

больше похожи на

foo $(bar)

постольку, поскольку они игнорируют статус выхода из bar и выдают статус выхода, основанный на главной команде (export, local или foo).  Таким образом, мы имеем странности вроде

   Command                                           Exit Status
$ FOO=$(bar)                                    Exit status from "bar"
                                                  (unless FOO is readonly)
$ export FOO=$(bar)                             0 (unless FOO is readonly,
                                                  or other error from “export”)
$ local FOO=$(bar)                              0 (unless FOO is readonly,
                                                  statement is not in a function,
                                                  or other error from “local”)

которые мы можем продемонстрировать с помощью

$ export FRIDAY=$(date -d tomorrow)
$ echo "FRIDAY   = $FRIDAY, status = $?"
FRIDAY   = Fri, May 04, 2018  8:58:30 PM, status = 0
$ export SATURDAY=$(date -d "day after tomorrow")
date: invalid date ‘day after tomorrow’
$ echo "SATURDAY = $SATURDAY, status = $?"
SATURDAY = , status = 0

и

myfunc() {
    local x=$(echo "Foo"; true);  echo "x = $x -> $?"
    local y=$(echo "Bar"; false); echo "y = $y -> $?"
    echo -n "BUT! "
    local z; z=$(echo "Baz"; false); echo "z = $z -> $?"
}

$ myfunc
x = Foo -> 0
y = Bar -> 0
BUT! z = Baz -> 1

К счастью, ShellCheck отлавливает ошибку и поднимает SC2155, который советует изменить

export foo="$(mycmd)"

на

foo=$(mycmd)
export foo

и

local foo="$(mycmd)"

на

local foo
foo=$(mycmd)

4
05.02.2017, 03:12
2 ответа

Он может находиться только в памяти и не подлежит восстановлению, и в этом случае вам придется попытаться восстановить его из файловой системы с помощью одного из этих инструментов восстановления файловой системы. (или, может быть, по памяти). Тем не мение!

$ cat hamlet.c
#include <unistd.h>
int main(void) { while (1) { sleep(9999); } }
$ gcc -o hamlet hamlet.c
$ md5sum hamlet
30558ea86c0eb864e25f5411f2480129  hamlet
$ ./hamlet &
[1] 2137
$ rm hamlet
$ cat /proc/2137/exe > newhamlet
$ md5sum newhamlet 
30558ea86c0eb864e25f5411f2480129  newhamlet
$ 

С интерпретируемыми программами получение файла сценария может быть где-то между сложным и невозможным, поскольку / proc / $$ / exe будет указывать на perl или что-то еще, а входной файл возможно, уже были закрыты:

$ echo sleep 9999 > x
$ perl x &
[1] 16439
$ rm x
$ readlink /proc/16439/exe
/usr/bin/perl
$ ls /proc/16439/fd
0  1  2

Открыты только стандартные файловые дескрипторы, поэтому x уже исчез (хотя может еще какое-то время существовать в файловой системе, и кто знает, что интерпретатор хранит в памяти) .

9
27.01.2020, 20:48

Dijiste que es C++, por lo que debería ser posible volcarlo de la memoria.

Primero desea encontrar el proceso en la memoria:

$ cat /proc/[pid]/maps
00400000-00404000 r-xp 00000000 ca:01 16823     /home/ec2-user/a.out (deleted)

Entonces puedes volcarlo

$ gdb --pid [pid]
dump memory /home/ec2-user/output 0x00400000 0x00404000

Entonces debería poder ejecutarlo marcándolo como ejecutable(chmod +x)

$ file output
output: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, missing section headers
4
27.01.2020, 20:48

Теги

Похожие вопросы