La DLL Injection è una delle tecniche più utilizzate dai malware per iniettare codice malevolo in uno o più processi in esecuzione. Questa metodologia si basa su una serie di step ben definiti, sfruttando le Windows API per ottenere il controllo del processo target e caricare una DLL dannosa.
Differenza tra DLL Injection e DLL Hijacking
La differenza tra DLL Injection e DLL Hijacking risiede nei metodi e negli obiettivi per sfruttare le DLL, pur avendo entrambi come scopo il caricamento di codice malevolo in un processo legittimo.
La DLL Injection è una tecnica attiva in cui un codice malevolo viene iniettato direttamente in un processo in esecuzione. L’obiettivo è far eseguire una DLL malevola nel contesto del processo target, manipolando il suo comportamento o raccogliendo dati sensibili. Richiede un’interazione diretta con il processo target, ad esempio usando funzioni legittime delle Windows API per allocare memoria, scrivere il percorso della DLL e creare un thread per eseguire il codice malevolo.
La DLL Hijacking, invece, è una tecnica passiva che sfrutta la vulnerabilità di ricerca delle DLL in un’applicazione. Se un’applicazione cerca una DLL mancante o errata, un attaccante può fornire una DLL malevola con lo stesso nome, che verrà caricata dall’applicazione.
Differenze principali
| Caratteristica | DLL Injection | DLL Hijacking |
| Metodo | Iniezione attiva sul processo target | Manipolazione dell’ordine di ricerca delle DLL |
| Richiede il controllo del processo target? | Sì | No |
| Obiettivo primario | Modifica del comportamento di un processo attivo | Ingannare un’applicazione per caricare una DLL malevola |
| Contesto di utilizzo | Attacchi runtime | Attacchi persistenti o su software vulnerabile |
Di seguito illustreremo i vari step utilizzati per fare DLL injection:
STEP 1: Identificazione del Processo Target
Il malware deve identificare un processo nel quale iniettare la DLL dannosa. Per raggiungere tale scopo sfrutta alcune funzioni delle Windows API, generando uno snapshot del processo e raccogliere informazioni da esso.
Funzione utilizzata per la creazione dello Snapshot del processo target:
CreateToolhelp32Snapshot(): Esegue un’istantanea (snapshot) dei processi specificati, nonché degli heap, dei moduli e dei thread utilizzati da tali processi. L’accesso allo snapshot è di sola lettura.
Sintassi della funzione in C++:
HANDLE CreateToolhelp32Snapshot( [in] DWORD dwFlags, [in] DWORD th32ProcessID );
Parametri:
- dwFlags specifica i tipi di informazioni da includere nello snapshot (ad esempio processi, thread, heap, moduli.
- th32ProcessID corrisponde all’ID del processo su cui si desidera avere lo snapshot, per ottenere informazioni su tutti i processi, questo valore può essere impostato su 0.
Se la funzione va a buon fine, restituisce un handle allo snapshot.
Per estrapolare le informazioni dallo snapshot, utili ad individuare il processo adatto per il DLL Injection, si usano le seguenti funzioni Windows API:
Process32First(): Recupera informazioni sul primo processo riscontrato in uno snapshot.
Sintassi della funzione in C++:
BOOL Process32First( [in] HANDLE hSnapshot, [in, out] LPPROCESSENTRY32 lppe );
Parametri:
- hSnapshot rappresenta l’handle per lo snapshot restituito dalla precedente chiamata alla funzione CreateToolhelp32Snapshot.
- lppe rappresenta un puntatore a alla struttura PROCESSENTRY32, la quale contiene informazioni sul processo come: il nome del file eseguibile, l’identificativo del processo e l’identificativo del processo padre. Di seguito riportiamo le informazioni raccolte da PROCESSENTRY32:
typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
CHAR szExeFile[MAX_PATH];
} PROCESSENTRY32;
Per recuperare informazioni su altri processi registrati nello stesso snapshot, utilizzare la funzione Process32Next.
Process32Next(): Recupera informazioni sul processo successivo registrato in uno snapshot del sistema.
Sintassi della funzione in C++:
BOOL Process32Next( [in] HANDLE hSnapshot, [out] LPPROCESSENTRY32 lppe );
Parametri:
- hSnapshot rappresenta l’handle per lo snapshot restituito dalla precedente chiamata alla funzione CreateToolhelp32Snapshot.
- lppe rappresenta un puntatore a alla struttura PROCESSENTRY32
Queste due funzioni (Process32First e Process32Next ) vengono utilizzate in un ciclo per esplorare tutti i processi nello snapshot, confrontando i dati con i criteri di selezione del malware (ad esempio, il nome del processo o il PID).
Step 2: Accesso del Processo Target
Una volta identificato il processo target, il malware deve aprirlo per effettuare operazioni su di esso.
Di seguito riportiamo le funzioni utilizzate per tale scopo:
OpenProcess(): usata per ottenere un handle su un processo specifico, permettendo operazioni come la lettura/scrittura di memoria.
Sintassi della funzione in C++:
HANDLE OpenProcess([in] DWORD dwDesiredAccess, [in] BOOL bInheritHandle, [in] DWORD dwProcessId);
Parametri:
- dwDesiredAccess: Specifica i permessi desiderati (ad esempio PROCESS_ALL_ACCESS).
- bInheritHandle: Indica se l’handle è ereditabile.
- dwProcessId: ID del processo da aprire.
GetModuleHandle(): Recupera un handle a un modulo (DLL o EXE) già caricato nello spazio di memoria del processo chiamante.
Sintassi della funzione in C++:
HMODULE GetModuleHandle(LPCSTR lpModuleName);
GetProcAddress(): Recupera l’indirizzo di una funzione esportata da un modulo.
Sintassi della funzione in C++:
FARPROC GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
STEP 3: Allocazione della Memoria nel Processo Target
Dopo aver ottenuto l’accesso, il malware deve individuare un’area di memoria all’interno del processo target dove scrivere il percorso della DLL malevola.
Per tale scopo utilizza la seguente funzione:
VirtualAllocEx(): Tale funzione alloca memoria nello spazio di un processo specifico.
Sintassi della funzione in C++:
LPVOID VirtualAllocEx( [in] HANDLE hProcess, [in, optional] LPVOID lpAddress, [in] SIZE_T dwSize, [in] DWORD flAllocationType, [in] DWORD flProtect );
Parametri:
- hProcess: rappresenta l’handle del processo target.
- dwSize: dimensione della memoria da allocare (sufficiente per contenere il percorso della DLL).dwProcessId: ID del processo da aprire.
- flAllocationType: Tipo di allocazione (ad esempio MEM_COMMIT).
- flProtect: Protezione della memoria (ad esempio PAGE_READWRITE).
STEP 4: Scrittura del Percorso della DLL
Il malware scrive il percorso della DLL malevola nell’area di memoria precedentemente allocata nel processo target.
Per tale scopo utilizza la seguente funzione:
WriteProcessMemory(): Scrive dati in un’area di memoria di un processo specifico.
LPVOID VirtualAllocEx( [in] HANDLE hProcess, [in, optional] LPVOID lpAddress, [in] SIZE_T dwSize, [in] DWORD flAllocationType, [in] DWORD flProtect );
STEP 5: Esecuzione della DLL Malevola
Per completare il processo di iniezione, il malware avvia un thread remoto nel processo target, caricando la DLL. Per tale scopo esistono varie funzioni alcune dei quali non sono documentate:
Funzioni Documentate:
CreateRemoteThread(): crea un nuovo thread remoto che esegue il codice in un modulo specifico.
HANDLE CreateRemoteThread( [in] HANDLE hProcess, [in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes, [in] SIZE_T dwStackSize, [in] LPTHREAD_START_ROUTINE lpStartAddress, [in, optional] LPVOID lpParameter, [in] DWORD dwCreationFlags, [out, optional] LPDWORD lpThreadId);
Parametri:
- lpStartAddress: Indirizzo della funzione da eseguire (ad esempio LoadLibrary).
- lpParameter: Parametro passato alla funzione (percorso della DLL).
LoadLibrary(): Carica una DLL in un processo.
È importante sottolineare che la funzione delle Windows API CreateRemoteThread() non è l’unica che può essere utilizzata per iniettare codice. Esistono anche altre funzioni che possono essere sfruttate per scopi simili, aumentando le possibilità per il malware di bypassare i controlli di sicurezza.
Funzioni Non Documentate:
NtCreateThreadEx(): Alternativa avanzata a CreateRemoteThread, caricata manualmente da Ntdll.dll.
RtlCreateUserThread(): Utilizzata da strumenti avanzati per il controllo dei processi, come Mimikatz e Metasploit.
L’uso di queste funzioni non documentate consente al malware di aggirare le tecniche di rilevamento basate su comportamenti noti delle API documentate.
Per far funzionare questa tecnica, il percorso della DLL malevola deve risiedere sul disco. Tuttavia, esiste una tecnica più discreta: la Reflective DLL Injection, che carica la DLL direttamente in memoria senza scriverla sul disco.
Conclusioni
Ogni step della DLL Injection sfrutta funzionalità legittime delle Windows API, rendendo questa tecnica particolarmente difficile da rilevare. La comprensione di queste procedure è fondamentale per lo sviluppo di contromisure efficaci, come l’analisi comportamentale e il monitoraggio delle chiamate API.
Speriamo che questo cyber tuffo ti abbia aiutato a comprendere un pochino meglio il funzionamento dei tuoi malware preferiti!






