![]() |
Добро пожаловать, гость ( Вход | Регистрация )
![]() |
-=CHE@TER=- |
![]()
Сообщение
#1
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,371 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 318 раз(а) ![]() |
Вот, есть такая статья: 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. Однако, где-то я чего-то упустил, ибо программа запускается, но ничего не делает. Кто-нибудь может помочь? |
![]() ![]() |
Xplorer |
![]()
Сообщение
#2
|
Advanced Member ![]() ![]() ![]() Группа: CTPAX-X Сообщений: 52 Регистрация: 4-February 08 Пользователь №: 8 Спасибо сказали: 30 раз(а) ![]() |
Исправленный код:
CODE Procedure SelfDel; Assembler; Asm call @code @pExitProcess: dd 0 @pWaitForSingleObject: dd 0 @pSleep: dd 0 @pDeleteFile: dd 0 @pCloseHandle: dd 0 @hParent: dd 0 // MAX_PATH = 260 { windows.pas } @szFileName: db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 nop nop nop nop @code: // ****************************** // full injection code: pop ebp push INFINITE mov ebx, TInitStruct(ebp).hParent push ebx call TInitStruct(ebp).pWaitForSingleObject mov ebx, TInitStruct(ebp).hParent push ebx call TInitStruct(ebp).pCloseHandle @delfile: lea ebx, TInitStruct(ebp).szFileName push ebx call TInitStruct(ebp).pDeleteFile or eax, eax jne @exit push 500 call TInitStruct(ebp).pSleep jmp @delfile @exit: push 0 call TInitStruct(ebp).pExitProcess End; А вот адреса API функций - левые. Их нужно именно как-то получить из запущенного процесса. Адреса в kernel32.dll для всех процессов одинаковые, т.к. это DLL (в памяти находится только один экземпляр кода). |
-=CHE@TER=- |
![]()
Сообщение
#3
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,371 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 318 раз(а) ![]() |
Исправленный код: О!!! Спасибо большое, ты гигант!!!<cut> Адреса в kernel32.dll для всех процессов одинаковые, т.к. это DLL (в памяти находится только один экземпляр кода). Я не знал про общий адрес, спасибо за справку и разъяснение! Только я не понял пару моментов: 1) На что указывает ebp, когда ты сделал команду pop ebp (он чему вообще равен был?) Я так понял, что ты его из стэка вытащил, а кто туда его сложил и с каким значением? 2) call @code - почему именно call, а не jmp? Это как раз связано с ebp? А! До меня, кажется, допёрло - ebp - это адрес возврата из call и он автоматически при вызове call ложится в стэк?.. (*улыбается*) Значит он должен как раз указывать на следующую инструкцию, после call - как раз на структуру. Тогда, и правда, простое и элегантное решение! Это так? (*улыбается*) Вот полный, причёсанный код (для тех, кто будет компилировать - нули справа от @szFileName: должны быть на ОДНОЙ встрочке!): CODE // // DSelfDel.dpr // // Self deleting executable for Win9x/WinNT (all versions) // URL: http://www.catch22.net/tuts/selfdel.asp // // Idea: J Brown 1/10/2003 // Delphi/ASM code by: -=CHE@TER=- / Xplorer // Program DSelfDel; Uses Windows; { Few more ways to go: 1. Self-deleting .BAT file 2. Create temporary file using CreateFile() with FILE_FLAG_DELETE_ON_CLOSE flag. URL: http://forum.vingrad.ru/act-ST/f-1/t-12088/unread-1/anchor-entry77762/0.html } Type TInitStruct = Packed Record pExitProcess: Pointer; pWaitForSingleObject: Pointer; pSleep: Pointer; pDeleteFile: Pointer; pCloseHandle: Pointer; hParent: THandle; szFileName: Array[0..MAX_PATH-1] Of Char; End; Procedure SelfDel; Assembler; Asm call @code @pExitProcess: dd 0 @pWaitForSingleObject: dd 0 @pSleep: dd 0 @pDeleteFile: dd 0 @pCloseHandle: dd 0 @hParent: dd 0 // MAX_PATH = 260 { windows.pas } @szFileName: db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @code: // ****************************** // full injection code: pop ebp push INFINITE mov ebx, TInitStruct(ebp).hParent push ebx call TInitStruct(ebp).pWaitForSingleObject mov ebx, TInitStruct(ebp).hParent push ebx call TInitStruct(ebp).pCloseHandle @delfile: lea ebx, TInitStruct(ebp).szFileName push ebx call TInitStruct(ebp).pDeleteFile or eax, eax jne @exit push 500 call TInitStruct(ebp).pSleep jmp @delfile @exit: push 0 call TInitStruct(ebp).pExitProcess End; Function GetCodeSize(P: PByte): Cardinal; Assembler; Asm mov ebx, eax mov cl, 0C3h @loop: inc eax cmp [eax], cl jnz @loop sub eax, ebx inc eax End; { used links: http://www.codeproject.com/useritems/selfdel.asp http://undocumented.ntinternals.net/ } Function GetProcessEntryPointAddress(hProcess, hThread: THandle): Cardinal; Var read, dwFSBase, dwImageBase, dwOffset, dwOptHeaderOffset, dd: Cardinal; context: TContext; entry: LDT_ENTRY; Begin // // get the current thread context // context.ContextFlags:=CONTEXT_FULL Or CONTEXT_DEBUG_REGISTERS; GetThreadContext(hThread, context); // // use the segment register value to get a pointer to // the TEB // GetThreadSelectorEntry(hThread, context.SegFs, entry); dwFSBase:=(entry.BaseHi ShL 24) Or (entry.BaseMid ShL 16) Or (entry.BaseLow); // // read the teb // ReadProcessMemory(hProcess, Ptr(dwFSBase + 48), @dd, 4, read); {1} // // read the peb from the location pointed at by the teb // ReadProcessMemory(hProcess, Ptr(dd + 8), @dwImageBase, 4, read); {2} // // figure out where the entry point is located; // ReadProcessMemory(hProcess, Ptr(dwImageBase + $3C), @dwOffset, 4, read); {3} dwOptHeaderOffset:=(dwImageBase + dwOffset + 4 + 20); ReadProcessMemory(hProcess, Ptr(dwOptHeaderOffset + 16), @dd, 4, read); {4} result:=dwImageBase + dd; End; Function DeleteSelf: Boolean; Var CodeSize, EntryPoint, dummy: Cardinal; InitStruct: TInitStruct; hKrnl32: HModule; St: String; Pt: PByte; si: STARTUPINFO; pi: PROCESS_INFORMATION; Begin result:=False; ZeroMemory(@si, SizeOf(si)); si.cb:=SizeOf(si); If CreateProcess(Nil, PChar('explorer.exe'), Nil, Nil, False, CREATE_SUSPENDED Or IDLE_PRIORITY_CLASS, Nil, Nil, si, pi) Then Begin With InitStruct Do Begin DuplicateHandle(GetCurrentProcess, GetCurrentProcess, pi.hProcess, @hParent, 0, FALSE, 0); hKrnl32:=GetModuleHandle('kernel32'); pExitProcess:=GetProcAddress(hKrnl32, 'ExitProcess'); pWaitForSingleObject:=GetProcAddress(hKrnl32, 'WaitForSingleObject'); pSleep:=GetProcAddress(hKrnl32, 'Sleep'); pDeleteFile:=GetProcAddress(hKrnl32, 'DeleteFileA'); pCloseHandle:=GetProcAddress(hKrnl32, 'CloseHandle'); FillChar(szFileName, MAX_PATH, 0); St:=ParamStr(0); Move(St[1], szFileName, Length(St)); End; Pt:=@SelfDel; Inc(Pt, 5); // offset to structure WriteProcessMemory(GetCurrentProcess, Pt, @InitStruct, SizeOf(InitStruct), dummy); Dec(Pt, 5); // restore offset to program start CodeSize:=GetCodeSize(Pt); EntryPoint:=GetProcessEntryPointAddress(pi.hProcess, pi.hThread); VirtualProtectEx(pi.hProcess, Ptr(entrypoint), CodeSize, PAGE_EXECUTE_READWRITE, dummy); WriteProcessMemory(pi.hProcess, Ptr(entrypoint), Pt, CodeSize, dummy); FlushInstructionCache(pi.hProcess, Ptr(entrypoint), CodeSize); ResumeThread(pi.hThread); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); result:=True; End; End; Begin DeleteSelf; End. |
![]() ![]() |
Упрощённая версия | Сейчас: 30th April 2025 - 20:55 |