» Решение задач: как программе удалить саму себя или как изменить название исполняемого файла Borland Delphi. windows. . Блог программистов


Блог программистов






200927 Июн

Решение задач: как программе удалить саму себя или как изменить название исполняемого файла

1. Введение
В интернете просматривая форумы по программированию я наталкивался на вопросы связанные c вопросом «Как программу заставить удалить или переименовать себя во время исполнения». В этой статье описывается самый элементарный способ.

2. Что нужно?
Borland Delphi желательно 7 — требует установки
Блокнот (notepad.exe) — стоит на всех компьютерах с Windows
cmd.exe — стоит на всех компьютерах с Windows

3. Начинаем
Зачем нам нужен блокнот и cmd.exe спросите вы?
Мы для решения этой задачи будем использовать Пакетный файл, подробнее: В Википедии
Функция для удаления:



function RemoveApp : boolean;
var
batfile : TextFile; // переменная файла
begin
try // блок try..except для обработки исключений (ошибок)
RemoveApp := true; // в результат возвращаемой функции ставим значение: истина
AssignFile(batfile,'Del.bat'); // присваиваем файл переменной
ReWrite(batfile); // Открываем для перезаписи (если существует файл перезапишится, иначе создастся)
ChDir(ExtractFilePath(ParamStr(0))); // меняем текущую директорию (с которой работает программа) на директорию в которой находится исполняемый файл
WriteLn(batfile,'del '+ExtractFileName(ParamStr(0))); // записываем в файл команду удаления del
WriteLn(batfile,'del Del.bat'); // пишем это для самоуничтожения пакетного файла
CloseFile(batfile); // закрываем файл
WinExec('Del.bat',SW_SHOW); // запускаем пакетный файл который был создан программой
ExitProcess(0); // завершаем программу
except
RemoveApp := false; // если происходит ошибка возвращаем ложь
end;
end;


Функция для переименования:



function RenameApp(newname : string) : boolean;
var
batfile : TextFile; // переменная файла
begin
try // блок try..except для обработки исключений (ошибок)
RenameApp := true; // в результат возвращаемой функции ставим значение: истина
AssignFile(batfile,'Rem.bat'); // присваиваем файл переменной
ReWrite(batfile); // Открываем для перезаписи (если существует файл перезапишется, иначе создастся)
ChDir(ExtractFilePath(ParamStr(0))); // меняем текущую директорию (с которой работает программа) на директорию в которой находится исполняемый файл
WriteLn(batfile,'ren '+ExtractFileName(ParamStr(0))+' '+newname); // записываем в файл команду переименовывание ren
WriteLn(batfile,'del Rem.bat'); // пишем это для самоуничтожения пакетного файла
CloseFile(batfile); // закрываем файл
WinExec('Rem.bat',SW_SHOW); // запускаем пакетный файл который был создан программой
ExitProcess(0); // завершаем программу
except
RenameApp := false; // если происходит ошибка возвращаем ложь
end;
end;


4. Заключение
Как видите ничего сложного тут нет. Эти функции не требуют ни каких дополнительных модулей.

5. Конец
Если будут какие то проблемы, непонятки то пишите в комментарии. С удовольствием отвечу. Желаю вам успеха в программировании!

Исходник к статье

Прошу вас если вы скопировали эту статью к себе на сайт или форум или блог, то укажите ссылку на источник.

Комментарии

  1. 30 июня, 2009 | 09:51

    Действительно, все гениальное просто.

  2. 30 июня, 2009 | 15:27

    😉 :mrgreen: :mrgreen: :mrgreen: Спасибо огромное за статью))))

  3. Алексей
    3 июля, 2009 | 07:02

    Нет гарантии, что из exe-шника всегда удастся выйти раньше, чем запустится bat-файл. Соответственно, при удалении bat-файлу могут дать по рукам.

  4. Алексей 2
    3 июля, 2009 | 20:52

    У батника пинг что ли есть некоторый: пытается выполнить задачу на определенном интеравале времени.

  5. DonDD
    14 июля, 2009 | 23:04

    Еще один способ решения поставленной задачи. На мой взгляд более оптимальный.

    procedure DeleteSelf;
    var
    module: HModule;
    buf: array[0..MAX_PATH — 1] of char;
    p: ULong;
    hKrnl32: HModule;
    pExitProcess,
    pDeleteFile,
    pFreeLibrary: pointer;
    begin
    module := GetModuleHandle(nil);
    GetModuleFileName(module, buf, SizeOf(buf));
    CloseHandle(THandle(4));
    p := ULONG(module) + 1;
    hKrnl32 := GetModuleHandle(‘kernel32’);
    pExitProcess := GetProcAddress(hKrnl32, ‘ExitProcess’);
    pDeleteFile := GetProcAddress(hKrnl32, ‘DeleteFileA’);
    pFreeLibrary := GetProcAddress(hKrnl32, ‘FreeLibrary’);
    asm
    lea eax, buf
    push 0
    push 0
    push eax
    push pExitProcess
    push p
    push pDeleteFile
    push pFreeLibrary
    ret
    end;
    end;

  6. 16 июля, 2009 | 09:03

    DonDD, а твое решение даже проще, ну по крайней мере мне больше нравится.

  7. 17 июля, 2009 | 08:48

    Так с этим понятно,а как сделать чтобы программа ИЗМЕНЯЛА свой код в ходе исполнения ?Такое возможно?Хочу сделать программу для постоения графиков функций.Идея такая:в окне вводится фунция ,затем она вставляется в программу некоторым количеством строчек ниже y:=f(x) Затем строится расчетная таблица а по ней график

  8. Crivel
    29 июля, 2009 | 13:33

    DonDD, ваш код можно тоже использовать, но если вы внимательно посмотрите — ваша одна процедура удаления занимает целых 30 строк, а мои ДВЕ процедуры удаления и переименования занимают всего 38 строк. + Ваш код только может удалять.

    Алексей, я тестировал свой код на двух компьютерах и всё работало.

  9. enzo_amd
    11 августа, 2009 | 16:29

    DonDD, или кто в курсе,
    объясните пожалуйста работу функции DeleteSelf, в которой применён ассемблер (без батников).

    А именно интересует:
    1) CloseHandle(THandle(4)); — что значит 4? что это за хэндл такой?
    2) в асм’е Мы заносим на стек адреса функций из kernel… почему именно в такой последовательности?
    насколько я понимаю, команда ret произведёт их вызов следующим образом:
    1 — FreeLibrary(@DeleteFile)
    2 — далее произойдёт возврат на адрес p (хотя у нас там не адрес, а хэндл)
    3 — а третьего уже не будет, т.к. в предыдущем шаге мы повешаем прогу.

    3) и ещё, я слышал, что всё это не будет работать в XP и более поздних версиях, а в этих версиях можно применять способ: \\127.0.0.1\C$\my_program.exe

  10. 13 августа, 2009 | 12:19

    Спасибо! Но для меня пока что это все сложно! 😥

  11. 24 августа, 2009 | 13:43

    Доброго дня! А у меня уже есть положительные сдвиги. Статья очень помогла!

  12. JTG
    1 сентября, 2009 | 13:46

    enzo_amd, после ret наверху слека останется

    7C831D93 /CALL to FreeLibrary
    00400001 0400001 (00400000-хендл экзешника, а 00400001 — хрень какая-то)

    после неё DeleteFileA с параметрами (который, кстати, вернёт ERROR_ACCESS_DENIED) и, наконец, ExitProcess

    Фишка в том, чтоб оставить после себя в стеке код, который будет выполнен в недрах kernel32 при завершении, но в ХР ни FreeLibrary ни UnmapViewOfFile уже не прокатывает. Загадочное CloseHandle(THandle(4)) тоже

  13. GeniY
    9 сентября, 2009 | 10:51

    Код прикольный. Но… после выполнения у меня создается действительно Bat-файл, И exe-файл не удаляется. Удаляется только после запуска непосредственно нажатием клавиши мыши.

    Получается, что Bat-файл выполняется ещё до выхода программы.

    Как это можно решить?

  14. GeniY
    9 сентября, 2009 | 11:36

    Немного исправлю.

    Сам нашел решение. Нужно вместо WinExec использовать Более продвинутую версию — ShellExecute.
    {WinExec — достались в наследство от Windows 3.x, Microsoft не рекомендует использовать ее в приложениях Win32. Они предлагают использовать CreatePocess. Но для данного решения достаточно и ShellExecute}

    Код таков:
    ShellExecute(Application.Handle,’open’,’Del.bat’,SW_ShowNormal);

    PS: А За простой код автору спасибо.

  15. GeniY
    9 сентября, 2009 | 11:40

    ShellExecute(Application.Handle,’open’,’Del.bat’,nil,nil,SW_ShowNormal);

  16. 16 сентября, 2009 | 00:51

    У батника пинг что ли есть некоторый: пытается выполнить задачу на определенном интеравале времени.

  17. denimi
    1 ноября, 2009 | 04:18

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

  18. 11 января, 2010 | 15:28

    И правда элегантное решение… но смущает то что после удаления остается батник.

  19. phpusr
    28 января, 2010 | 16:51

    WriteLn(batfile,’del Del.bat’);
    Батник тоже удаляется

  20. Arhangel7
    28 февраля, 2010 | 11:30

    writeln (batfile,’del %0′);
    эта строка заставит бантик самоликвидироватся.

  21. Dimon
    1 мая, 2010 | 13:56

    Кстати, первый вариант с bat файлами работает как часы, а «элегантное» решение (второй вариант) почему то не работает… прога просто закрывается. В чем же дело??

  22. 25 мая, 2010 | 17:27

    да, с shellexecute первый вариант работает.

  23. 8 января, 2011 | 17:51

    Вопрос к тем, кто шарит в асме: разберитесь, пожалуйста, с этим элегантным решением, работает ли оно и если нет, то как исправить.

    Автор, Ваш метод может не сработать, если у программы недостаточно прав для записи в каталог, в котором она расположена. Чисто теоретически, IMHO, такое всё-таки возможно.

  24. dsgfsg
    9 января, 2011 | 16:26

    Не работает.

    >как исправить.
    Установить win98

  25. 9 января, 2011 | 17:44

    В более современной винде нет совсем никаких способов поместить в стек вызов системных функций?

  26. Mukhit
    9 марта, 2011 | 15:17

    Dobryi den’, i srazu vopros:

    — kak mojno udalit’ files po prowedwim dniam (files v papke)?

    spasibo…

  27. Qwerty
    26 мая, 2011 | 13:49

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

  28. 1 июня, 2011 | 18:26

    И это действительно большой минус. Каждая программа требует перезагрузки по любому чиху. Как минимум надоело.

    К тому же:
    «При запуске Windows 2000 и Windows XP в безопасном режиме разделы RunOnce игнорируются» (http://support.microsoft.com/kb/179365)

  29. icWasya
    23 августа, 2011 | 17:25

    и еще
    вот эту команду
    ChDir(ExtractFilePath(ParamStr(0)));
    должен выполнять bat-файл
    примерно таким образом
    var
    P:String;
    WriteLn(batfile,ExtractFileDrive(ParamStr(0)));// переходим на диск с программой
    P:=ExtractFilePath(ParamStr(0);
    if (Length(P)>0) and (P[Length(P)]=’\’) then SetLength(P,Length(P)-1);
    WriteLn(batfile,’cd «‘+P+'»‘); //переходим на папку с программой
    если в имени файла или папки есть пробелы, то его нужно заключать в кавычки

    и кроме того, после удаления программы, если она последняя,
    желательно удалить и папку, в которую её установили.
    Но это отдельная задачка 🙂