Contrariamente a quanto credono molte persone, in realtà ci sono diversi modi per farlo. Alcuni di loro sono comuni, alcuni visti raramente. Alcuni di loro sono deboli, altri forti. Tutto dipende da come lo fai.
Vediamone una raccolta:
1. Trucco RegisterServiceProcess
pre-NT
Windows 9x e altri sistemi operativi pre-NT avevano un'API non documentata in kernel32.dll chiamata RegisterServiceProcess
, che (come suggerisce il nome) registra il processo come servizio di sistema. Una volta che un processo aveva chiamato questa funzione, il sistema operativo la considerava critica e non avrebbe permesso al task manager di ucciderla. Questa funzione è stata rimossa quando è uscito NT, quindi non funziona su XP o versioni successive.
2. Trucchi per la denominazione dei processi
In WinXP, l'eseguibile di Task Manager conteneva un elenco hardcoded di nomi di processi che avrebbe rifiutato di uccidere, mostrando invece un messaggio come quello che hai menzionato. Fondamentalmente coprivano i servizi di sistema critici come smss.exe
e rpcss.exe
. Il problema era che il percorso non è stato controllato, quindi qualsiasi altro eseguibile con lo stesso nome risulterebbe in un processo irreversibile. Questo trucco non impedisce di per sé che il processo venga terminato, ma piuttosto impedisce al Task Manager di Windows XP di essere in grado di terminare il processo. È ancora possibile utilizzare un altro strumento per terminare il processo.
3. Processi di mantenimento
Questi sono di gran lunga i più comuni. Vengono creati due processi e controllano ripetutamente l'esistenza dell'altro. Se uno viene ucciso, l'altro lo resuscita. Questo non ti impedisce di interrompere davvero il processo, ma rende fastidioso interrompere il processo di ritorno.
Task Manager include un'opzione per terminare l'albero dei processi, che consente di terminare un processo e tutti i processi figli, il che può aiutare a risolvere questo problema. Quando un processo viene creato in Windows, il sistema operativo tiene traccia dell'ID del processo che lo ha creato. Kill process tree itera attraverso tutti i processi e cerca quelli che hanno un ID genitore uguale all'ID del processo che stai uccidendo. Poiché i processi keep-alive di solito funzionano su un polling ripetuto, puoi terminare entrambi i processi prima che si accorgano che qualcosa è andato storto.
Una difesa contro questo è creare un processo fittizio che genera il processo keep-alive, quindi avere l'uscita del processo fittizio. Il processo principale passa il proprio ID al processo fittizio e il processo fittizio passa il proprio ID al processo keep-alive, ma la catena viene interrotta quando il processo fittizio esce. Ciò lascia in esecuzione sia il processo primario che quello keepalive, ma rende impossibile utilizzare la funzione di kill process tree di Task Manager. Invece, dovresti scrivere uno script per ucciderli o utilizzare uno strumento che ti consenta di uccidere più processi contemporaneamente.
4. Hook in modalità utente tramite DLL caricate
È possibile iniettare una DLL in un processo in esecuzione. In effetti, Windows offre una funzionalità per caricare qualsiasi DLL in tutti i processi che importano user32.dll, ai fini dell'estensibilità. Questo metodo è chiamato AppInit DLL. Una volta che una DLL viene inserita, potrebbe manipolare la memoria del processo. È quindi possibile sovrascrivere i valori di determinati puntatori a funzione in modo che la chiamata venga reindirizzata a una routine di stub, che quindi chiama la funzione di destinazione. Quella routine stub può essere utilizzata per filtrare o manipolare i parametri e restituire i valori di una chiamata di funzione. Questa tecnica è chiamata hooking e può essere molto potente. In questo caso, sarebbe possibile iniettare una DLL nei processi in esecuzione che aggancia OpenProcess
e TerminateProcess
per garantire che nessuna applicazione possa ottenere un handle per il processo o terminarlo . Ciò si traduce in qualche modo in una corsa agli armamenti, poiché è possibile utilizzare API alternative in modalità utente per terminare i processi ed è difficile collegarli e bloccarli tutti, soprattutto se si considerano le API non documentate.
5 . Hook in modalità utente tramite thread iniettati
Questo trucco funziona come con le DLL, tranne per il fatto che non è necessario alcun file DLL. Viene creato un handle per il processo di destinazione, una parte della memoria viene allocata al suo interno tramite VirtualAllocEx
, il codice e i dati vengono copiati nel blocco di memoria tramite WriteProcessMemory
e viene creato un thread in il processo tramite CreateRemoteThread
. Ciò si traduce in un codice esterno che viene eseguito all'interno di un processo di destinazione, che può quindi istigare vari hook per impedire che un processo venga ucciso.
6. Hook di chiamata in modalità kernel
Nel kernel, c'è una struttura speciale chiamata SSDT (System Service Dispatch Table), che mappa gli ID delle funzioni dalle chiamate in modalità utente ai puntatori alle funzioni delle API del kernel. Questa tabella viene utilizzata per passare dalla modalità utente alla modalità kernel. Se è possibile caricare un driver dannoso, potrebbe modificare l'SSDT per eseguire la propria funzione, invece dell'API corretta. Questo è un hook in modalità kernel, che costituisce un rootkit. In sostanza è possibile gettare la lana sugli occhi del sistema operativo restituendo dati fasulli dalle chiamate. In effetti, è possibile rendere il processo non solo non uccidibile, ma anche invisibile. Un problema con questo su build x64 è che SSDT è protetto da Kernel Patch Protection (KPP). È possibile disabilitare KPP, ma ciò ha conseguenze di vasta portata che potrebbero rendere difficile lo sviluppo di un rootkit.
7. Manipolazione diretta degli oggetti del kernel (DKOM)
Questo trucco comporta anche il caricamento di un driver dannoso sul sistema operativo, ma non richiede l'alterazione dell'SSDT. I processi sul sistema sono memorizzati come strutture EPROCESS
nel kernel. Tieni presente che questa struttura dipende interamente dalla versione ed è solo parzialmente documentata da Microsoft, quindi è necessario il reverse engineering su più versioni di destinazione per assicurarti che il codice non tenti di leggere i puntatori oi dati sbagliati. Tuttavia, se riesci a individuare ed enumerare con successo le strutture EPROCESS
nel kernel, è possibile manipolarle.
Ogni voce nell'elenco dei processi ha un puntatore FLink
e BLink
, che punta al processo successivo e precedente nell'elenco. Se identifichi il tuo processo di destinazione e fai in modo che i suoi puntatori FLink
e BLink
rimandino a se stessi e i FLink
e BLink
dei suoi fratelli puntano l'uno verso l'altro, il sistema operativo salta semplicemente il processo quando si eseguono operazioni di pulizia, ad es. processi di uccisione. Questo trucco si chiama scollegamento. Ciò non solo rende il processo invisibile all'utente, ma impedisce anche a tutte le API in modalità utente di prendere di mira il processo a meno che non sia stato generato un handle per il processo prima che fosse scollegato. Questa è una tecnica rootkit molto potente, soprattutto perché è difficile ripristinarla.
8. Trucchi del debugger
Questo è un trucco piuttosto interessante che devo ancora vedere in natura, ma funziona abbastanza bene. L'API del debugger di Windows consente a qualsiasi processo di eseguire il debug di un altro, a condizione che disponga delle autorizzazioni per farlo. Se si utilizza l'API del debugger, è possibile mettere un processo in uno stato "debuggato". Se questo processo contiene un thread che è attualmente interrotto da un debugger, il processo non può essere terminato da Windows, perché non è possibile garantire il controllo appropriato del thread durante la terminazione quando il thread è bloccato. Ovviamente, se uccidi il debugger, il processo smette di essere sottoposto a debug e si chiude o si blocca. Tuttavia, a volte è possibile produrre una situazione in cui esiste una catena di processi che eseguono il debug a vicenda in un ciclo. Se ogni processo interrompe un thread fittizio nel successivo, nessuno può essere ucciso. Nota che è possibile per un utente esperto uccidere manualmente altri thread all'interno del processo, rendendolo inutilizzabile, ma non verrà comunque ucciso.
9. Windows 8 DRM
Questo è uno nuovo di cui ho sentito parlare solo di recente, ma non ne so molto. Su Twitter circolava un po 'di voci al riguardo, e ho visto frammenti qua e là su vari siti tecnici, ma devo ancora vedere alcuna ricerca concreta. Penso che sia ancora agli inizi. In sostanza, la storia è che Windows 8 ha un meccanismo che consente ai "fornitori affidabili" di registrare i processi come DRM critici, impedendo che vengano uccisi o manipolati dall'utente. Alcune persone hanno ipotizzato che il meccanismo per controllare i provider attendibili sia debole e potrebbe essere soggetto ad attacchi. < - Sembra che questo sia falso. Questo per quanto riguarda le voci!
Aggiornamento: Harry Johnston ha sottolineato nei commenti che Windows 8.1 introduce servizi protetti, progettati per essere utilizzati da AV e DRM per proteggere il sistema da eventuali manipolazioni o attacchi da parte di codice con privilegi inferiori.
10. Manipolazione degli strumenti
Questo probabilmente è stato usato molto in natura, ma non l'ho mai visto fare correttamente. Essenzialmente questo trucco implica il targeting di strumenti specifici, ad es. Task Manager, modificando gli eseguibili su disco in un modo che altera la funzionalità. Questo è molto simile ai trucchi hook in modalità utente che ho menzionato prima, ma in questo caso persistono su disco e hanno conseguenze di più ampia portata rispetto al semplice hooking API. Naturalmente, un problema è che Windows File Protection (WFP) impedisce l'alterazione di alcuni file di sistema critici, incluso il task manager. In modo divertente, tuttavia, è possibile modificare il percorso eseguibile del task manager predefinito tramite il registro. Quindi, invece di scherzare con il file eseguibile del task manager, scarica la tua versione da qualche parte e fai in modo che il sistema operativo la utilizzi.
Tutto sommato, ci sono molti modi per ottenere questo risultato, con diversi gradi di robustezza. Quanto sopra ne rappresenta la maggioranza, ma non è esaustivo. In effetti, molti dei trucchi che ho descritto possono essere realizzati in modi alternativi, utilizzando diversi meccanismi o API per raggiungere lo stesso obiettivo.