Решение задач: как программе удалить саму себя или как изменить название исполняемого файла
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. Конец
Если будут какие то проблемы, непонятки то пишите в комментарии. С удовольствием отвечу. Желаю вам успеха в программировании!
Прошу вас если вы скопировали эту статью к себе на сайт или форум или блог, то укажите ссылку на источник.
Действительно, все гениальное просто.
😉 Спасибо огромное за статью))))
Нет гарантии, что из exe-шника всегда удастся выйти раньше, чем запустится bat-файл. Соответственно, при удалении bat-файлу могут дать по рукам.
У батника пинг что ли есть некоторый: пытается выполнить задачу на определенном интеравале времени.
Еще один способ решения поставленной задачи. На мой взгляд более оптимальный.
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;
DonDD, а твое решение даже проще, ну по крайней мере мне больше нравится.
Так с этим понятно,а как сделать чтобы программа ИЗМЕНЯЛА свой код в ходе исполнения ?Такое возможно?Хочу сделать программу для постоения графиков функций.Идея такая:в окне вводится фунция ,затем она вставляется в программу некоторым количеством строчек ниже y:=f(x) Затем строится расчетная таблица а по ней график
DonDD, ваш код можно тоже использовать, но если вы внимательно посмотрите — ваша одна процедура удаления занимает целых 30 строк, а мои ДВЕ процедуры удаления и переименования занимают всего 38 строк. + Ваш код только может удалять.
Алексей, я тестировал свой код на двух компьютерах и всё работало.
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
Спасибо! Но для меня пока что это все сложно! 😥
Доброго дня! А у меня уже есть положительные сдвиги. Статья очень помогла!
enzo_amd, после ret наверху слека останется
7C831D93 /CALL to FreeLibrary
00400001 0400001 (00400000-хендл экзешника, а 00400001 — хрень какая-то)
после неё DeleteFileA с параметрами (который, кстати, вернёт ERROR_ACCESS_DENIED) и, наконец, ExitProcess
Фишка в том, чтоб оставить после себя в стеке код, который будет выполнен в недрах kernel32 при завершении, но в ХР ни FreeLibrary ни UnmapViewOfFile уже не прокатывает. Загадочное CloseHandle(THandle(4)) тоже
Код прикольный. Но… после выполнения у меня создается действительно Bat-файл, И exe-файл не удаляется. Удаляется только после запуска непосредственно нажатием клавиши мыши.
Получается, что Bat-файл выполняется ещё до выхода программы.
Как это можно решить?
Немного исправлю.
Сам нашел решение. Нужно вместо WinExec использовать Более продвинутую версию — ShellExecute.
{WinExec — достались в наследство от Windows 3.x, Microsoft не рекомендует использовать ее в приложениях Win32. Они предлагают использовать CreatePocess. Но для данного решения достаточно и ShellExecute}
Код таков:
ShellExecute(Application.Handle,’open’,’Del.bat’,SW_ShowNormal);
PS: А За простой код автору спасибо.
ShellExecute(Application.Handle,’open’,’Del.bat’,nil,nil,SW_ShowNormal);
У батника пинг что ли есть некоторый: пытается выполнить задачу на определенном интеравале времени.
может хтонебудь покажет как зделать файл, на самоуничтожения, т.е например фото при первом просмотре чтоб она уничтожилась, или может видео, т.е принцип работы. Буду очень благодарен!
И правда элегантное решение… но смущает то что после удаления остается батник.
WriteLn(batfile,’del Del.bat’);
Батник тоже удаляется
writeln (batfile,’del %0′);
эта строка заставит бантик самоликвидироватся.
Кстати, первый вариант с bat файлами работает как часы, а «элегантное» решение (второй вариант) почему то не работает… прога просто закрывается. В чем же дело??
да, с shellexecute первый вариант работает.
Вопрос к тем, кто шарит в асме: разберитесь, пожалуйста, с этим элегантным решением, работает ли оно и если нет, то как исправить.
Автор, Ваш метод может не сработать, если у программы недостаточно прав для записи в каталог, в котором она расположена. Чисто теоретически, IMHO, такое всё-таки возможно.
Не работает.
>как исправить.
Установить win98
В более современной винде нет совсем никаких способов поместить в стек вызов системных функций?
Dobryi den’, i srazu vopros:
— kak mojno udalit’ files po prowedwim dniam (files v papke)?
spasibo…
В реестре есть ветка (сейчас не помню), ключи которой выполняются при загрузке компьютера и самоуничтожаются еще до того, как выполнится содержащаяся в них инструкция. Туда можно вставить удаление себя любимого. Минус: удалится только после перезагрузки.
И это действительно большой минус. Каждая программа требует перезагрузки по любому чиху. Как минимум надоело.
К тому же:
«При запуске Windows 2000 и Windows XP в безопасном режиме разделы RunOnce игнорируются» (http://support.microsoft.com/kb/179365)
и еще
вот эту команду
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+'»‘); //переходим на папку с программой
если в имени файла или папки есть пробелы, то его нужно заключать в кавычки
и кроме того, после удаления программы, если она последняя,
желательно удалить и папку, в которую её установили.
Но это отдельная задачка 🙂