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





468x60 banner

Jun27th

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

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. June 30th, 2009 | 09:51

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

  2. June 30th, 2009 | 15:27

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

  3. Алексей
    July 3rd, 2009 | 07:02

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

  4. Алексей 2
    July 3rd, 2009 | 20:52

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

  5. DonDD
    July 14th, 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. July 16th, 2009 | 09:03

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

  7. July 17th, 2009 | 08:48

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

  8. Crivel
    July 29th, 2009 | 13:33

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

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

  9. enzo_amd
    August 11th, 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. August 13th, 2009 | 12:19

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

  11. August 24th, 2009 | 13:43

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

  12. JTG
    September 1st, 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
    September 9th, 2009 | 10:51

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

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

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

  14. GeniY
    September 9th, 2009 | 11:36

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

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

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

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

  15. GeniY
    September 9th, 2009 | 11:40

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

  16. September 16th, 2009 | 00:51

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

  17. denimi
    November 1st, 2009 | 04:18

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

  18. January 11th, 2010 | 15:28

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

  19. phpusr
    January 28th, 2010 | 16:51

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

  20. Arhangel7
    February 28th, 2010 | 11:30

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

  21. Dimon
    May 1st, 2010 | 13:56

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

  22. May 25th, 2010 | 17:27

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

Ответить