IPB

Добро пожаловать, гость ( Вход | Регистрация )

> Самоудаляющийся .EXE файл, Self-Deleting Executable
-=CHE@TER=-
Jun 23 2007, 10:13
Сообщение #1


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



Вот, есть такая статья: Self-Deleting Executables.
Она рассказывает о нелёгких поисках способа удалить программно .EXE файл изнутри. Т.е. написать такую программу, которая сможет себя удалить, когда вы её запустите. Как известно в DOS такой проблемы не существует и я, в своё время, делал Uninstall'ер для своей программы, который удалял всё, включая и себя самого, ибо после запуска .EXE файл уже был не нужен. В Windows .EXE файл недоступен (занят системой) до тех пор, пока запущенная программа не прекратила работать, в частности удалить его тоже нельзя.
Из данной статьи я взял универсальный способ-пример, довольно оригинального решения, файл "selfdel05.c" и попытался переписать его на Delphi (оригинал можно взять по ссылке выше - см. Download source).
CODE
//
//  selfdel.c
//
//  Self deleting executable for Win9x/WinNT (all versions)
//
//  J Brown 1/10/2003
//
//  This source file must be compiled with /GZ turned OFF
//  (basically, disable run-time stack checks)
//
//  Under debug build this is always on (MSVC6)
//
//
Uses Windows;
// #pragma pack(push, 1)
// #define
Const CODESIZE = $200;
//
//  Structure to inject into remote process. Contains
//  function pointers and code to execute.
//
Type
     PSELFDEL = ^TSELFDEL;
     TSELFDEL = Packed Record
            ARG0: PSELFDEL; // pointer to self
         opCodes: Array[0..CODESIZE-1] Of Byte; // code
         hParent: THandle; // parent process handle
      fnWaitForSingleObject: Function(hHandle: THandle; dwMilliseconds: DWORD): DWORD; stdcall;
              fnCloseHandle: Function(hObject: THandle): BOOL; stdcall;
               fnDeleteFile: Function(lpFileName: PChar): BOOL; stdcall;
                    fnSleep: Procedure(dwMilliseconds: DWORD); stdcall;
              fnExitProcess: Procedure(uExitCode: UINT); stdcall;
          fnRemoveDirectory: Function(lpPathName: PChar): BOOL; stdcall;
             fnGetLastError: Function: DWORD; stdcall;
                    fRemDir: LongBool;
                 szFileName: Array[0..MAX_PATH-1] Of Char; // file to delete
     End;

//#pragma pack(pop)

{$ifdef _DEBUG}
//{$define FUNC_ADDR(func) (PVOID)(*(DWORD *)((BYTE *)func + 1) + (DWORD)((BYTE *)func + 5))}
{$else}
//{$define FUNC_ADDR(func) func}
{$endif}

//
//  Routine to execute in remote process.
//
procedure remote_thread(remote: PSELFDEL); stdcall;
Begin
  // wait for parent process to terminate
  remote^.fnWaitForSingleObject(remote^.hParent, INFINITE);
  remote^.fnCloseHandle(remote^.hParent);
  // try to delete the executable file
  while (not remote^.fnDeleteFile(remote^.szFileName)) Do
  Begin
    // failed - try again in one second's time
    remote^.fnSleep(1000);
  End;
  // finished! exit so that we don't execute garbage code
  remote^.fnExitProcess(0);
End;

//
//  Delete currently running executable and exit
//  
Function SelfDelete(fRemoveDirectory: LongBool): Boolean;
Var
    si: STARTUPINFO;
    pi: PROCESS_INFORMATION;
    context: TContext;
    oldProt: DWORD;
    local: TSELFDEL;
    entrypoint: DWORD;
    szExe: Array[0..MAX_PATH-1] Of Char;

    remdel: Pointer;
    dummy: dword;
Begin
  result:=FALSE;
  szExe:='explorer.exe'#0;
  //
  //  Create executable suspended
  //
  ZeroMemory(@si, SizeOf(si));
  si.cb:=SizeOf(si);
  if CreateProcess(Nil, szExe, Nil, Nil, False, CREATE_SUSPENDED Or IDLE_PRIORITY_CLASS, Nil, Nil, si, pi) Then
  Begin
    local.fnWaitForSingleObject := @WaitForSingleObject;
    local.fnCloseHandle         := @CloseHandle;
    local.fnDeleteFile          := @DeleteFile;
    local.fnSleep               := @Sleep;
    local.fnExitProcess         := @ExitProcess;
    local.fnRemoveDirectory     := @RemoveDirectory;
    local.fnGetLastError        := @GetLastError;

    local.fRemDir               := fRemoveDirectory;

    // Give remote process a copy of our own process handle
    DuplicateHandle(GetCurrentProcess, GetCurrentProcess, pi.hProcess, @local.hParent, 0, FALSE, 0);
    GetModuleFileName(0, local.szFileName, MAX_PATH);

    // copy in binary code
    remdel:=@remote_thread;
    move(remdel, local.opCodes, CODESIZE); //move(local.opCodes, @remdel, CODESIZE); {!}

    //
    // Allocate some space on process's stack and place
    // our SELFDEL structure there. Then set the instruction pointer
    // to this location and let the process resume
    //
    context.ContextFlags := CONTEXT_INTEGER Or CONTEXT_CONTROL;
    GetThreadContext(pi.hThread, context);

    // Allocate space on stack (aligned to cache-line boundary)
    entrypoint := (context.Esp - sizeof(TSELFDEL)) And Cardinal(Not $1F);
    
    //
    // Place a pointer to the structure at the bottom-of-stack
    // this pointer is located in such a way that it becomes
    // the remote_thread's first argument!!
    //
    local.Arg0:=Ptr(entrypoint); // local.Arg0 := TSELFDEL(entrypoint);

    context.Esp := entrypoint - 4; // create dummy return address
    context.Eip := entrypoint + 4; // offset of opCodes within structure

    // copy in our code+data at the exe's entry-point
    VirtualProtectEx(pi.hProcess, Ptr(entrypoint), sizeof(local), PAGE_EXECUTE_READWRITE, Ptr(oldProt));
    WriteProcessMemory(pi.hProcess, Ptr(entrypoint), Pointer(@local), sizeof(local), dummy);

    FlushInstructionCache(pi.hProcess, Ptr(entrypoint), sizeof(local));

    SetThreadContext(pi.hThread, context);

    // Let the process continue
    ResumeThread(pi.hThread);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    result:=TRUE;
  End;
End;

Begin
  SelfDelete(False);
End.

Однако, где-то я чего-то упустил, ибо программа запускается, но ничего не делает.
Кто-нибудь может помочь?
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
 
Reply to this topicStart new topic
Ответов
Axsis
Jul 3 2007, 07:17
Сообщение #2


Advanced Member
***

Группа: CTPAX-X
Сообщений: 121
Регистрация: 6-February 08
Пользователь №: 374
Спасибо сказали: 149 раз(а)



Чё-то я не совсем понял принцип работы этого кода... Вы создаёте процесс explorer.exe, усыпляете его и копируете в него свой код? =( ) Если так, то мне интересно, как отнесутся антивирусы и всякие системы проактивной защиты к такому действию? Представьте, что человек слил прогу с инета, запустил, а антивирь написал, что так и так, предотвращена попытка вклиниться в аднесное пространство explorer.exe! А если после этого ещё и оригинальный exe'шник удалится... Да чел в жизни отсюда ничего больше не скачает! Если я всё провильно понял, то подобный код допустим только для личного использования, в публичные проги его пихать нельзя! Или, может, я что-то пропустил и -=CHE@TER=- переключился на написание троянов? =)
ЗЫ: если я неправильно понял, плиз напишите принцип работы ЭТОГО smile.gif
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jul 3 2007, 08:47
Сообщение #3


Walter Sullivan
***

Группа: Root Admin
Сообщений: 1,355
Регистрация: 4-February 08
Пользователь №: 3
Спасибо сказали: 311 раз(а)



QUOTE(Axsis @ Jul 3 2007, 07:17 AM) *
Чё-то я не совсем понял принцип работы этого кода... Вы создаёте процесс explorer.exe, усыпляете его и копируете в него свой код? =( ) Если так, то мне интересно, как отнесутся антивирусы и всякие системы проактивной защиты к такому действию? Представьте, что человек слил прогу с инета, запустил, а антивирь написал, что так и так, предотвращена попытка вклиниться в аднесное пространство explorer.exe! А если после этого ещё и оригинальный exe'шник удалится... Да чел в жизни отсюда ничего больше не скачает! Если я всё провильно понял, то подобный код допустим только для личного использования, в публичные проги его пихать нельзя! Или, может, я что-то пропустил и -=CHE@TER=- переключился на написание троянов? =)
ЗЫ: если я неправильно понял, плиз напишите принцип работы ЭТОГО smile.gif
Ок, давайте по порядку:
1) Вопрос первый:
QUOTE
Вы создаёте процесс explorer.exe, усыпляете его и копируете в него свой код? =( )
Совершенно точно (поправочка: Explorer.exe создаётся усыплённым). Находится EntryPoint, откуда Explorer.exe начинает работать (стартовая точка) и в это место всовывается код.

2) Вопрос второй:
QUOTE
Если так, то мне интересно, как отнесутся антивирусы и всякие системы проактивной защиты к такому действию?
Насчёт антивирусов - не знаю, у меня стоит Symantec с последними базами - он к этому спокойно относится. (*улыбается*) Если у тебя другой - можешь у себя скомпилировать Си или Delphi вариант и проверить. (*улыбается*) Сообщи, пожалуйста, о результатах, тоже интересно.
Кстати, вот что ещё сейчас в голову пришло: получается, что все трейнеры и прочие ArtMoney - это тоже вирусы, т.к. они тоже пишут в адресное пространство другого процесса. (*улыбается*)

3) Ну и насчёт третьего пункта приводить цитату целиком не буду - а просто отвечу:
мне данный код нужен был для апдейта моей программы. Вместо DeleteFileA() я использую MoveFileExA(), т.е. конечный у меня алгоритм такой:
1) Человек запускает прогу
2) Прога долбится искать обновление
3) Если обновление есть, то оно скачивает во временный каталог
4) Создаётся усыплённый Explorer.exe, и в него вклинивается код с двумя путями: ParamStr(0) (имя текущей программы) и путь до временного файла в темпе (назовём его TEMPFileName)
5) Текущий процесс завершает свою работу, размораживая Explorer.exe
6) Внедрённый код в Explorer.exe делает следующее:
- ждёт, пока завершит работу родительский процесс
- затем, через MoveFileExA() перемещает TEMPFileName заместо ParamStr(0) (на его место)
- снова запускает ParamStr(0) (уже проапдейтеную версию)
- и завершает работу

Т.е. в итоге программа обновилась, а ты даже этого не заметил - работаешь, как работал. (*улыбается*)

Скажу сразу - вирусы, трояны и прочую хрень никогда не писал и не собираюсь.
Просто мне нравится элегантное и красивое решение, когда не создаёт 200 файлов, один из которых обновляет первый, третий - четвёртый и т.д. Хочу, чтобы моя программа была в одном файле.
Вариант совать в ресур .EXE Updater'а, и создавать его в TEMP'е с флагом FILE_FLAG_DELETE_ON_CLOSE у CreateFile() мне тоже не очень нравится, потому что .EXE файл будет так или иначе больше жрать, чем приведённый выше код.

P.S. Пишу вполне легальную программу. На данный момент ей пользуется ~ 30 человек. (*улыбается*)
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

Сообщения в этой теме
-=CHE@TER=-   Самоудаляющийся .EXE файл   Jun 23 2007, 10:13
-=CHE@TER=-   Немного поправил исходный код с move() и ещё пара ...   Jun 23 2007, 16:27
Siberian GRemlin   А не проще сделать генералицю .bat'ника с кома...   Jun 24 2007, 10:50
-=CHE@TER=-   А не проще сделать генералицю .bat'ника с кома...   Jun 24 2007, 13:43
-=CHE@TER=-   Гм, так и знал. EntryPoint от explorer.exe я получ...   Jun 25 2007, 12:30
Heim   Заменил local.fnWaitForSingleObject = (FAR...   Jun 28 2007, 11:29
-=CHE@TER=-   Heim! Неа, не работает. Мне нужны адреса функц...   Jun 28 2007, 11:45
Xplorer   Исправленный код: Procedure SelfDel; Assembler; As...   Jun 28 2007, 13:32
-=CHE@TER=-   Исправленный код: <cut> Адреса в kernel32.d...   Jun 28 2007, 13:56
nickolayer   Ох ты. Потрясающе. Я честно скажу, последние три с...   Jun 30 2007, 09:50
Axsis   Чё-то я не совсем понял принцип работы этого кода....   Jul 3 2007, 07:17
-=CHE@TER=-   Чё-то я не совсем понял принцип работы этого кода....   Jul 3 2007, 08:47
Axsis   Сразу со 2-го пункта: ругаться могут не столько ан...   Jul 4 2007, 17:16
-=CHE@TER=-   Сразу со 2-го пункта: ругаться могут не столько ан...   Jul 5 2007, 09:23
Axsis   Я не знаю ни одного трейнера который бы патчил ко...   Jul 5 2007, 15:38
-=CHE@TER=-   Я не знаю ни одного трейнера который бы патчил код...   Jul 5 2007, 17:00
Axsis   Хех, конечно я не вручную его проверял, есть тако...   Jul 5 2007, 20:25
-=CHE@TER=-   Хех, конечно я не вручную его проверял, есть такой...   Jul 5 2007, 21:35


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0 -

 



Упрощённая версия Сейчас: 19th June 2024 - 21:31