Можно ли написать саморазрушающуюся программу на C?

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


person Alex Coplan    schedule 01.04.2012    source источник
comment
Вероятно, можно написать программу, которая удаляет файл .exe или что-то еще, хотя вам, возможно, придется пройти через некоторые препятствия, поскольку в некоторых средах ОС блокирует .exe во время его выполнения.   -  person Hot Licks    schedule 01.04.2012


Ответы (5)


да.

#include <unistd.h>
int main(int argc, char* argv[])
{
  return unlink(argv[0]);
}

(Проверено и работает.)

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

Также, если файл имеет несколько жестких ссылок, будет удалена только вызываемая ссылка.

person blueshift    schedule 01.04.2012
comment
Здесь мы переходим к обычному делу о надежности argv[0] как пути к бинарнику. POSIX говорит, что должен указывать на двоичный файл, но не требует этого, и API позволяет программам устанавливать его на что-то другое. Конечным результатом является то, что это обычно работает, но ненадежно. Более того, даже если у вас есть правильный путь, двоичный файл может быть жестко связан более чем в одном месте. - person dmckee --- ex-moderator kitten; 01.04.2012
comment
На самом деле не работает. @LuchianGrigore прав, после вызова unlink добавьте сон (30), затем, пока программа спит, запустите lsof в другом терминале (это утилита * nix), и вы увидите, что ОС все еще имеет дескриптор открытого файла. Файл исчез из ls, но он все еще существует до тех пор, пока программа не завершится и ОС не закроет свой дескриптор. - person SoapBox; 01.04.2012
comment
@SoapBox - Да, это так. По завершению выполнения он пропал из файловой системы или нет? По крайней мере, я спрашивал, как это сделать. - person Alex Coplan; 01.04.2012
comment
@dmckee Меня интересует пример, который касается этой ситуации. - person blueshift; 01.04.2012
comment
Насколько я знаю, не существует полностью стандартного решения. Возможно, вы сможете улучшить его в Linux, используя псевдофайловую систему /proc. - person dmckee --- ex-moderator kitten; 01.04.2012
comment
Этот ответ может быть действительно забавным, если это двоичный файл suid-root, пытающийся удалить себя... ;-) - person R.. GitHub STOP HELPING ICE; 01.04.2012
comment
Это не решение с использованием C. unlink - это POSIX, а не часть требования. - person Jens Gustedt; 01.04.2012

Я не знаю, можно ли удобно сделать это действительно независимым от платформы способом, но вы не указали независимость от платформы, поэтому попробуйте следующий код в стиле Linux:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv) {
    printf("Read carefully!  You cannot print this message again.\n");
    return unlink(argv[0]);
}

Насколько это близко к тому, что вы хотите?

person thb    schedule 01.04.2012
comment
Это самая дурацкая типизация аргументов для функции main(), которую я когда-либо видел. - person blueshift; 01.04.2012
comment
Кстати, это нестандартные аргументы для main. Учитывая это, это только усложнит понимание вашего примера кода для новичка... - person Oliver Charlesworth; 01.04.2012
comment
По многочисленным просьбам я сейчас пересматриваю свой ответ! [Однако я замечу, что мой компилятор GCC 4.4, если он вызывается с переключателями -Wall и -Wextra, выдает предупреждение, если я не могу поставить перед int argc __attribute__((unused)) в этом конкретном примере. Причина, конечно же, в том, что argc здесь не используется.] - person thb; 01.04.2012
comment
@OliCharlesworth по праву является сторонником стандарта. Я думал, что я тоже, пока я не столкнулся с ним, но он поднимает это на другой уровень. Если бы не его комментарий, я бы сказал, что программист может свободно принимать переменные аргументы в качестве постоянных параметров и что было бы благоразумно сделать большинство объектов постоянными, если не предполагается их изменение. Однако с моими константами может остаться какая-то скрытая проблема, которую Оли видит, а я нет. Тем не менее, мои константы отвлекали внимание, поэтому я их удалил. Во всяком случае, они не были основным пунктом моего ответа. - person thb; 01.04.2012
comment
@thb: На практике в этой ситуации ничего не повредит. Но в общем случае T** нельзя преобразовать в const T**, поэтому лучше не смешивать их. - person Oliver Charlesworth; 01.04.2012
comment
Что ж, сегодня я кое-чему научился. @OliCharlesworth отметил ранее c-faq.com/ansi/constmismatch.html, что объясняет его точку зрения. Интересный. - person thb; 01.04.2012

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

Если ОС этого не позволяет, ваша программа (назовем ее A) может создать другой двоичный файл, содержащий другую программу (назовем ее B). Затем A немедленно уходил.

Программа B будет иметь один цикл, проверяющий, работает ли A, и как только A завершает работу, B стереть двоичный файл A.

person Imp    schedule 01.04.2012
comment
Ну, миссия была убить А, не так ли? B может храниться в какой-то временной папке и ждать, когда его когда-нибудь уберут. - person Imp; 01.04.2012
comment
@Imp, если цель состояла в том, чтобы уничтожить любые доказательства исходного файла, то это, безусловно, сработает. - person Alex Coplan; 01.04.2012
comment
@DavidSouther +1 за ссылку на легенду жаргонного файла - person blueshift; 01.04.2012
comment
@AlexCoplan Хорошо, чтобы уничтожить любые улики, мы также должны записать несколько нулей в исходную позицию файла на диске;) - person Imp; 01.04.2012

Вы можете попытаться просто удалить исполняемый файл в программе (ФАЙЛ* и прочее)... но, поскольку этот исполняемый файл запускается, это может не сработать. Я вижу это как поедание самого себя, и, насколько я знаю, это невозможно, но вы, безусловно, можете попробовать, используя метод, который я упомянул выше.

person Community    schedule 01.04.2012

Я думаю, что это зависит от платформы, которую вы используете. По сути, после загрузки исполняемого файла любое последующее изменение двоичного файла не влияет на работающую программу. В Unix это так, и вы можете использовать системный вызов unlink.

Я не уверен, верно ли это для Windows или нет. Удаление исполняемого образа может быть запрещено. Вы можете попробовать API DeleteFile() в Windows.

person stoictopia    schedule 01.04.2012