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 5 2007, 20:25
Сообщение #2


Advanced Member
***

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



QUOTE
Ого! Моё почтение! Ты, наверное, тестированием антивирусных систем занимаешься? (*улыбается*) Спасибо тебе большое за отчёт! На самом деле были у меня подозрения, но ты их развеял. (*улыбается*) Спасибо! И правда, антивирусов, которые считают программу трояном - мало. И к тому же они все (ИМХО) аутсайдеры - т.е. их мало кто использует.

Хех, конечно я не вручную его проверял, есть такой замечательный сайтик http://www.virustotal.com/ на котором можно через форму загрузить свой файл и он проверится всеми этими антивирусами, всё это разумеется халявное, но вот в зависимости от загруженности сервера придётся подождать от 1 до 30 минут в очереди (+ 1-2 минуты на проверку) Поэтому когда нужно что-либо быстро проверить обхожусь онлайн-сканером каспера - http://www.kaspersky.ru/scanforvirus/ . Я думал ты слышал о вирустотал'е rolleyes.gif
QUOTE
QUOTE
Дома ещё с аутпостом проверю, глянем на его реакцию. Ещё бы с KIS проверить, тока нету его у меня

Я даже слов таких не знаю. (*улыбается*) А KIS - это что?

Аутпост - это Agnitum Outpost Firewall - фаервол, как и следует из названия smile.gif
KIS - это Kaspersky Internet Security, в который входят Kasp. AntiVirus и Kasp. AntiHacker (последнее - тоже фаервол smile.gif)
Так вот у обеих прог с некоторых пор есть проактивная защита, которая отслеживает всякие действия, которые в основном используются вредоносным ПО, такие как внедрение в адресное пространство другого процеса, установка перехватчиков нажатий клавиш, модификация критических ключей реестра и т.д.
Результатом работы этой защиты у аутпоста является вот такое окошко (как я и предполагал) :

Если нажать "Allow Once" то файл удаляется, а если "Block Once" то память не модифицируется и просто запускается проводник, то есть оригинальный explorer.exe smile.gif
Даю 99% что КИС отреагирует точно так.
QUOTE
Понимаешь, с ключом-параметром, ты даёшь (теоретически) возможность пользователю самому этот ключ использовать. Он может например даже другим пользователям какую-нибудь гадость сделать.

Помню ты упоминал что работал бета-тестером smile.gif Про параметр можно нигде не упоминать пользователи не будут даже знать о нем (кому надо тот конечно найдёт). А можно и вовсе обойтись без передачи параметра - например сделать проверку на имя exe-шника, например так (допустим у нас будет prog.exe):
- запускаем оригинал prog.exe (или prog.tmp)
- prog.exe (prog.tmp) проверяет своё расширение
если exe:
- проверка и загрузка обновления в prog.tmp, если обновления нет - продолжаем нормально работать
- prog.exe запускает prog.tmp а сам завершается
иначе:
- ждём завершения prog.exe и переименовываем себя (prog.tmp) в prog.exe
надеюсь ты поймёшь что я имел ввиду wink.gif если нет - напишу в виде норм. алгоритма а не такого бреда smile.gif
вариантов решения для конкретно этого случая (когда надо не удалить а обновить) много и ИМХО код без внедрения будет безопаснее, ведь в твоём случае, код, записываемый в explorer, "злодеи" тоже могут подправить tongue.gif и кстати, а будет ли это работать под ограниченной учётной записью? или тока с правами админа? huh.gif
User is offlineProfile CardPM
Go to the top of the page
+Quote Post
-=CHE@TER=-
Jul 5 2007, 21:35
Сообщение #3


Walter Sullivan
***

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



QUOTE(Axsis @ Jul 5 2007, 08:25 PM) *
Хех, конечно я не вручную его проверял, есть такой замечательный сайтик http://www.virustotal.com/ на котором можно через форму загрузить свой файл и он проверится всеми этими антивирусами, всё это разумеется халявное, но вот в зависимости от загруженности сервера придётся подождать от 1 до 30 минут в очереди (+ 1-2 минуты на проверку) Поэтому когда нужно что-либо быстро проверить обхожусь онлайн-сканером каспера - http://www.kaspersky.ru/scanforvirus/ . Я думал ты слышал о вирустотал'е rolleyes.gif
Теперь - слышал. Ещё раз спасибо! (*улыбается*)

QUOTE(Axsis @ Jul 5 2007, 08:25 PM) *
KIS - это Kaspersky Internet Security, в который входят Kasp. AntiVirus и Kasp. AntiHacker (последнее - тоже фаервол smile.gif)
Аутпост-то я знаю. KIS первый раз слышу. Хотя предпологал, что "K" - от кашпировского.

QUOTE(Axsis @ Jul 5 2007, 08:25 PM) *
Результатом работы этой защиты у аутпоста является вот такое окошко (как я и предполагал) :

Если нажать "Allow Once" то файл удаляется, а если "Block Once" то память не модифицируется и просто запускается проводник, то есть оригинальный explorer.exe smile.gif
Даю 99% что КИС отреагирует точно так.
А-а-а! Засада. (*улыбается*) Заблочили...

QUOTE(Axsis @ Jul 5 2007, 08:25 PM) *
Помню ты упоминал что работал бета-тестером smile.gif
(*слава богу я там больше не работаю*)

QUOTE(Axsis @ Jul 5 2007, 08:25 PM) *
- ждём завершения prog.exe и переименовываем себя (prog.tmp) в prog.exe
У меня было сильно сомнение, но я всё-таки переборол свою лень и проверил твоё предложение из предыдущего поста - действительно, оказывается, во время работы .EXE файл можно переименовывать. Кхех - весело. (*улыбается*) Думаю, что это решает тогда все мои проблемы без внедрения кода. Спасибо за дельный совет (хотя какая идея и реализация были красивые... (*улыбается*))!
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
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0 -

 



Упрощённая версия Сейчас: 27th April 2024 - 18:23