/*
* Thanks to Giuseppe Caulo <giusc@softzone.it>
* and thanks to http://www.catch22.net/tuts/selfdel.asp
*
*/
#include "SelfDeleting.h"
void remote_thread(SELFDEL *remote)
{
// Attende che il processo padre termini
remote->fnWaitForSingleObject(remote->hParent, INFINITE);
remote->fnCloseHandle(remote->hParent);
// prova a cancellare il file eseguibile
while(!remote->fnDeleteFile(remote->szFileName))
{
// fallito - prova dinuovo fra poco
remote->fnSleep(1000);
}
// finito! Possiamo uscire in modo pulito
remote->fnExitProcess(0);
}
void end_remote_thread(void) {}
BOOL SelfDelete(void)
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CONTEXT context;
DWORD oldProt;
SELFDEL local;
DWORD entrypoint;
size_t func_siz;
TCHAR szExe[MAX_PATH] = _T("explorer.exe");
//
// Avvia l'eseguibile sospeso
//
if(CreateProcess(0, szExe, 0, 0, 0, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, 0, 0, &si, &pi))
{
//Assegna un indirizzo alle funzioni da eseguire nel thread remoto
local.fnWaitForSingleObject = (FARPROC)WaitForSingleObject;
local.fnCloseHandle = (FARPROC)CloseHandle;
local.fnDeleteFile = (FARPROC)DeleteFile;
local.fnSleep = (FARPROC)Sleep;
local.fnExitProcess = (FARPROC)ExitProcess;
local.fnGetLastError = (FARPROC)GetLastError;
// Da' al processo remoto una copia dell'handle del nostro processo
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
pi.hProcess, &local.hParent, 0, FALSE, 0);
GetModuleFileName(0, local.szFileName, MAX_PATH);
//Copia il codice binario contenente le istruzioni da eseguire
func_siz = ((DWORD)end_remote_thread-(DWORD)remote_thread);
ZeroMemory(local.opCodes, 1024);
CopyMemory((void *)local.opCodes, FUNC_ADDR(remote_thread), func_siz);
//
// Alloca dello spazio nello stack del processo e ci piazza dentro
// la nostra struttura SELFDEL. Dopodiché imposta il puntatore alle
// istruzioni alla locazione desiderata e infine avvia il processo
//
context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
GetThreadContext(pi.hThread, &context);
// Alloca lo spazio nello stack correttamente allineato
entrypoint = (context.Esp - sizeof(SELFDEL)) & ~0x1F;
//
// Inserisce il puntatore alla struttura alla fine dello stack
// in modo che diventi il primo argomento del thread remoto
//
local.Arg0 = (SELFDEL *)entrypoint;
context.Esp = entrypoint - 4; // crea un finto indirizzo di ritorno
context.Eip = entrypoint + 4; // offset del codice all'interno della struttura
// Copia il nostro codice+dati nell'entry-point dell'eseguibile
VirtualProtectEx(pi.hProcess, (PVOID)entrypoint, sizeof(local), PAGE_EXECUTE_READWRITE, &oldProt);
WriteProcessMemory(pi.hProcess, (PVOID)entrypoint, &local, sizeof(local), 0);
FlushInstructionCache(pi.hProcess, (PVOID)entrypoint, sizeof(local));
SetThreadContext(pi.hThread, &context);
// Consente al processo di essere eseguito
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return TRUE;
}
return FALSE;
}