Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Nascondere processi in Windows 2000/XP/2003 intercettando l' api nativa NtQuerySystemInformation


Nell' articolo articolo46.htm abbiamo visto come realizzare un sistema di intercettazione delle api di Windows coivolgendo tutti i processi: come esempio è stata utilizzata l' api DrawFocusRect che consente di definire il rettangolo del focus su pulsanti, elementi di una lista etc...: ogni pulsante od elemento di una lista, etc ... avrà un rettangolino rosso al posto del classico rettangolino grigio (questo in tutte le applicazioni). Per la realizzazione del pacchetto di intercettazione delle api di Windows mi sono servito dell' ottima implementazione in Delphi realizzata da Erik van Bilsen e disponibile all' url

www.thedelphimagazine.com, Issue 101, Jan

Si tratta del sorgente allegato alla rivista TheDelphiMagazine del Gennaio 2004.  Sono disponibili i sorgenti relativi alle varie tematiche trattate tra cui anche l' esempio di implementazione della tecnica di Detours. Bene, ora voglio intercettare un' altra api: l' api NtQuerySystemInformation. Questa api è una delle cosidette Native Api e consente di prelevare numerose informazioni relative al sistema (come spiega il nome stesso del resto) e tra queste anche l' elenco dei processi come si è già visto nell' articolo articolo44.htm. Il risultato della query sul sistema è una sequnza di byte puntata dal secondo parametro: in pratico il primo parametro della funzione specifica il tipo di informazione che vogliamo prelevare ed il secondo parametro punta al risultato dell' interrogazione. Bene ora il mio intento è intercettare questa api e nel caso in cui sia stata chiamata per enumerare i processi (ricordiamo: valore del primo parametro = SystemProcessesAndThreadsInformation) modificare il risultato consentendo di nascondere un determinato processo. Visto che questa è l'api a più basso livello che viene chiamata tutte le volte che qualsiasi applicazione decide di enumerare i processi, tale processo risulterà invisibile in tutti gli applicativi (Task Manager, Process Explorer, etc...). Come già visto in precedenza il risultato restituito da NtQuerySystemInformation nel caso in cui il primo parametro sia SystemProcessesAndThreadsInformation sarà una sequenza di blocchi di byte ognuno dei quali descrive le caratteristiche di un singolo processo: ognuno di questi blocchi può essere rapprentato dal record _SYSTEM_PROCESSES i primi 4 byte di ogni blocco (campo NextEntryDelta del record _SYSTEM_PROCESSES) rappresentano la distanza a cui si trova il blocco successivo a partire da quello corrente. Bene ... Quando ad un certo punto arriviamo al blocco corrispondente al processo che vogliamo nascondere, basta che modifichiamo il valore di NextEntryDelta del blocco precedente sommandogli il NextEntryDelta del blocco corrente (ossia quello che corrisponde al processo che vogliiamo nascondere): in questo modo il blocco procedente a quello che vogliamo nascondere punterà a quello successivo saltando quindi il blocco che vogliamo nascondere; nel corso dell' enumerazione dei blocchi, quello che vogliamo nascondere verrà effetivamente saltato. Riepilogando: la procedura che si dovrà sostituire ad NtQuerySystemInformation dovrà chiamare la funzione originale e sul risultato così ottenuto (2° parametro della funzione NtQuerySystemInformation) dovrà effettuare la sostituzione appena descritta. Di seguito l' implementazione della funzione

 

function DetourNtQuerySystemInformation(SystemInformationClass: SYSTEM_INFORMATION_CLASS; SystemInformation: PVOID; SystemInformationLength: ULONG; ReturnLength: PULONG ): NTSTATUS; stdcall; var i,rl,cp : dword; pinfo : PSystemProcesses; pinfo_prec: PSystemProcesses; buf : Pointer; dim: dword; begin Result := TrampolineNtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); if SystemInformationClass <> SystemProcessesAndThreadsInformation then exit; if Result = 0 then begin cp := 0; pinfo_prec := nil; repeat pinfo := PSystemProcesses(Pointer(dword(SystemInformation) + cp)); with pinfo^ do begin if (ProcessName.Buffer <> nil) then begin if LowerCase(WideCharToString(ProcessName.Buffer)) = 'notepad.exe' then begin if pinfo.NextEntryDelta = 0 then //siamo all' ultimo elemento begin if pinfo_prec <> nil then pinfo_prec.NextEntryDelta := 0; Exit; end else //siamo su un elemento interno qualsiasi begin pinfo_prec.NextEntryDelta := pinfo_prec.NextEntryDelta + pinfo.NextEntryDelta; end; end else begin pinfo_prec := pinfo; end; end end; cp := cp + pinfo.NextEntryDelta; until (pinfo.NextEntryDelta = 0); end; end;

Nell' esempio ho specificato notepad.exe come eseguibile da nascondere. Nel caso in cui si voglia nascondere il processo corrente si potrebbe usare il PID (pinfo^.ProcessId) e confrontarlo con il PID del processo corrente (GetCurrentProcessId).

A questo punto però ho riscontrato un problema: quando lancio il Task Manager, i 2 tab "Prestazioni" e "Rete" non visualizzano nulla ed anche l' elenco dei processi e soggetto ad un visibile lampeggio costante. Analizzo un pò la situazione e verifico che si tratta di un fenomo che avviene solo quando il Task Manager viene aperto dopo che ho settato l' intercettazione dell' api; allora decido di rendere il caso della creazione del processo taskmgr.exe un caso particolare: la procedura che viene seguita quando si rileva una chiamata a CreateProcess è la seguente:

creo il processo in forma "suspended" in maniera tale che il thread primario non esegua nulla
inietto la dll nel processo
risveglio il thread primario del processo con un ResumeThread

nel caso di taskmgr.exe farò esattamente il contrario e cioè:

creo il processo
attendo che abbia terminato la sua inizializzazione con un WaitForInputHandle
inietto la dll

il sorgente delle 2 funzioni che sostituiscono le 2 CreateProcess diventerà

 

function DetourCreateProcessA(lpApplicationName: PAnsiChar; lpCommandLine: PAnsiChar; lpProcessAttributes, lpThreadAttributes: PSecurityAttributes; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: PAnsiChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation ): BOOL; stdcall; begin if Pos('taskmgr.exe', LowerCase(lpCommandLine)) <> 0 then begin //creo il processo ed attendo che abbia terminato la sua inizializzazione //tramite la WaitForInputIdle TrampolineCreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); WaitForInputIdle(lpProcessInformation.hProcess, INFINITE); InjectDll(lpProcessInformation.dwProcessId, NomeDll); end else begin //creo il processo tenendo sospeso il suo thread primario in maniera che non esegua nulla TrampolineCreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags + CREATE_SUSPENDED, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); InjectDll(lpProcessInformation.dwProcessId, NomeDll); ResumeThread(lpProcessInformation.hThread); end; end; function DetourCreateProcessW(lpApplicationName: PWideChar; lpCommandLine: PWideChar; lpProcessAttributes, lpThreadAttributes: PSecurityAttributes; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation ): BOOL; stdcall; begin if Pos('taskmgr.exe', LowerCase(WideCharToString(lpCommandLine))) <> 0 then begin //creo il processo ed attendo che abbia terminato la sua inizializzazione //tramite la WaitForInputIdle TrampolineCreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); WaitForInputIdle(lpProcessInformation.hProcess, INFINITE); InjectDll(lpProcessInformation.dwProcessId, NomeDll); end else begin //creo il processo tenendo sospeso il suo thread primario in maniera che non esegua nulla TrampolineCreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags + CREATE_SUSPENDED, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation ); InjectDll(lpProcessInformation.dwProcessId, NomeDll); ResumeThread(lpProcessInformation.hThread); end; end;

 

Sorgenti

 

 

 
 
Your Ad Here