Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

SubClassing di finestre in processi diversi da quello corrente
 

Oggi non ho proprio niente da fare, ho acceso la televisione e non c' è niente, poi ho acceso la radio (e c' è sempre la stessa roba), poi ho fatto un giro in bici e si è messo a piovere e poi ... e poi mi sono rotto i cogl... Bene questo preambolo per introdurre le motivazioni fondamentali che mi hanno portato alla stesura delle ca...te che andrò ad elencare di seguito. Dunque l' obiettivo è prendere un programma qualsiasi e modificarne il comportamento ad esempio in corrispondenza della pressione di alcuni tasti, impedirne la chiusura, etc..  In alcuni articoli precedenti ho parlato di dll injection, di system hooks ... in linea di massima il concetto chiave è mappare del codice nello spazio di memoria del processo che ci interessa ed eseguire tale codice per giungere ad un certo livello di personalizzazione del processo in questione. Naturalmente non si può pretendere di usare questa tecnica in tutte le situazioni e per tutti gli obiettivi possibili ed immaginabili; vi sono contesti in cui senza il sorgente del programma si fa veramente fatica a cavarci gli zampetti, tuttavia qualcosa di interessante può essere raggiunto. Bene, anzitutto per mappare il codice nello spazio di memoria del processo in esame, utilizzeremo la tecnica di dll injection: il codice verrà scritto in una dll e poi eseguito nel contesto del processo destinazione; con un procedimento analogo andremo a eliminare la dll dallo spazio di memoria del processo remoto. Vediamo come procedere con il mapping e l' unmapping di una dll nello spazio di memoria di un processo: dato il PID (Process identifier) di un processo ed il nome di una dll (comprensivo di percorso completo) possiamo utilizzare la seguente funzione per mappare la dll nello spazio di memoria del processo

function InjectDll(PID: dword; DLL: pChar): LongWord; var BytesWritten, Process, Thread, ThreadId: dword; Paramaters: pointer; begin Result := 0; //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;

La procedure ModificaPrivilegio consente l' abilitazione di un determionato privilegio. La usiamo per abilitare il privilegio di debug

 

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;

Bene ora che abbiamo visto come mappare una dll nello spazio di memoria di un processo remoto, vediamo come eliminarla dal medesimo (behh certo se si fa una operazione bisogna anche essere in grado di eseguirne l' annullamento con il conseguente ripristino del sistema allo stato precedente). Il concetto è analogo al mapping: il thread che andrà in esecuzione nel processo remoto (tramite CreateRemoteThread) non dovrà più eseguire un LoadLibraryA ma un FreeLibrary. FreeLibrary prende in input l' indirizzo di base di caricamento della dll nello spazio di memoria del processo che esegue la funzione stessa. A questo punto la domanda è spontanea: esiste un modo per determinare l' indirizzo di base di caricamento di una dll in un processo. La risposta è: Cerrrtoooo. Semplicemente utilizzando le "Tool Help API". Di seguito la procedura che, dato il PID di un processo ed il nome di una dll caricata nello spazio di memoria del processo medesimo (N.B. sono il nome, non percorsi, etc...) restituisce l' indirizzo (nello spazio di memoria del processo in questione) a partire dal quale la dll è caricata (N.B. è necessario includere la unit TlHelp32).

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;

A questo punto possiamo definire la procedura per eseguire il free di una dll in un processo remoto 

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) nel contesto del processo remoto 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;

Ok; per finire la procedura che, dato il nome di un processo, ne restituisce il PID:

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;

Ohhh, finalmente abbiamo tutti gli strumenti per mappare una dll nello spazio di memoria di un processo e per eseguire il free della stessa. Bene, a questo punto la storiella potrebbe finire qui, argomentazione trattata con esaustività e completezza (stica...) ... Però fuori piove ancora e in sequenza mi sono venute in mente un pò di cose con le quali pasteggiavo nel lontano 2001: la più importante è la possibilità di personalizzare il comportamento di un controllo visuale sostituendo la sua Window Procedure con una versione personalizzata. Un attimo, calma e sangue freddo ... cos' è la Window Procedure di una finestra??? Mmhhh, in sostanza si tratta della procedura che viene chiamata ogni volta che la finestra medesima riceve un messaggio (sia con un SendMessage sia con un PostMessage). Il parametro fondamentale di una Window Procedure è appunto il messaggio: nell' implemetazione della Window Procedure c'è  il classico "case" che raccoglie i vari tipi di messaggi che può ricevere quella finestra ed il conseguente comportamento da adottare in corrispondenza di ogni singolo messaggio. Una Window Procedure è una funzione che ha 4 parametri e restituisce un valore: i 4 parametri rappresentano le caratteristiche del messaggio inviato alla finestra; più precisamente rappresentano rispettivamente l' handle della finestra destinazione, il tipo di messaggio (WM_LBUTTONDOWN, WM_CLOSE, etc...), i 2 parametri LParam e WParam tipici di ogni messaggio (guardare il tipo TMsg nell' help di Delphi per trovare i medesimi elementi). Ora entra in gioco l' api SetWindowLong: questa funzione consente di modificare un attributo di una finestra specifica; la finestra viene identificata dal suo handle e tra gli attributi della medesima c' è appunto anche la Window Procedure; ciò significa che se conosco l' handle di una finestra posso assegnargli una Window Procedure creata da me intercettando quindi tutti i messaggi destinati alla finestra e personalizzandone quindi il comportamento???? La risposta è si ma non sempre; mi spiego meglio: ciò è possibile ma solo nell' ambito delle finestre create dallo stesso processo che esegue l' api SetWindowLong. Se non sbaglio però all' inizio di stà pappardella abbiamo parlato di mapping e unmapping di dll (e quindi di codice da eseguire) nello spazio di memoria di un altro processo. Se l' implementazione della dll consistesse in una chiamata a SetWindowLong passandogli come parametro l' handle di una finestra del processo remoto, riusciremmo a modificare la Window Procedure di una finestra del processo remoto (in quanto la dll è appunto mappata nello spazio di memoria del processo remoto): infatti  proprio perchè la dll è stata mappata, una chiamata a SetWindowLong nella dll equivale ad una chiamata a SetWindowLong eseguita dal processo remoto. E' importantissimo osservare che Il valore restituito dall' api SetWindowLong è il vecchio valore del' attributo che si è andati a modificare. Vediamo ora come avviene la sostituzione della Window Procedure di una finestra

var //handle della finestra di cui si vuole personalizzare la Window Procedure FHandle: THandle; //puntatore alla Window Procedure originale: utilizzato sia per ripristinare //la Window Procedure originale, sia per chiamare la medesima nel contesto della //nuova Window Procedure (in genere infatti l' implementazione della nuova //Window Procedure consiste in una serie di operazioni, quali ad esempio notifiche, //etc.. e nella chiamata alla Window Procedure originale) OldWindowProc: Pointer; //nuova Window Procedure function NewWindowProc(WindowHandle: hWnd; TheMessage: Longint; ParamW: Longint; ParamL: Longint): LongInt; stdcall; begin //elaborazioni varie (notifiche, etc...) //se si vuole interrompere qui l' eleaborazione del messaggio //allora: (* /////// result := 0; exit; *) /////// //altrimenti vado a chiamare la Window Procedure originale (*NewWindowProc := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW, ParamL); *) end; procedure Modify(); begin //imposto la nuova Window Procedure (NewWindowProcedure) e contemporaneamente //salvo la vecchia nel puntatore OldWindowProc OldWindowProc := Pointer(SetWindowLong(FHandle, GWL_WNDPROC, LongInt(@NewWindowProc))); end; procedure Restore(); begin //ripristino la vecchia Window Procedure (OldWindowProc) SetWindowLong(FHandle, GWL_WNDPROC, LongInt(OldWindowProc)); end;

Ok, a questo punto devo trovare il modo di determinare l' handle della finestra di cui voglio cambiare la Window Procedure. Il discorso non è semplice, o meglio è semplice se si vogliono fare le cose semplici, un pò più complicato altrimenti (il ragionamento non fa una piega). Una funzione che viene spesso usata per trovare l' handle di una finestra è FindWindow. FindWindow consente di determinare l' handle di qualsiasi finestra Top-Level ossia di una finestra che non ha alcuna finestra "parent" (o equivalentemente ha il desktop come finestra parent) dati il nome della finestra ed il nome della classe di implementazione. Per trovare l' handle di una finestra figlia (sempre sfruttando "nome finestra" e "nome classe") occorre l' api FindWindowEx che utilizza i medesimi paramateri utilizzati dall FindWindow con in più l' handle della finestra padre. In linea di massima poi l' enumerazione delle finestre top-level avviene tramite l' api EnumWindows e l' enumerazione delle finestre figlie di una finestra avviene tramite l' api EnumChildWindows. Ok per l' esempio che voglio fare è sufficiente FindWindow. Si ma di quale esempio si tratta??? Bene il mio obiettivo è impedire che venga chiuso "Outlook Express": mi insinuerò nel processo di "Outlook Express" ed andrò a cambiare la Window Procedure della finestra principale; la nuova Window Procedure annullerà l' elaborazione del messaggio WM_CLOSE (che viene inviato alla finestra pincipale dell' applicativo quando si decide di chiudere il medesimo). Ok, ma come ottenere il nome della finestra e la classe di implementazione (parametri da passare a FindWindow) relativamente ad Outlook Express???? Si può utilizzare un ottimo programmino che restituisce le caratteristiche della finestra su cui è posizionato il cursore del mouse: si chiama Window Detective. Utilizzandolo si vede che la finestra principale di "Outlook Express" ha le seguenti caratteristiche:

1)Nome finestra: Outlook Express

2)Nome classe: Outlook Express Browser Class

l' handle della finestra pincipale di Outlook Express si può ottenere quindi tramite la seguente semplice chiamata

FindWindow('Outlook Express Browser Class', 'Outlook Express');

Per impedire la chiusura di Outlook Express dovrò annulare il messaggio WM_CLOSE: la nuova Window Procedure (che andrò a definire nella dll che vado a mappare nel processo remoto (che in questo caso è appunto Outlook Express)) dovrà quindi avere la seguente implementazione

function NewWindowProc(WindowHandle: hWnd; TheMessage: Longint; ParamW: Longint; ParamL: Longint): LongInt; stdcall; begin if Themessage = WM_CLOSE then begin result := 0; exit; end; NewWindowProc := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW, ParamL); end;

L' unica cosa che manca (e che serve alle procedure DllInject e DllUninject) è il nome del processo di "Outlook Express": detto fatto:

msimn.exe

Bene è tutto. Però prima voglio rimpilzare il programma con qualcos' altro (tanto non ciò un ca**o da fare): quel qualcos' altro è la comunicazione all' applicativo che esegue il mapping e l' unmapping del tentativo di chiusura di "Outlook Express". Come gestire la comunicazione tra i 2 processi??? Behh una buona scelta è quella di usare lo scambio di messaggi usufruendo delle potenzialità del messaggio WM_COPYDATA. Il parametro lParam di questo tipo di messaggio contiene un puntatore ad un record di nome TCopyDataStruct (definito nella unit Windows) dotato di 3 campi. Nel caso specifico vorrò passare una stringa (si possono passare dati di ogni tipo come ad esempio record, ...); si ottiene la seguente procedura che consente l' invio di una stringa ad un altro processo

//funzione per inviare i dati ad un altro processo procedure InvioDati(str: pChar); var copydata: TCopyDataStruct; begin //campo dwdata: tipologia di dato WM_COPYDATA //(serve al receiver per distinguere tra tutti i possibili messaggi WM_COPYDATA //che gli possono arrivare: il receiver si comporterà nel seguente modo: se il codice è 199 //allora faccio questo altrimenti se il codice è (ad esempio) 287 faccio quest' altro e così via.) copydata.dwData := 199; //dimensione della stringa copydata.cbData := Length(str) + 1; //indirizzo a partire dal quale è memorizzata la stringa copydata.lpData := pChar(str); //il programma che esegue il mapping e l' unmapping ha la finestra principale con nome e classe //così come sono assegnati di default da Delphi SendMessage(FindWindow('TForm1', 'Form1'), WM_COPYDATA, 0, integer(@copydata)); end;

la nuova Window Procedure (che andrò a definire nella dll che vado a mappare nel rpocesso remoto (che in questo caso è appunto Outlook Express) assumerà a questo punto la seguente forma:

//nuova Window Procedure function NewWindowProc(WindowHandle: hWnd; TheMessage: Longint; ParamW: Longint; ParamL: Longint): LongInt; stdcall; begin if Themessage = WM_CLOSE then begin //messaggio che invio al mio applicativo InvioDati(pChar('tentativo di chiusura dell'' applicazione')); result := 0; exit; end; NewWindowProc := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW, ParamL); end;

Analogamente nel programma principale (quello, tanto per intenderci, a cui saranno inviate le notifiche sotto forma di messaggio WM_COPYDATA) ci deve essere una procedura di gestione del messaggio WM_COPYDATA. Nella dichiarazione della TForm1 (nella sezione "private") inseriremo la procedura di gestione del messaggio

type TForm1 = class(TForm) ..... private { Private declarations } procedure WMCopyData(Var msg: TWMCopyData); message WM_COPYDATA; public { Public declarations } end;

 

procedure TForm1.WMCopyData(Var msg: TWMCopyData); begin Case msg.Copydatastruct^.dwData of 199: begin //la form dispone di un controllo TMemo in cui andiamo //ad inserire il contenuto del messaggio Memo1.Lines.Add(pChar(msg.CopyDataStruct^.lpData)); end; end; end;

Ok adesso è proprio tutto. Di seguito il sorgente del programma e della dll

unit Main; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ProcessUtilities; type TForm1 = class(TForm) btInject: TButton; btUninject: TButton; Memo1: TMemo; procedure btInjectClick(Sender: TObject); procedure btUninjectClick(Sender: TObject); private { Private declarations } procedure WMCopyData(Var msg: TWMCopyData); message WM_COPYDATA; public { Public declarations } end; var Form1: TForm1; PID: LongWord; DllBaseAddr: PByte; implementation {$R *.dfm} procedure TForm1.WMCopyData(Var msg: TWMCopyData); begin Case msg.Copydatastruct^.dwData of 199: begin Memo1.Lines.Add(pChar(msg.CopyDataStruct^.lpData)); end; end; end; procedure TForm1.btInjectClick(Sender: TObject); begin PID := PidProcesso('msimn.exe'); InjectDll(PID, pAnsiChar(GetCurrentDir + '\HookDll.dll')); MessageDlg('La dll HookDll.dll è stata mappata e ' + 'non è più possibile chiudere Outlook Express', mtInformation, [mbOK], 0); end; procedure TForm1.btUninjectClick(Sender: TObject); begin // DllBaseAddr := BaseAddrDllProcesso(PID, 'HookDll.dll'); UninjectDll(PID, DllBaseAddr); MessageDlg('La dll HookDll.dll è stata deallocata ' + 'ed ora è possibile chiudere Outlook Express', mtInformation, [mbOK], 0); end; end.

////////

library HookDll; uses Windows, SysUtils, Classes, Messages; {$R *.RES} var FHandle: THandle; OldWindowProc: Pointer; procedure InvioDati(str: pChar); var copydata: TCopyDataStruct; begin copydata.dwData := 199; copydata.cbData := Length(str) + 1; copydata.lpData := pChar(str); SendMessage(FindWindow('TForm1', 'Form1'), WM_COPYDATA, 0, integer(@copydata)); end; function NewWindowProc(WindowHandle: hWnd; TheMessage: Longint; ParamW: Longint; ParamL: Longint): LongInt; stdcall; begin if Themessage = WM_CLOSE then begin InvioDati(pChar('tentativo di chiusura dell'' applicazione')); result := 0; exit; end; NewWindowProc := CallWindowProc(OldWindowProc, WindowHandle, TheMessage, ParamW, ParamL); end; procedure Modify(); begin OldWindowProc := Pointer(SetWindowLong(FHandle, GWL_WNDPROC, LongInt(@NewWindowProc))); end; procedure Restore(); begin SetWindowLong(FHandle, GWL_WNDPROC, LongInt(OldWindowProc)); end; procedure EntryPointProc(reason: integer); var str: pChar; begin case reason of DLL_PROCESS_ATTACH: begin FHandle := FindWindow('Outlook Express Browser Class', 'Outlook Express'); Modify; end; DLL_THREAD_ATTACH: begin end; DLL_PROCESS_DETACH: begin Restore; end; DLL_THREAD_DETACH: begin end; end; end; begin DllProc := @EntryPointProc; EntryPointProc(DLL_PROCESS_ATTACH); end.

sorgenti

 

 
 
Your Ad Here