Самоудаляющийся .EXE файл, Self-Deleting Executable |
Добро пожаловать, гость ( Вход | Регистрация )
Самоудаляющийся .EXE файл, Self-Deleting Executable |
-=CHE@TER=- |
Jun 23 2007, 10:13
Сообщение
#1
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Вот, есть такая статья: 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. Однако, где-то я чего-то упустил, ибо программа запускается, но ничего не делает. Кто-нибудь может помочь? |
-=CHE@TER=- |
Jun 23 2007, 16:27
Сообщение
#2
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Немного поправил исходный код с move() и ещё пара ошибок зафиксено.
По прежнему ничего не делает, причём, похоже, remote_thread() вообще управление не передаётся. Кто-нибудь может помочь? |
Siberian GRemlin |
Jun 24 2007, 10:50
Сообщение
#3
|
Advanced Member Группа: CTPAX-X Сообщений: 537 Регистрация: 4-February 08 Пользователь №: 2 Спасибо сказали: 221 раз(а) |
А не проще сделать генералицю .bat'ника с командой удаления .exe и его исполнение?
|
-=CHE@TER=- |
Jun 24 2007, 13:43
Сообщение
#4
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
А не проще сделать генералицю .bat'ника с командой удаления .exe и его исполнение? Это не спортивно. (*улыбается*)Хочется аккуратное решение. Думаю, что тут скорее всего нужно будет сделать код на асме, там править адреса и уже его инжектировать в процесс "explorer.exe" (как только это делать - пока что х.з.). Потому что, как мне кажется, расколбас идёт из-за того, что код на Delphi занимает больше, чем на C++ (CODESIZE = $200;). Добавлено: Пытаюсь через Assembler работать - вот, пока что получилось адрес заменить: CODE Uses Windows; {$APPTYPE CONSOLE} Procedure SelfDel; Assembler; Asm jmp @code @pExitProcess: dd 00 @code: xor eax,eax push eax call Cardinal(@pExitProcess) retn End; procedure DeleteSelf; var pExitProcess: pointer; pt: PByte; dummy: cardinal; begin pt:=@selfdel; Inc(pt, 2); pExitProcess:=@ExitProcess; WriteProcessMemory(GetCurrentProcess, pt, @pExitProcess, 4, dummy); end; Begin DeleteSelf; SelfDel; WriteLn('failed'); End. Думаю по-позже с "explorer.exe" попробовать. Только за адреса вызова не ручаюсь... У меня сомнения есть + непонятно, как EntryPoint указывать. В общем, буду рад любой помощи. |
-=CHE@TER=- |
Jun 25 2007, 12:30
Сообщение
#5
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Гм, так и знал. EntryPoint от explorer.exe я получил, но вот вживить приведённый выше код SelfDel туда не получается - адреса у API функций другие... Кто-нибудь знает, как получить адреса необходимых API функций у запущенного процесса? Что-нибудь типа GetProcAddress(hHandle, 'ExitProcess'); только в Suspended процессе?..
|
Heim |
Jun 28 2007, 11:29
Сообщение
#6
|
Незарегистрирован |
Заменил
CODE local.fnWaitForSingleObject = (FARPROC)WaitForSingleObject; local.fnCloseHandle = (FARPROC)CloseHandle; local.fnDeleteFile = (FARPROC)DeleteFile; local.fnSleep = (FARPROC)Sleep; local.fnExitProcess = (FARPROC)ExitProcess; local.fnRemoveDirectory = (FARPROC)RemoveDirectory; local.fnGetLastError = (FARPROC)GetLastError; на: CODE HMODULE hMod = LoadLibrary(_T("Kernel32.dll")); if( hMod ) { local.fnWaitForSingleObject = GetProcAddress( hMod, "WaitForSingleObject" );//(FARPROC)WaitForSingleObject; local.fnCloseHandle = GetProcAddress( hMod, "CloseHandle" );//(FARPROC)CloseHandle; local.fnDeleteFile = GetProcAddress( hMod, "DeleteFileW" );//(FARPROC)DeleteFile; local.fnSleep = GetProcAddress( hMod, "Sleep" );//(FARPROC)Sleep; local.fnExitProcess = GetProcAddress( hMod, "ExitProcess" );//(FARPROC)ExitProcess; local.fnRemoveDirectory = GetProcAddress( hMod, "RemoveDirectoryW" );//(FARPROC)RemoveDirectory; local.fnGetLastError = GetProcAddress( hMod, "GetLastError" );//(FARPROC)GetLastError; FreeLibrary( hMod ); } Работает... Может тебе поможет???? |
-=CHE@TER=- |
Jun 28 2007, 11:45
Сообщение
#7
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Heim!
Неа, не работает. Мне нужны адреса функций именно из адресного пространства другого процесса. Вот код, который я сделал: CODE Uses Windows; {$APPTYPE CONSOLE} 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 jmp @code @pExitProcess: dd 00 @pWaitForSingleObject: dd 00 @pSleep: dd 00 @pDeleteFile: dd 00 @pCloseHandle: dd 00 @hParent: dd 00 // 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: lea eax, @hParent push eax push INFINITE call DWORD(@pWaitForSingleObject) lea eax, @hParent push eax call DWORD(@pCloseHandle) @delfile: push 03E8h // 1 sec call DWORD(@pSleep) lea eax, @szFileName push eax call DWORD(@pDeleteFile) test eax, eax jz @delfile xor eax,eax push eax call DWORD(@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 context: TContext; entry: LDT_ENTRY; read, dwFSBase, dwImageBase, dwOffset, dwOptHeaderOffset: Cardinal; dd: cardinal; 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 // WriteLn(ReadProcessMemory(hProcess, Ptr(dwFSBase + 48), @dd, 4, read)); {1} // // read the peb from the location pointed at by the teb // WriteLn(ReadProcessMemory(hProcess, Ptr(dd + 8), @dwImageBase, 4, read)); {2} // // figure out where the entry point is located; // WriteLn(ReadProcessMemory(hProcess, Ptr(dwImageBase + $3C), @dwOffset, 4, read)); {3} dwOptHeaderOffset:=(dwImageBase + dwOffset + 4 + 20); WriteLn(ReadProcessMemory(hProcess, Ptr(dwOptHeaderOffset + 16), @dd, 4, read)); {4} result:=dwImageBase + dd; End; Function DeleteSelf: Boolean; Var InitStruct: TInitStruct; hKrnl32: HModule; dummy: Cardinal; St: String; Pt: PByte; {---} si: STARTUPINFO; pi: PROCESS_INFORMATION; CodeSize, oldprot, entrypoint: Cardinal; Begin result:=False; With InitStruct Do Begin 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)); hParent:=0; End; 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 DuplicateHandle(GetCurrentProcess, GetCurrentProcess, pi.hProcess, @InitStruct.hParent, 0, FALSE, 0); Pt:=@selfdel; Inc(Pt, 5); // offset to structure WriteLn(WriteProcessMemory(GetCurrentProcess, Pt, @InitStruct, SizeOf(InitStruct), dummy)); Dec(Pt, 5); // restore offset to program start CodeSize:=GetCodeSize(Pt); entrypoint:=GetProcessEntryPointAddress(pi.hProcess, pi.hThread); oldprot:=0; VirtualProtectEx(pi.hProcess, Ptr(entrypoint), CodeSize, PAGE_EXECUTE_READWRITE, oldProt); WriteLn(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; WriteLn('ready'); End. При запуске, если в код, сразу вставить C3, чтобы процесс завершил работу - то всё ок. А вот адреса API функций - левые. Их нужно именно как-то получить из запущенного процесса. |
Xplorer |
Jun 28 2007, 13:32
Сообщение
#8
|
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=- |
Jun 28 2007, 13:56
Сообщение
#9
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Исправленный код: О!!! Спасибо большое, ты гигант!!!<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. |
nickolayer |
Jun 30 2007, 09:50
Сообщение
#10
|
Member Группа: Delegated Сообщений: 23 Регистрация: 4-February 08 Пользователь №: 1,698 Спасибо сказали: 1 раз(а) |
Ох ты. Потрясающе. Я честно скажу, последние три строчки поражают своей простотой. А все остальное просто поражает.
|
Axsis |
Jul 3 2007, 07:17
Сообщение
#11
|
Advanced Member Группа: CTPAX-X Сообщений: 121 Регистрация: 6-February 08 Пользователь №: 374 Спасибо сказали: 149 раз(а) |
Чё-то я не совсем понял принцип работы этого кода... Вы создаёте процесс explorer.exe, усыпляете его и копируете в него свой код? =( ) Если так, то мне интересно, как отнесутся антивирусы и всякие системы проактивной защиты к такому действию? Представьте, что человек слил прогу с инета, запустил, а антивирь написал, что так и так, предотвращена попытка вклиниться в аднесное пространство explorer.exe! А если после этого ещё и оригинальный exe'шник удалится... Да чел в жизни отсюда ничего больше не скачает! Если я всё провильно понял, то подобный код допустим только для личного использования, в публичные проги его пихать нельзя! Или, может, я что-то пропустил и -=CHE@TER=- переключился на написание троянов? =)
ЗЫ: если я неправильно понял, плиз напишите принцип работы ЭТОГО |
-=CHE@TER=- |
Jul 3 2007, 08:47
Сообщение
#12
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Чё-то я не совсем понял принцип работы этого кода... Вы создаёте процесс explorer.exe, усыпляете его и копируете в него свой код? =( ) Если так, то мне интересно, как отнесутся антивирусы и всякие системы проактивной защиты к такому действию? Представьте, что человек слил прогу с инета, запустил, а антивирь написал, что так и так, предотвращена попытка вклиниться в аднесное пространство explorer.exe! А если после этого ещё и оригинальный exe'шник удалится... Да чел в жизни отсюда ничего больше не скачает! Если я всё провильно понял, то подобный код допустим только для личного использования, в публичные проги его пихать нельзя! Или, может, я что-то пропустил и -=CHE@TER=- переключился на написание троянов? =) Ок, давайте по порядку:ЗЫ: если я неправильно понял, плиз напишите принцип работы ЭТОГО 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 человек. (*улыбается*) |
Axsis |
Jul 4 2007, 17:16
Сообщение
#13
|
Advanced Member Группа: CTPAX-X Сообщений: 121 Регистрация: 6-February 08 Пользователь №: 374 Спасибо сказали: 149 раз(а) |
Сразу со 2-го пункта: ругаться могут не столько антивири, сколько системы проактивной защиты, типа тех что в Outpost Firewall и Kaspersky Internet Security. ArtMoney и прочие трейнеры не пишут в область кода другого процесса, поэтому тут надо будет проверять работу с такими прогами. Дома смогу проверить работоспособность с Аутпостом, тока дельфя не установлена - выкладывай откомпиленный
3. Для обновления можно юзать ещё такой алгоритм: - при запуске прога проверяет обновление - скачивает его и сохраняет во временный файл с произвольным именем - запускает временный файл на исполнение (можно с параметром, указывающим что это первый запуск новой версии) - оригинал завершает работу - временный файл после проверки что оригинал завершился переименовывает себя в нормальное имя (на сколько я знаю, переименование запущенных файлов в винде допускается) и продолжает нормально выполняться Если прога ходит за обновлениями в инет, то надо особенно тщательно проверить работоспособность этого алгоритма с разными системами защиты (антивирями, проактивками), потому что если сначала будет предупреждение о модификации explorer.exe, а потом ещё и в инет прога полезет, то опытного пользователя будет очень нелегко убедить что она за обновлением полезла )) ЗЫ: про вирусы-трояны я конечно пошутил, но среди этих зверьков попадаются настоящие произведения программерского искусства, которые писались явно не дураками =) |
-=CHE@TER=- |
Jul 5 2007, 09:23
Сообщение
#14
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Сразу со 2-го пункта: ругаться могут не столько антивири, сколько системы проактивной защиты, типа тех что в Outpost Firewall и Kaspersky Internet Security. ArtMoney и прочие трейнеры не пишут в область кода другого процесса, поэтому тут надо будет проверять работу с такими прогами. Дома смогу проверить работоспособность с Аутпостом, тока дельфя не установлена - выкладывай откомпиленный Насчёт области кода и области данных... х.з. Есть же трейнеры, которые память патчат, чтобы жизнь вообще не отнималась (*улыбается*).QUOTE - временный файл после проверки что оригинал завершился переименовывает себя в нормальное имя (на сколько я знаю, переименование запущенных файлов в винде допускается) и продолжает нормально выполняться Тоже, в принципе, "с боку припёка". (*улыбается*)QUOTE Если прога ходит за обновлениями в инет, то надо особенно тщательно проверить работоспособность этого алгоритма с разными системами защиты (антивирями, проактивками), потому что если сначала будет предупреждение о модификации explorer.exe, а потом ещё и в инет прога полезет, то опытного пользователя будет очень нелегко убедить что она за обновлением полезла )) Не так - сначала ищется обновление, затем скачивается. И только потом Explorer.exe модифицируется. Нет обновления - нет запуска Explorer.exe и модификации.QUOTE ЗЫ: про вирусы-трояны я конечно пошутил, но среди этих зверьков попадаются настоящие произведения программерского искусства, которые писались явно не дураками =) Я не говорил, что они дураки. Однако, назвать их "умными" было бы тоже неправильно.Есть люди, которые просто ездят в автобусах, а есть такие, которые при этом ещё лазят по чужим карманам. Раз ты так не хочешь делать - значит они "не дураки", а ты дурак?.. ИМХО, вирусы, трояны и прочую лабудень может и пишут "не дураки", но уж точно не от большого ума. Добавлено: Блин, торможу - вот, лови. (*улыбается*) dselfdel.zip |
Axsis |
Jul 5 2007, 15:38
Сообщение
#15
|
Advanced Member Группа: CTPAX-X Сообщений: 121 Регистрация: 6-February 08 Пользователь №: 374 Спасибо сказали: 149 раз(а) |
QUOTE Насчёт области кода и области данных... х.з. Есть же трейнеры, которые память патчат, чтобы жизнь вообще не отнималась (*улыбается*). Я не знаю ни одного трейнера который бы патчил код игры, там принцип такой, что каждые несколько милисекунд трейнер восстанавливает значение в памяти на прежнее, то есть жизни отнимаются, но через несколько мс восстанавливаются, для игрока это незаметно просто Вот ещё отчёт с ВирусТотала для твоего файла: CODE Complete scanning result of "DSelfDel.exe", received in VirusTotal at 07.05.2007, 16:29:41 (CET). Antivirus Version Update Result AhnLab-V3 2007.7.5.0 07.05.2007 no virus found AntiVir 7.4.0.37 07.05.2007 HEUR/Malware <<<<<<<<<<<<<<< Authentium 4.93.8 07.04.2007 no virus found Avast 4.7.997.0 07.04.2007 no virus found AVG 7.5.0.476 07.04.2007 no virus found BitDefender 7.2 07.05.2007 no virus found CAT-QuickHeal 9.00 07.05.2007 no virus found ClamAV devel-20070416 07.05.2007 no virus found DrWeb 4.33 07.05.2007 no virus found eSafe 7.0.15.0 07.05.2007 suspicious Trojan/Worm <<<<<<<<<<<<<<< eTrust-Vet 30.8.3765 07.05.2007 no virus found Ewido 4.0 07.05.2007 no virus found FileAdvisor 1 07.05.2007 no virus found Fortinet 2.91.0.0 07.05.2007 no virus found F-Prot 4.3.2.48 07.04.2007 no virus found F-Secure 6.70.13260.0 07.05.2007 Possibly malicious <<<<<<<<<<<<<<< Ikarus T3.1.1.8 07.05.2007 no virus found Kaspersky 4.0.2.24 07.05.2007 no virus found McAfee 5067 07.04.2007 no virus found Microsoft 1.2701 07.05.2007 no virus found NOD32v2 2379 07.04.2007 no virus found Norman 5.80.02 07.04.2007 no virus found Panda 9.0.0.4 07.05.2007 no virus found Sophos 4.19.0 06.24.2007 no virus found Sunbelt 2.2.907.0 07.04.2007 no virus found Symantec 10 07.05.2007 no virus found TheHacker 6.1.6.142 07.04.2007 no virus found VBA32 3.12.0.2 07.05.2007 no virus found VirusBuster 4.3.23:9 07.05.2007 no virus found Webwasher-Gateway 6.0.1 07.05.2007 Heuristic.Malware <<<<<<<<<<<<<<< Aditional Information File size: 9728 bytes MD5: 20a3c83a74dd2aeb9f64bfe4894998c0 SHA1: 416ef725c4a8837e3a19c5e74bba2b46318dca5d packers: UPX Как видишь, эвристические движки 4 антивирей сочли этот код потенциально опасным. Да, это редкие (очень редкие ) антивирусы, но тем не менее... Дома ещё с аутпостом проверю, глянем на его реакцию. Ещё бы с KIS проверить, тока нету его у меня QUOTE Тоже, в принципе, "с боку припёка". (*улыбается*) На самом деле отличие от твоей версии лишь в том что файл заменяет себя сам а не из внедрённого кода, а в остальном... тот же временный файл, та же прозрачность для пользователя, та же реализация в виде 1-го exe... QUOTE Не так - сначала ищется обновление, затем скачивается. И только потом Explorer.exe модифицируется. Нет обновления - нет запуска Explorer.exe и модификации. Ну так всё-таки лучше |
-=CHE@TER=- |
Jul 5 2007, 17:00
Сообщение
#16
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Я не знаю ни одного трейнера который бы патчил код игры, там принцип такой, что каждые несколько милисекунд трейнер восстанавливает значение в памяти на прежнее, то есть жизни отнимаются, но через несколько мс восстанавливаются, для игрока это незаметно просто Просто есть моменты, когда игра резко обнуляет жизнь и тяжко успеть восстановить значение до того, как придёт надпись "Game Over".QUOTE Вот ещё отчёт с ВирусТотала для твоего файла: Ого! Моё почтение! Ты, наверное, тестированием антивирусных систем занимаешься? (*улыбается*) Спасибо тебе большое за отчёт! На самом деле были у меня подозрения, но ты их развеял. (*улыбается*) Спасибо! И правда, антивирусов, которые считают программу трояном - мало. И к тому же они все (ИМХО) аутсайдеры - т.е. их мало кто использует.QUOTE Как видишь, эвристические движки 4 антивирей сочли этот код потенциально опасным. Да, это редкие (очень редкие ) антивирусы, но тем не менее... Понимаю, но мне очень хочется, чтобы всё было "красиво". (*улыбается*)QUOTE Дома ещё с аутпостом проверю, глянем на его реакцию. Ещё бы с KIS проверить, тока нету его у меня Я даже слов таких не знаю. (*улыбается*) А KIS - это что?QUOTE На самом деле отличие от твоей версии лишь в том что файл заменяет себя сам а не из внедрённого кода, а в остальном... тот же временный файл, та же прозрачность для пользователя, та же реализация в виде 1-го exe... Понимаешь, с ключом-параметром, ты даёшь (теоретически) возможность пользователю самому этот ключ использовать. Он может например даже другим пользователям какую-нибудь гадость сделать. Например, запустить с этим ключом программу так, что она себя чем-нибудь другим заменит. ИМХО, чем меньше прав у пользователя - тем лучше. Он может делать всё, что не запрещено. А если есть что-то, что ему нельзя делать, но он это может - то это уже плохо. Программа должна быть кондовой: пользователь может хоть головой об компьютер долбиться, но она должна работать как надо. (*улыбается*) |
Axsis |
Jul 5 2007, 20:25
Сообщение
#17
|
Advanced Member Группа: CTPAX-X Сообщений: 121 Регистрация: 6-February 08 Пользователь №: 374 Спасибо сказали: 149 раз(а) |
QUOTE Ого! Моё почтение! Ты, наверное, тестированием антивирусных систем занимаешься? (*улыбается*) Спасибо тебе большое за отчёт! На самом деле были у меня подозрения, но ты их развеял. (*улыбается*) Спасибо! И правда, антивирусов, которые считают программу трояном - мало. И к тому же они все (ИМХО) аутсайдеры - т.е. их мало кто использует. Хех, конечно я не вручную его проверял, есть такой замечательный сайтик http://www.virustotal.com/ на котором можно через форму загрузить свой файл и он проверится всеми этими антивирусами, всё это разумеется халявное, но вот в зависимости от загруженности сервера придётся подождать от 1 до 30 минут в очереди (+ 1-2 минуты на проверку) Поэтому когда нужно что-либо быстро проверить обхожусь онлайн-сканером каспера - http://www.kaspersky.ru/scanforvirus/ . Я думал ты слышал о вирустотал'е QUOTE QUOTE Дома ещё с аутпостом проверю, глянем на его реакцию. Ещё бы с KIS проверить, тока нету его у меня Я даже слов таких не знаю. (*улыбается*) А KIS - это что? Аутпост - это Agnitum Outpost Firewall - фаервол, как и следует из названия KIS - это Kaspersky Internet Security, в который входят Kasp. AntiVirus и Kasp. AntiHacker (последнее - тоже фаервол ) Так вот у обеих прог с некоторых пор есть проактивная защита, которая отслеживает всякие действия, которые в основном используются вредоносным ПО, такие как внедрение в адресное пространство другого процеса, установка перехватчиков нажатий клавиш, модификация критических ключей реестра и т.д. Результатом работы этой защиты у аутпоста является вот такое окошко (как я и предполагал) : Если нажать "Allow Once" то файл удаляется, а если "Block Once" то память не модифицируется и просто запускается проводник, то есть оригинальный explorer.exe Даю 99% что КИС отреагирует точно так. QUOTE Понимаешь, с ключом-параметром, ты даёшь (теоретически) возможность пользователю самому этот ключ использовать. Он может например даже другим пользователям какую-нибудь гадость сделать. Помню ты упоминал что работал бета-тестером Про параметр можно нигде не упоминать пользователи не будут даже знать о нем (кому надо тот конечно найдёт). А можно и вовсе обойтись без передачи параметра - например сделать проверку на имя exe-шника, например так (допустим у нас будет prog.exe): - запускаем оригинал prog.exe (или prog.tmp) - prog.exe (prog.tmp) проверяет своё расширение если exe: - проверка и загрузка обновления в prog.tmp, если обновления нет - продолжаем нормально работать - prog.exe запускает prog.tmp а сам завершается иначе: - ждём завершения prog.exe и переименовываем себя (prog.tmp) в prog.exe надеюсь ты поймёшь что я имел ввиду если нет - напишу в виде норм. алгоритма а не такого бреда вариантов решения для конкретно этого случая (когда надо не удалить а обновить) много и ИМХО код без внедрения будет безопаснее, ведь в твоём случае, код, записываемый в explorer, "злодеи" тоже могут подправить и кстати, а будет ли это работать под ограниченной учётной записью? или тока с правами админа? |
-=CHE@TER=- |
Jul 5 2007, 21:35
Сообщение
#18
|
Walter Sullivan Группа: Root Admin Сообщений: 1,361 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 314 раз(а) |
Хех, конечно я не вручную его проверял, есть такой замечательный сайтик http://www.virustotal.com/ на котором можно через форму загрузить свой файл и он проверится всеми этими антивирусами, всё это разумеется халявное, но вот в зависимости от загруженности сервера придётся подождать от 1 до 30 минут в очереди (+ 1-2 минуты на проверку) Поэтому когда нужно что-либо быстро проверить обхожусь онлайн-сканером каспера - http://www.kaspersky.ru/scanforvirus/ . Я думал ты слышал о вирустотал'е Теперь - слышал. Ещё раз спасибо! (*улыбается*)KIS - это Kaspersky Internet Security, в который входят Kasp. AntiVirus и Kasp. AntiHacker (последнее - тоже фаервол ) Аутпост-то я знаю. KIS первый раз слышу. Хотя предпологал, что "K" - от кашпировского.Результатом работы этой защиты у аутпоста является вот такое окошко (как я и предполагал) : А-а-а! Засада. (*улыбается*) Заблочили...Если нажать "Allow Once" то файл удаляется, а если "Block Once" то память не модифицируется и просто запускается проводник, то есть оригинальный explorer.exe Даю 99% что КИС отреагирует точно так. Помню ты упоминал что работал бета-тестером (*слава богу я там больше не работаю*)- ждём завершения prog.exe и переименовываем себя (prog.tmp) в prog.exe У меня было сильно сомнение, но я всё-таки переборол свою лень и проверил твоё предложение из предыдущего поста - действительно, оказывается, во время работы .EXE файл можно переименовывать. Кхех - весело. (*улыбается*) Думаю, что это решает тогда все мои проблемы без внедрения кода. Спасибо за дельный совет (хотя какая идея и реализация были красивые... (*улыбается*))! |
Упрощённая версия | Сейчас: 14th November 2024 - 14:20 |