Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Monitorare lo stato di un processo e riavviarlo in automatico nel caso che venga terminato


Nell'articolo Elimina se terminato viene descritto come eliminare il .exe associato ad un processo in esecuzione immediatamente dopo la terminazione del processo medesimo. In maniera analoga, in questo articolo viene mostrato come riavviare un processo subito dopo che questo č stato terminato. E' un ennesimo esempio di applicazione della tecnica di "Code Injection" esposta nell'articolo Code Injection. Rispetto all'articolo sull'eliminazione del .exe, viene chiamata l'api win32 CreateProcess (creazione di un processo) al posto dell'api win32 DeleteFile (eliminazione di un file su disco).

1. Implementazione

function RestartIfTerminated(PID: Cardinal; //PID del processo remoto TargetPid: Cardinal; TargetExeName: PAnsiChar; var outValue: Cardinal; //valore importante ottenuto //dalla funzione remota var codError: Cardinal; //errore riscontrato dalla funzione remota synch: Boolean): Boolean; //esecuzione sincrona del thread remoto type TRestartIfTerminatedData = record errorcod: Cardinal; //codice di errore rilevato nella funzione remota output: Cardinal; //risultato significativo nella funzione remota //Indirizzi delle API usate: elenco puntatori a funzioni; N.B. rigorosamente stdcall //Es. pLoadLibraryA: function(pLibFileName: PAnsiChar): Cardinal; stdcall; pExitThread: procedure (dwExitCode: Cardinal); stdcall; //API obbligatoria pGetLastError: function(): Cardinal; stdcall; pOpenProcess: function (dwDesiredAccess: Cardinal; bInheritHandle: Boolean; dwProcessId: Cardinal): Cardinal; stdcall; pWaitForSingleObject: function (hHandle: Cardinal; dwMilliseconds: Cardinal): Cardinal; stdcall; pCreateProcessA: function (lpApplicationName: PAnsiChar; lpCommandLine: PAnsiChar; lpProcessAttributes: PSecurityAttributes; lpThreadAttributes: PSecurityAttributes; bInheritHandles: Boolean; dwCreationFlags: Cardinal; lpEnvironment: Pointer; lpCurrentDirectory: PAnsiChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): Boolean; stdcall; pCloseHandle: function (hObject: Cardinal): Boolean; stdcall; //Puntatori a dati; Es. tutte le stringhe vanno messe qui dentro //Es. pNomeDll: Pointer; pTargetPID: Cardinal; pTargetExeName: Pointer; //Puntatori a dati; Es. tutte le stringhe vanno messe qui dentro //Es. pNomeDll: Pointer; end; var hProcess: Cardinal; //handle al processo remoto RestartIfTerminatedData: TRestartIfTerminatedData; //indirizzo del record nello //spazio di memoria del processo remoto pRestartIfTerminatedData: Pointer; //indirizzo della funzione del thread nello //spazio di memoria del processo remoto pRestartIfTerminatedThread: Pointer; output_value: Cardinal; error_code: Cardinal; functionSize, parameterSize: Cardinal; procedure RestartIfTerminatedThread(lpParameter: pointer); stdcall; var hProcess: Cardinal; StartupInfo: TStartupInfo; ProcessInfo: TProcessInformation; //qui posso definire delle variabili locali begin with TRestartIfTerminatedData(lpParameter^) do begin //implementazione: tutte le API vengono chiamate //tramite i puntatori nel record hProcess := pOpenProcess(SYNCHRONIZE, False, pTargetPID); if hProcess = 0 then begin errorcod := pGetLastError; pExitThread(0); end; case pWaitForSingleObject(hProcess, INFINITE) of WAIT_FAILED: begin errorcod := pGetLastError; pExitThread(0); end; end; pCloseHandle(hprocess); StartupInfo.cb := SizeOf(StartupInfo); StartupInfo.lpReserved := nil; StartupInfo.lpDesktop := pAnsiChar('winsta0\default'); StartupInfo.lpTitle := nil; StartupInfo.dwX := 0; StartupInfo.dwY := 0; StartupInfo.dwXSize := 0; StartupInfo.dwYSize := 0; StartupInfo.dwXCountChars := 0; StartupInfo.dwYCountChars := 0; StartupInfo.dwFillAttribute := 0; StartupInfo.dwFlags := 1; StartupInfo.wShowWindow := 5; StartupInfo.cbReserved2 := 0; StartupInfo.lpReserved2 := nil; StartupInfo.hStdInput := 0; StartupInfo.hStdOutput := 0; StartupInfo.hStdError := 0; if not pCreateProcessA(nil, pTargetExeName, nil, nil, False, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo) then begin errorcod := pGetLastError; pExitThread(0); end else begin //come output metto il PID del processo creato output := ProcessInfo.dwProcessId; pCloseHandle(ProcessInfo.hProcess); pExitThread(1); end; //N.B. chiamare sempre pExitCodeThread per definire il codice di uscita del thread //Es. pExitCodeThread(1) significa successo // pExitCodeThread(0) significa fallimento end; end; //dealloco la memoria in remoto function RestartIfTerminatedUnloadData(): Boolean; begin Result := False; with RestartIfTerminatedData do begin //chiamo UnloadData su tutti i puntatori a dati inclusi nel record UnloadData(hProcess, pTargetExeName); end; //deallocazione spazio per il parametro UnloadData(hProcess, pRestartIfTerminatedData); //deallocazione spazio per la funzione UnloadData(hProcess, pRestartIfTerminatedThread); Result := True; end; //definisco i valori dei campi del record e copio i dati in remoto function RestartIfTerminatedInjectData(): Boolean; begin Result := False; try //inizializzazione valori campi del record: with RestartIfTerminatedData do begin errorcod := 0; output := 0; //assegno i valori ai puntatori a funzione (tramite GetModuleHandle e GetProcAddres) //Es. pLoadLibraryA := GetProcAddress(GetModuleHandle('kernel32'), 'LoadLibraryA'); pExitThread := GetProcAddress(GetModuleHandle('kernel32'), 'ExitThread'); //API Obbligatoria pGetLastError := GetProcAddress(GetModuleHandle('kernel32'), 'GetLastError'); pOpenProcess := GetProcAddress(GetModuleHandle('kernel32'), 'OpenProcess'); pWaitForSingleObject := GetProcAddress(GetModuleHandle('kernel32'), 'WaitForSingleObject'); pCreateProcessA := GetProcAddress(GetModuleHandle('kernel32'), 'CreateProcessA'); pCloseHandle := GetProcAddress(GetModuleHandle('kernel32'), 'CloseHandle'); pTargetPID := TargetPid; //assegno i valori ai puntatori ai dati (tramite InjectData); //N.B. se una InjectData ritorna False allora bisogna chiamare Exit if not InjectData(hProcess, TargetExeName, Length(TargetExeName), False, pTargetExeName) then begin Exit; end; //assegno i valori ai puntatori ai dati (tramite InjectData); //N.B. se una InjectData ritorna False allora bisogna chiamare Exit end; //copio il parametro parameterSize := SizeOf(RestartIfTerminatedData); if not InjectData(hProcess, @RestartIfTerminatedData, parameterSize, False, pRestartIfTerminatedData) then begin Exit; end; //copio la funzione functionSize := SizeOfProc(@RestartIfTerminatedThread); if not InjectData(hProcess, @RestartIfTerminatedThread, functionSize, True, pRestartIfTerminatedThread) then begin Exit; end; Result := True; finally if not Result then begin RestartIfTerminatedUnloadData; end; end; end; begin //inizializzo a zero le variabili locali hProcess := 0; pRestartIfTerminatedData := nil; pRestartIfTerminatedThread := nil; output_value := 0; error_code := 0; try hProcess := OpenProcessEx(PROCESS_CREATE_THREAD + PROCESS_QUERY_INFORMATION + PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_VM_READ, False, PID ); if hProcess = 0 then begin ErrStr('OpenProcessEx'); Exit; end; if not RestartIfTerminatedInjectData() then Exit; if not InjectThread(hProcess, pRestartIfTerminatedThread, pRestartIfTerminatedData, output_value, error_code, synch) then Exit; //output_value e error_code sono stati inizializzati a 0. //sono stati modificati dalla InjectThread solo se synch = true; //se synch=false sono rimasti uguali a zero outvalue := output_value; codError := error_code; Result := True; finally if synch or (not Result) then begin RestartIfTerminatedUnloadData; end; if hProcess <> 0 then begin if not CloseHandle(hProcess) then begin ErrStr('CloseHandle'); end; end; end; end;

e di seguito un semplice esempio di utilizzo

procedure TfrmMain.btnRestartIfterminatedClick(Sender: TObject); var output: Cardinal; err: Cardinal; exeName: PAnsiChar; begin // GetMem(exeName, 1000); GetModuleFileNameA(0, exeName, 1000); if not RestartIfTerminated(PidProcesso(edtNomeEXE.Text), GetCurrentProcessId, exeName, output, err, False) then begin mmoLog.Lines.Add('errore nella procedura'); end else begin if err <> 0 then mmoLog.Lines.Add('Errore nel thread; Cod errore: ' + IntToStr(err)) else MessageDlg('Perfetto: hai attivato con successo il monitoraggio' + #13#10 + 'Il processo ' + edtNomeEXE.Text + ' ha un thread che' + #13#10 + 'sorveglia la terminazione di questo processo' + #13#10 + 'Quando questo processo terminerā (in qualsiasi modo questo succeda)' + #13#10 + 'verrā automaticamente riavviato', mtInformation, [mbOK], 0); end; FreeMem(exeName); end;

RiavviaSeTerminato

 

 

 

 

 
 
Your Ad Here