Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Due modi per mappare una dll automaticamente in tutti i processi (o quasi)


Negli articoli sul Dll Injection e Code Injection sono state esposte delle procedure che consentono di mappare un dll nello spazio di memoria di un processo remoto. Spesso è utile mappare una determinata dll nello spazio di memoria di tutti i processi ("tutti" è un concetto relativo, va inteso come "la maggior parte possibile"). Chiaramente si può creare una procedura che enumera tutti i processi (ad esempio usando la Tool Help Library) e per ognuno di essi esegue la procedura di Injection. Bisogna però rilevare la creazione di nuovi processi ed eseguire l'Injection anche per essi. In questo articolo vengono esposte 2 tecniche per eseguire un mapping automatico della nostra dll.

1. Metodo 1: utilizzo della chiave di registro

Questa tecnica è sicuramente la più semplice e consente il mapping automatico della dll in questione in tutti i processi che caricano nel loro spazio di memoria la dll user32.dll. Di seguito un esempio

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows] "AppInit_DLLs"="carlo.dll,pino.dll,luisa.dll"

L'entry-point di user32.dll, tra le altre cose, va a leggere la chiave sopra definita e carica tutte le dll specificate nel valore AppInit_DLLs (elenco di nomi separato da virgola o anche semplice spazio).

Di seguito andiamo quindi ad analizzare le caratteristiche di questo tipo di automapping

  • La nostra dll viene mappata in automatico in tutte le applicazioni che hanno la user32 caricata nel proprio spazio di memoria; più nel dettaglio, il caricamento della nostra dll avviene nel codice dell'entry-point della user32. Una limitazione è data dal fatto che il mapping avviene solo per i processi che caricano user32, quindi il range dei processi interessati è limitato a questo tipo di processi (sugli altri processi non avviene il mapping) e al tempo stesso non si può definire un sottoinsieme di tali processi (il mapping avviene per ognuno di questi processi, non posso scartarne qualcuno).  

Tutto sommato, nonostante le osservazioni appena fatte, questa tecnica viene usata di frequente nella realizzazione di malware, quindi è sempre buona norma tenere sott'occhio questo valore nel registro.

2. Metodo 2: utilizzo degli Hook di sistema

Per fare in modo che una dll venga caricata in automatico nello spazio di memoria di tutti i processi (senza dover  costantemente monitorare la creazione di nuovi processi) si può ricorrere agli Hook di sistema. Per definizione un Hook è un punto, nel meccanismo di gestione messaggi di Windows, in cui un' applicazione può installare una procedura per monitorare il traffico dei messaggi ed eseguire determinate operazioni in corrispondenza di determinati messaggi prima che i medesimi vengano processati dalla Window Procedure della finestra alla quale sono destinati. Esistono vari tipi di Hook: ognuno interviene nel meccanismo di gestione di un determinato gruppo di messaggi di Windows. Facciamo un esempio di Keyboard Hook ossia di Hook che si inserisce nel meccanismo di gestione dei messaggi di Windows nell' ambito dei messaggi che riguardano la pressione dei tasti della tastiera:

unit HookUnit; interface uses Windows; var Hook: HHOOK; DllInstance: dword; HookProc: FARPROC; procedure SetHook; procedure RemoveHook; implementation procedure SetHook; begin DllInstance := LoadLibrary('HookDll.dll'); HookProc := GetProcAddress(DllInstance, 'HookProcedure'); Hook := SetWindowsHookEx(WH_KEYBOARD, HookProc, DllInstance, 0); end; procedure RemoveHook; begin UnhookWindowsHookEx(Hook); FreeLibrary(DllInstance); end; end.

library HookDll; uses Windows, SysInit; function HookProcedure(ncode: integer; wParam: WPARAM; lParam: LPARAM): integer; stdcall; var //dichiarazione ventuali variabili begin //implementazione //... //wParame lParam sono i corrispondenti parametri del messaggio (class TMsg nella unit Windows) //a cui fa riferimento l'hook //ed alla fine: Result := 0; Result := 0; end; procedure EntryPointProc(reason: integer); begin case reason of DLL_PROCESS_ATTACH: //1 begin DisableThreadLibraryCalls(HInstance); end; DLL_THREAD_ATTACH: //2 begin end; DLL_PROCESS_DETACH: //3 begin end; DLL_THREAD_DETACH: //0 begin end; end; end; exports HookProcedure; begin //codice di inizializzazione della dll DllProc := @EntryPointProc; DllProc(DLL_PROCESS_ATTACH); end.

In sostanza abbiamo definito una Unit ed una dll: nella Unit sono state definite le procedure di settaggio (SetHook) e rimozione (RemoveHook) di un Hook sulla tastiera (WH_KEYBOARD); focalizziamoci un attimo sull' ultimo parametro della funzione SetWindowsHookEx (che nell' esempio è stato settato a 0): quel parametro specifica l' identificativo del Thread su cui va settato l' hook; specificando l' identificativo di un thread, l' hook in questione si inserirà nel meccanismo di gestione dei messaggi di Windows relativamente a tutti i messaggi inviati alle finestre create da quel thread (naturalmente i messaggi di cui l' hook in questione si occupa, ad esempio la pressione dei tasti della tastiera nel caso dell' hook WH_KEYBOARD). Se invece metto semplicemente 0, l' hook interverrà in tutti i processi in esecuzione nello stesso Desktop del thread che ha eseguito l'api win32 SetWindowsHookEx (vedere al riguardo l'articolo WinstaDesktop che tratta i concetto di Desktop). Bene, una volta settato l' hook, ogni volta che una finestra qualsiasi (abbiamo appunto settato l' hook su tutti i thread nella SetWindowsHookEx) riceve un messaggio che rientra tra i messaggi di cui si occupa l' hook in questione (pressioni dei tasti della tastiera nell' esempio specifico), il thread che ha creato la finestra va a chiamare la funzione HookProcedure implementata nella dll HookDll. Chiaramente per chiamare una funzione implementata in una dll, il processo deve prima di tutto caricare la dll. Quindi è chiaro a questo punto che se vogliamo che una nostra dll venga mappata in automatico nello spazio di memoria di tutti i processi possiamo effettivamente settare un Hook di sistema. Inoltre HookPocedure a questo punto serve solo per consentire alla dll in cui è implementata di essere caricata dal processo e quindi deve essere una funzione dummy la cui implementazione consiste unicamante nella restituzione di un output pari a 0 (ad indicare l' esecuzione con successo in quanto la HookProcedure per definizione deve restituire 0). Inoltre bisogna far riferimento ad un Hook che riguardi il maggior numero di messaggi (in maniera tale da garantire il suo inserimento in ogni processo (e la conseguente mappatura della dll nello spazio di memoria del processo medesimo). Si può usare l' Hook WH_GETMESSAGE che monitorizza qualsiasi tipo di messaggio inserito nella coda dei messaggi di una finestra (PostMessage). La chiamata all' api UnHookWindowsHookEx comporta lo scaricamento della dll da tutti i processi in cui era stata caricata. Quindi concludendo si avrà

unit HookUnit; interface uses Windows; var Hook: HHOOK; DllInstance: dword; HookProc: FARPROC; procedure SetHook; procedure RemoveHook; implementation //chiamando questa procedura, HookDll.dll verrà mappata //nello spazio di memoria di tutti i processi (già esistenti e futuri) //in esecuzione nello stesso Dekstop del thread chiamante. Non appena //un processo in esecuzione nello stesso Desktop del thread chiamante //riceverà un messaggio qualsiasi tramite PostMessage (abbiamo infatti //specificato WH_GETMESSAGE), HookDll.dll verrà caricata nello spazio //di memoria del processo in questione. Chiaramente il messaggio sarà //ricevuto da una delle finestre del processo in questione, in quanto //i messaggi hanno come destinazione le finestre. procedure SetHook; begin DllInstance := LoadLibrary('HookDll.dll'); HookProc := GetProcAddress(DllInstance, 'HookProcedure'); Hook := SetWindowsHookEx(WH_GETMESSAGE, HookProc, DllInstance, 0); end; //chiamando questa procedura, HookDll.dll viene scaricata //dallo spazio di memoria di tutti i processi in esecuzione //nello stesso Desktop del thread chiamante e non si ha più //il mapping automatico procedure RemoveHook; begin UnhookWindowsHookEx(Hook); FreeLibrary(DllInstance); end; end.

Di seguito analizziamo i limiti di questa implementazione

  • i processi interessati sono quelli in esecuzione nello stesso Desktop in cui è in esecuzione il thread chiamante (ossia il thread che ha eseguito la chiamata all'api win32 SetWindowsHookEx). Lo scambio di messaggi avviene infatti a livello di Desktop, sorgente e destinatario di un messaggio rientrano nello stesso Desktop: quindi anche il concetto di Hook è relativo al singolo Desktop.
  • se un processo non ha finestre, tipo ad esempio una Console Application, chiaramente non riceverà mai messaggi e quindi sarà fuori dal mapping della dll. Chiaramente il fatto che un processo non abbia finestre visibili, non significa che non abbia finestre.
  • anche in questo caso, come nel precedente (ossia la voce di registro), non esiste una tecnica diretta per filtrare i processi in cui eseguire il mapping.

3. Filtro sui processi

Come ultima cosa, visto che nei paragrafi precedenti è stato sollevato il problema derivante dall'impossibilità di definire un sottoinsieme dei processi su cui mappare la dll, è opportuno dire che esiste un modo per decidere se eseguire o meno il mapping di una dll in relazione al processo destinazione. Consiste nell'andare a verificare il processo destinazione nell'entry-point della dll che vogliamo mappare. Di seguito un esempio:

library HookDll; uses Windows, SysInit; procedure EntryPointProc(reason: integer); var ProgName: array[0..260] of Char; begin case reason of DLL_PROCESS_ATTACH: //1 begin DisableThreadLibraryCalls(HInstance); GetModuleFileName(0, PAnsiChar(ProgName), SizeOf(ProgName)); //pseudocodice della condizione //if ProgName <> 'c:\windows\system32\notepad.exe' then // ExitCode = 1; //vado a settare la variabile ExitCode (dichiarata nella Unit System) //ad un valore diverso da 0, la dll viene scaricata dalla memoria end; DLL_THREAD_ATTACH: //2 begin end; DLL_PROCESS_DETACH: //3 begin end; DLL_THREAD_DETACH: //0 begin end; end; end; begin //codice di inizializzazione della dll DllProc := @EntryPointProc; DllProc(DLL_PROCESS_ATTACH); end.

In pratica verifico quale sia il processo in cui sto andando a mappare la mia dll (ottenendo il nome del .exe associato tramite l'api win32 GetModuleFileName) ed in caso che il processo in questione non sia notepad scarico la dll (settando la variabile ExitCode ad un valore diverso da 0).

 

 

 

 

 
 
Your Ad Here