Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Intercettazione delle api di Windows con la tecnica di Detours, monitoraggio della creazione di processi a livello di tutto il sistema, etc...


Negli articoli precedenti ho parlato di intercettazione delle api di Windows ed ho utilizzato il componente TJclPeMapImgHooks che fa parte della Jedi Code Library (JCL) scaricabile liberamente all' indirizzo www.delphi-jedi.org. Quel componente utilizza della tecnica di patch della tabella IAT (Import Address Table) per consentire di sostituire una funzione con una versione propria. Gli esempi allegati trattano l' intercettazione di api nel contesto del processo corrente; ho esteso l' intercettazione delle api a tutti i processi utilizzando gli hook di sistema; bene .... ora voglio utilizzare un' altra tecnica per l' intercettazione delle api ed un altra tecnica per l' applicazione del codice di intercettazione a tutti i processi presenti e futuri. Infatti bisogna dire che patchando la tabella IAT posso intercettare tutte le funzione implementate in librerie caricate staticamente; se però un dato programma chiama una funzione implementata in una dll caricando dinamicamente la dll stessa (LoadLibrary della dll seguito da GetProcAddress per la determinazione dell' indirizzo della funzione) in questo caso allora questa funzione non la riesco ad intercettare. Una tecnica molto valida per l' intercettazione delle api di Windows è la tecnica di Detours: andando all' indirizzo

http://research.microsoft.com/sn/detours/

si può scaricare il pacchetto comprensivo di sorgenti della libreria, esempi e un pò di documentazione. Questa tecnica consiste nel mettere come prima istruzione della funzione che si vuole intercettare un jump incondizionato alla funzione che ho preparato e che deve essere chiamata nel momento in cui il programma chima quella da intercettare. In breve chiameremo FunzioneOriginale la funzione che si vuole intercettare e FunzioneSostitutiva la funzione che ci siamo creati noi e che dovrà essere chiamata al posto dell' originale. Se metto come prima istruzione della FunzioneOriginale l' istruzione jmp <Displacement>, quando il programma chiama la FunzioneOriginale, esso esegue un salto incondizionato all' indirizzo che dista <Displacement> dall' indirizzo immediatamente successivo all' instruzione jmp <Displacement>. jmp è 1 byte (codice E9 in esadecimale) mentre <Displacement> rappresenta una distanza ed è espresso tramite 4 byte: complessivamente l' istruzione jmp <Displacement> sono 5 byte. Per fare in modo che venga chiamata FunzioneSostitutiva quando viene chiamata FunzioneOriginale, il salto incondizionato che eseguo come prima istruzione di FunzioneOriginale, mi deve portare all' indirizzo di FunzioneSostitutiva e quindi <Displacement> sarà dato da

@FunzioneSostitutiva - (@FunzioneOriginale + 4)  

dove il simbolo @ rappresenta l' indirizzo della funzione a cui è collegato (come in Delphi).

A questo punto quando il programma chiama FunzioneOriginale, verrà chiamata FunzioneSostitutiva. Bene... io voglio intercettare e non sostitire totalmente: in sostanza la FunzioneSostitutiva deve essere in grado di chiamare FunzioneOriginale coì come era implementata in principio; è in questo contesto che entra in gioco la "funzione trampolino" che chiameremo "FunzioneTrampolino": in pratica devo vedere quali sono le istruzioni della FunzioneOriginale che rientrano nel primi 5 byte della medesima (byte che vengono sovrascritti appunto dal jmp <Displacement>) e farle diventare le prime istruzioni della FunzioneTrampolino: subito dopo queste istruzioni, andrò ad inserire nella FunzionTrampolino un jump incondizionato all' istruzione immediatamente successiva nella FunzioneOriginale. In questo modo la FunzioneTrampolino ricostruisce alla perfezione la FunzioneOriginale: infatti contiene le istruzioni che vengono sovrascritte dal jmp <Displacement> e subito dopo un jump incondizionato (una istruzione sempre del tipo jmp <Displacement>) alla istruzione immediatamente successiva nella FunzioneOriginale. La FunzioneSostituitiva nella sua implementazione ad un certo punto chiamerà la FunzioneTrampolino preservano quindi il funzionamento della FunzioneOriginale: ad esempio se voglio semplicemente monitorare la chiamate alla FunzioneOriginale, la FunzioneSostitutiva mi invierà un messaggio in cui si comunica la chiamata della FunzioneOriginale e poi subito dopo chiamerà la FunzioneTrampolino. Messa in questi termini non sembra poi così complessa: invece la complessità viene fuori nel momento in cui si decide di realizzarne una implementazione corretta in tutte le circostanza. La prima cosa importante da osservare è che le istruzioni della FunzioneOriginale che rientrano nei primi 5 byte non necessariamente rientrano esattamente nei 5 byte: bisogna quindi disporre di un disassemblatore che ci consenta di vedere quali sono le istruzioni coinvolte nei primi 5 byte. L' implementazione ufficiale della tecnica dispone di procedure per il riconoscimento automatico delle istruzioni coinvolte nei primi 5 byte, raccogliendo tutti i tipi di comandi assembler ... e poi altre rifiniture. Spulciando un pò nella rete alla ricerca di una implementazione Delphi di questa tecnica, ho visto che sul sito www.thedelphimagazine.com (una delle mie mete preferite) vengono resi disponibili per il download i codici sorgenti allegati ogni mese alla rivista. Nel numero 101 (Gennaio 2004) vi è una eccellente implementazione realizzata da Erik van Bilsen: è una classe Delphi molto ben realizzata che contiene tutto quello che viene esposto nella implementazione originale sul sito Microsoft (compreso appunto il riconoscimento automatico delle istruzioni nei primi 5 byte della FunzioeOriginale). Allora mi sono messo un pò a giocare partendo dall' esempio allegato. Anche in questo caso l' intercettazione viene realizzata nell' ambito del processo corrente e mi sono detto :"si certo Carlo questo codice non l' hai realizzato tu ... ma in ogni caso puoi realizzare il modulo che consenta l' applicazione del codice a tutti i processi realizzando un intercettazione a livello di sistema (e non solo a livello di processo corrente). Bene: un hook di sistema e tutto a posto come nella situazione precedente ... uhhh che bello si intercettano le api a livello di tutti i processi. Si ... però ho fatto troppo poco per meritarmi qualcosina ed allora vado un pò più in profondità ... guarda caso se apro cmd.exe le api non vengono intercettate: dunqueeeee ... si il fatto è che cmd.exe non ha associata una coda dei messaggi e quindi l' hook di sistema (che appunto interviene nel contesto del sistema di messaggistica) qui non ha alcun effetto e la dll contenente il codice per l' intercettazione non viene mappata nello spazio di memoria di cmd.exe. Ok allora devo mapparla direttamente tramite CreateRemoteThread (guarda un pò di articoli precedenti che ne ho parlato talmente a stufo che ciò la nausea).Bene bene .... quindi se vogliamo coinvolgere tutti i processi dobbiamo dimenticarci degli hook di sistema (che tra l' altro poi oltre ad essere innocui con cmd.exe non fanno nulla nemmeno coi processi tipo winlogon.exe, etc...). Possiamo enumerare tutti i processi e per ognuno di essi mappare la dll col codice di intercettazione: bene detto fatto:

 

procedure ModificaPrivilegio(szPrivilege: pChar; fEnable: Boolean); var NewState: TTokenPrivileges; luid: TLargeInteger; hToken: THandle; ReturnLength: DWord; begin //apro il token di accesso asociato al processo corrente (il cui handle //è ottenuto tramite GetCurrentProcess. Specifico TOKEN_ADJUST_PRIVILEGES //come tipo di accesso al Token: in questa maniera sono in grado di abilitare //e/o disabilitare Privilegi. hToken è l' handle del token di accesso appena //aperto. OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken); //ricavo il LUID (Locally Unique Identifier) corrispondente al privilegio //specificato: si tratta in sostanza di un identificativo univoco del privilegio; //varia da sessione a sessione ed anche tra un riavvio e l' altro del sistema LookupPrivilegeValue(nil, szPrivilege, luid); //lavoro su NewState (di tipo TTokenPrivileges). Rappresenta un elenco di privilegi; //nel caso specifico conterrà un solo privilegio (ProvilegeCount = 1). L' arrary //Privileges contiene oggetti con 2 campi: il luid del privilegio (Luid) ed //il livello di abilitazione del medesimo (Attributes) NewState.PrivilegeCount := 1; NewState.Privileges[0].Luid := luid; if fEnable then //abilitiamo il privilegio NewState.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED else //disabilitiamo il privilegio NewState.Privileges[0].Attributes := 0; //eseguiamo la modifica sullo stato di abilitazione del privilegio //nel contesto del token di accesso aperto AdjustTokenPrivileges( hToken, FALSE, NewState, sizeof(NewState), nil, ReturnLength); //chiudo l' handle al token di accesso aperto CloseHandle(hToken); end; function PidProcesso(NomeProcesso: string): LongWord; var pe: TProcessEntry32; hSnap: THandle; begin Result := 0; hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); pe.dwSize := sizeof(TProcessEntry32); //Prelevo informazioni sul primo processo nello snapshot di sistema Process32First(hSnap, pe); repeat //loop sui processi Result := pe.th32ProcessID; if (LowerCase(pe.szExeFile) = LowerCase(NomeProcesso)) then begin break; end; until (not (Process32Next(hSnap, pe)) ) ; CloseHandle(hSnap); end; function BaseAddrDllProcesso(PID: LongWord; NomeDll: string): PByte; var me: TModuleEntry32; hSnap: THandle; begin Result := 0; hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); me.dwSize := sizeof(TModuleEntry32); //Prelevo informazioni sul primo modulo del processo in questione Module32First(hSnap, me); repeat //loop sui moduli if LowerCase(me.szModule) = LowerCase(NomeDll) then begin result := me.modBaseAddr; break; end; until (not (Module32Next(hSnap, me))); CloseHandle(hSnap); end; function InjectDll(PID: dword; DLL: pChar): LongWord; var BytesWritten, Process, Thread, ThreadId: dword; Paramaters: pointer; begin Result := 0; if DLL = nil then Exit; //conferisco, al processo che chiama la funzione, il privilegio //di debug ModificaPrivilegio('SeDebugPrivilege', TRUE); //ottengo un handle al processo destinazione (identificato da PID); //specifico come valore del primo parametro della OpenProcess un elenco //di privilegi di accesso al processo in questione tali da consentirmi //le operazioni che andrò ad eseguire di seguito. Basta consultare il Platform //SDK e cercare le funzioni successive per vedere con quali diritti di accesso //un processo debba essere aperto per consentire appunto l' esecuzione di //ciascuna di esse Process := OpenProcess(PROCESS_CREATE_THREAD + PROCESS_QUERY_INFORMATION + PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, PID ); //vado ad allocare della memoria nello spazio di memoria del processo destinazione //(identificato dall' handle Process). Tale fetta di memoria deve contenere una //stringa che definisce il nome della dll che si vuole mappare (comprensivo di //percorso completo). Quindi la sua dimensione sarà data da Length(DLL). Mi //viene restituito (Paramaters) l' indirizzo (nel contesto del processo destinazione) //a partire dal quale è presente tale area di memoria Paramaters := VirtualAllocEx( Process, nil, Length(DLL), MEM_COMMIT, PAGE_READWRITE); //vado a scrivere nella fetta di memoria (appena allocata nel processo //destinazione tramite VirtualAllocEx) la stringa che definisce il nome della //dll da mappare (comprensivo di percorso completo). Gli passerò l' handle //del processo destinazione (Process, ottenuto tramite OpenProcess), l' indirizzo //di partenza dell' area di memoria allocata per inserirvi il nome della dll da //mappare (Paramaters, ottenuto tramite VirtualAllocEx), l' indirizzo a partire //da quale è memorizzato il nome della dll nel contesto del processo corrente //(Pointer(DLL)), la dimensione dei dati da copiare (Lenght(DLL)) WriteProcessMemory(Process, Paramaters, Pointer(DLL), Length(DLL), BytesWritten); //Bene, ora che ho copiato il nome della dll nello spazio di memoria del processo //remoto, posso creare un thread nel processo remoto: tale thread consiste //nell' esecuzione di LoadLibraryA passando come parametro il nome della dll: //in parole povere il caricamento della dll nello spazio di memeoria del processo //remoto. Il parametri fondamentali sono: l' handle del processor remoto (Process, //ottenuto tramite OpenProcess), l' indirizzo a partire dal quale è implementata //l' api LoadLibraryA (il 4° parametro), l' indirizzo a partire dal quale è //memrizzato il nome della dll comprensivo di percorso completo (Paramaters). //Da notare che quando si parla di indirizzo di una funzione da invocare nel //contesto di un processo remoto (nel caso specifico l' api LoadLibraryA) si parla //di indirizzo nello spazio di memoria del processo remoto; il 4° parametro della //CreateRemoteThread è l' indirizzo dell' api LoadLibraryA nel contesto del processo //corrente e di conseguenza nasce il dubbio sulla validità; il linea di massima una dll //non viene sempre caricata allo stesso indirizzo nel' ambito di un processo e di //conseguenza anche l' indirizzo delle funzioni esportate dalla dll medesima può //variare di volta in volta (in quanto è soggetto a variazione l' indirizzo di base //di caricamento di una dll nello spazio di memoria di un processo). Tuttavia la dll //kernel32.dll fa eccezione in quanto viene caricata sempre allo stesso indirizzo. Più //precisamente tutte le dll hanno un indirizzo di preferenza a partire dal quale possono //essere caricate ma sono soggette alla cosidetta rilocazione (variazione sull' indirizzo //base di caricamento rispetto al valore desiderato) in relazione al contesto. La dll //kernel32.dll non è soggetta ad alcuna rilocazione. Se si provasse a forzare il suo //caricamento in altri indirizzi si otterrebbe immediatamente un errore irreversibile Thread := CreateRemoteThread(Process, nil, 0, GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'LoadLibraryA'), Paramaters, 0, ThreadId); //mi metto in attesa della terminazione del Thread innescato nel processo remoto //tramite CreateRemoteThread. L' handle del Thread è stato restituito dalla //CreateRemoteThread. Non ci sono interruzioni all' attesa diverse dalla terminazione //del thread medesimo (time out infinito: secondo parametro è INFINITE) WaitForSingleObject(Thread, INFINITE); //una volta terminato il thread remoto copio come output della funzione DllInject //il codice di uscita del thread in questione: si tratta del codice di uscita della //funzione che mi ha definito il thread ossia LoadLibraryA e quindi altro non è il //valore restituito da LoadLibraryA ossia l' handle della dll caricata. GetExitCodeThread(Thread, Result); //libero la memoria allocata nel processo remoto (che contiene il nome della DLL) //come parametri avrò naturalmente l' handle del processo remoto (Process, ottenuto //tramite OpenProcess) e Paramaters che è appunto l' indirizzo (nel contesto del //processo remoto) a partire dal quale è memorizzato il nome della Dll VirtualFreeEx(Process, Paramaters, 0, MEM_RELEASE); //chiudo gli handle al processo remoto (Process) ed al thread creato nel processo //remoto (Thread) CloseHandle(Thread); CloseHandle(Process); end; procedure UninjectDll(PID: dword; BaseAddrDLL: PByte); var BytesWritten, Process, Thread, ThreadId: dword; Paramaters: pointer; begin //ablito il privilegio di debug ModificaPrivilegio('SeDebugPrivilege', TRUE); //apro il processo remoto Process := OpenProcess(PROCESS_CREATE_THREAD + PROCESS_QUERY_INFORMATION + PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, PID ); //creo ed eseguo un thread nel processo remoto. A differenza della InjectDll, //in questo caso non abbiamo bisogno di copiare l' argomento di input della //funzione che mi definisce l' esecuzione del thread (in questo caso FreeLibrary, //nel caso precedente LoadLibraryA) in quanto il valore restituito da BaseAddrDll //è già un indirizzo valido nel contesto del processo remoto; non c' è quindi più //bisogno di allocare memoria (VirtualAllocEx), scrivere nella memoria allocata //(WriteProcessMemory) e deallocare la memoria (VirtualFreeEx) Thread := CreateRemoteThread(Process, nil, 0, GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'FreeLibrary'), BaseAddrDLL, 0, ThreadId); //mi metto in attesa della terminazione del thread remoto (che consiste appunto in //una FreeLibrary sulla dll precedentemente mappata con DllInject WaitForSingleObject(Thread, INFINITE); //chiudo gli handle al processo remoto (Process) ed al thread creato nell' ambito //del processo remoto (Thread) CloseHandle(Thread); CloseHandle(Process); end; procedure InjectDllAllProcesses(DLL: pChar); var pe: TProcessEntry32; hSnap: THandle; begin hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); pe.dwSize := sizeof(TProcessEntry32); //Prelevo informazioni sul primo processo nello snapshot di sistema Process32First(hSnap, pe); repeat //loop sui processi InjectDll(pe.th32ProcessID, DLL); until (not (Process32Next(hSnap, pe)) ) ; CloseHandle(hSnap); end; procedure UnInjectDllAllProcesses(DLL: pChar); var pe: TProcessEntry32; hSnap: THandle; DllHandle: DWORD; dll_base_addr: PByte; begin hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); pe.dwSize := sizeof(TProcessEntry32); //Prelevo informazioni sul primo processo nello snapshot di sistema Process32First(hSnap, pe); repeat //loop sui processi dll_base_addr := BaseAddrDllProcesso(pe.th32ProcessId, Dll); if dword(dll_base_addr) <> 0 then UnInjectDll(pe.th32ProcessID, dll_base_addr); until (not (Process32Next(hSnap, pe)) ) ; CloseHandle(hSnap); end;

Ok ...  tanto bel codice ben commentato: InjectDllAllProcesses e UnijectDllAllprocesse ... siiii sono loro 2 le funzioni che ci consentono di mappare la nostra dll magica in tutti i processi e per contro di scaricarla da tutti i processi. Non mi dilungherei troppo anche perchè sennò facciamo notte (no anzi qui è già notte ... o meglio mezzanotte). Ora pensiamo un attimo: è tutto a posto???? Neanche per sogno in quanto dobbiamo fare in modo che tale dll venga mappata anche in tutti i processi che verranno creati in futuro: dobbiamo quindi intercettare la creazione di nuovi processi e mappare la dll in ognuno di essi. Utilizzeremo quindi sempre la classe DELPHI che implementa la tecnica di Detours per intercettare l' api CreateProcess. La funzione che si sostituisce a CreateProcess (o meglio le 2 funzioni che si sostituiscono rispettivamente a CreateProcessA e CreateProcessW) dovranno eseguire il CreateProcess originale e poi mappare la dll nello spazio di memoria del processo creato. Una volta creato, il processo (o meglio il thread primario del processo) può chiamare delle api che io voglio intercettare o anche creare a sua volta un altro processo: tutte queste operazioni potrebbero avvenire prima che la nostra dll sia stata effettivamente mappata perdendoci quindi qualcosa di bello che è successo nel frattempo; è opportuno quindi che il processo venga creato in forma SUSPENDED: in questo modo il thread primario non eseguirà nulla; vado quindi a mappare la dll nello spazio di memoria del processo e riattivo il processo con un ResumeThread passandogli come input l' handle del thread primario. Sia il PID del nuovo processo (necessario per mappare la dll nel suo spazio di memoria tramite la funzione InjectDll) sia l' handle del suo thread primario (necessario per risvegliare il processo dallo stato SUSPENDED tramite l' api ResumeThread) sono campi dell' ultimo parametro dell' api CreateProcess (che è appunto l' output della CreateProcess): rispettivamente lpProcessInformation.dwProcessId e lpProcessInformation.hThread. Ricapitoliamo quindi un attimo: mappiamo la dll in tutti i processi attivi; la dll consente l' intercettazione della CreateProcess e quindi la creazione di processi figli: ogni volta che un processo crea un processo figlio la dll viene mappata automaticamente nello spazio di memoria del processo figlio (è quello che succede nell' implementazione della funzione che si va a sostituire alla CreateProcess originale); in questo modo ricorsivamente i processi figli mapperanno in automatico tale dll in tutti i processi loro figli e così via. Ho quindi sotto controllo la creazione di ogni processo. A questo punto l' unico neo è la definizione del percorso completo della dll nella funzione InjectDll: scrivere il percorso completo non è elegante perchè tutte le volte che sposto il programma o la dll lo devo ridefinire; potrei mettere la dll nella cartella di sistema solo che anche quello è un vincolo in sè: la soluzione migliore è scrivere il percorso completo della dll in un File Mappato In Memoria (in maniera che sia accessibile nel contesto di tutti i processi): l' eseguibile, prima di eseguire il mapping iniziale su tutti i processi, scrive il nome della dll (comprensivo di percorso completo) nel File Mappato in Memoria; nell' entrypoint di ogni dll ci sarà la lettura dell' informazione; in pratica l' eseguibile crea il file mappato in memoria (CreateFileMapping) ne ottiene una copia in scrittura nel proprio spazio di memoria (MapViewOfFile) e ci scrive la stringa (MapViewOfFile restituisce un puntatore che può essere usato come qualsiasi puntatore e quindi scrivere sul file mappato in memoria equivale ad eseguire l' assegnazione di una stringa). Ogni dll aprirà il File mappato in memoria (OpenFileMapping), ne otterrà una copia in lettura nel proprio spazio di memoria e va a leggere la stringa che specifica il nome della dll comprensivo di percorso completo. Un' ultima cosa: l' esempio che vado a riportare ridefinisce il funzionamento dell' api DrawFocusRect a livello di sistema e ci troveremo quindi con il rettangolino del focus (su pulsanti elementi di una lista etc...) di color rosso. Dato che c' ero ho deciso di inviare anche un messaggio a video ogni volta che viene generato un nuovo processo consentendo l' esecuzione o meno del medesimo per verificare appunto la validità della procedura di intercettazione dell' api CreateProcess. E' importante notare che la dll viene mappata in tutti i processi: i processi come ad esempio winlogon.exe appartengono ad una winstation differente dalla winstation in cui vediamo eseguire i nostri programmini e quindi una MessageBox eseguita da quei processi blocca tutto il sistema in quanto non è visibile e non si riesce quindi a chiuderla. E' opportuno quindi usare l' api WTSSendMessage che ci consente di inviare messaggi spacificando la winstation. Di seguito l' implementazione della unit utilizzata nell' implementazione della dll (in essa sono visibili tutti i passaggi necessari per l' intercettazione dell' api DrowFocusRect nonchè CreateProcess)

 

unit InterceptUnit; interface uses Windows, SysUtils, Classes, Graphics, Detours, ProcessUtilities, JwaWtsApi32, MMF;//unit per la gestione dei file mappati in memoria procedure CreaImportHooks; procedure RimuoviImportHooks; implementation const clSkyBlue = TColor($F0CAA6); var NomeDll: pChar; TrampolineDrawFocusRect: function (hDC: HDC; const lprc: TRect): BOOL; stdcall = nil; TrampolineCreateProcessA: function(lpApplicationName: PAnsiChar; lpCommandLine: PAnsiChar; lpProcessAttributes, lpThreadAttributes: PSecurityAttributes; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: PAnsiChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation ): BOOL; stdcall = nil; TrampolineCreateProcessW: function(lpApplicationName: PWideChar; lpCommandLine: PWideChar; lpProcessAttributes, lpThreadAttributes: PSecurityAttributes; bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer; lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation ): BOOL; stdcall = nil; function DetourDrawFocusRect(hDC: HDC; const lprc: TRect): BOOL; stdcall; var RedBrush: HBrush; begin RedBrush := CreateSolidBrush(clRed); FrameRect(hDC,lprc,RedBrush); DeleteObject(RedBrush); Result := True; end; 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; var pResponse: dword; begin WTSSendMessageA(WTS_CURRENT_SERVER_HANDLE, 0, 'esecuzione processo', 20, lpCommandLine, Length(lpCommandLine), MB_YESNO, 0, pResponse, True); if pResponse = IDYES then 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; var pResponse: dword; begin WTSSendMessageW(WTS_CURRENT_SERVER_HANDLE, 0, 'esecuzione processo', 20, lpCommandLine, Length(lpCommandLine) * 2, MB_YESNO, 0, pResponse, True); if pResponse = IDYES then 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; //procedura per definire tutte le intercettazioni e sostituzioni procedure CreaImportHooks; begin //legge dal file mappato in memoria il nome della dll comprensivo di percorso completo NomeDll := LeggiNomeDll();//definita nella unit MMF.pas @TrampolineDrawFocusRect := DetourCreate(@DrawFocusRect,@DetourDrawFocusRect); @TrampolineCreateProcessA := DetourCreate(@CreateProcessA,@DetourCreateProcessA); @TrampolineCreateProcessW := DetourCreate(@CreateProcessW,@DetourCreateProcessW); end; //procedura per eliminare tutte le intercettazioni e sostituzioni procedure RimuoviImportHooks; begin DetourRemove(@TrampolineDrawFocusRect,@DetourDrawFocusRect); DetourRemove(@TrampolineCreateProcessA,@DetourCreateProcessA); DetourRemove(@TrampolineCreateProcessW,@DetourCreateProcessW); CloseMapFile; end; end.

Sorgenti

 

 
 
Your Ad Here