2012-04-14 7 views
11

Spero che questo post non sia un duplicato. Lasciatemi spiegare:Sospende/riprendi i processi come PsSuspend fa

Ho considerato il post simile How to pause/resume any external process under Windows? ma con preferenza C++/Python e tuttavia senza una risposta accettata al momento della pubblicazione.


La mia domanda:

Sono interessato a una possibile implementazione a Delfi delle funzionalità fornite da PsSuspend da Mark Russinovich di Windows Sysinternals.

Citazioni:

PsSuspend consente di sospendere i processi sul locale o un sistema remoto, che è desiderabile nei casi in cui un processo sta consumando una risorsa (ad esempio rete, CPU o del disco) che si desidera per consentire l'utilizzo di diversi processi . Piuttosto che uccidere il processo che sta consumando la risorsa, la sospensione di consente di lasciarlo continuare l'operazione in un secondo momento successivo a .

Grazie.


Edit:

Un attuazione parziale farà. Le funzionalità remote possono essere eliminate.

+0

Si desidera emulare l'intera funzionalità? Anche processi remoti? –

+1

ora questa è davvero una (x3) buona domanda – ComputerSaysNo

+0

@David Heffernan: No, lascia cadere la funzionalità remota. – menjaraz

risposta

10

Si può provare a utilizzare il seguente codice. Utilizza le funzioni non documentate NtSuspendProcess e NtResumeProcess. L'ho provato su Windows 7 a 64 bit dall'applicazione a 32 bit di Delphi 2009 e funziona per me. Si noti che queste funzioni non documentate possono quindi essere rimosse dalle versioni future di Windows.

Aggiornamento

I SuspendProcess e ResumeProcess involucri dal seguente codice sono ora funzioni e restituisce true se riesce, False altrimenti.

type 
    NTSTATUS = LongInt; 
    TProcFunction = function(ProcHandle: THandle): NTSTATUS; stdcall; 

const 
    STATUS_SUCCESS = $00000000; 
    PROCESS_SUSPEND_RESUME = $0800; 

function SuspendProcess(const PID: DWORD): Boolean; 
var 
    LibHandle: THandle; 
    ProcHandle: THandle; 
    NtSuspendProcess: TProcFunction; 
begin 
    Result := False; 
    LibHandle := SafeLoadLibrary('ntdll.dll'); 
    if LibHandle <> 0 then 
    try 
    @NtSuspendProcess := GetProcAddress(LibHandle, 'NtSuspendProcess'); 
    if @NtSuspendProcess <> nil then 
    begin 
     ProcHandle := OpenProcess(PROCESS_SUSPEND_RESUME, False, PID); 
     if ProcHandle <> 0 then 
     try 
     Result := NtSuspendProcess(ProcHandle) = STATUS_SUCCESS; 
     finally 
     CloseHandle(ProcHandle); 
     end; 
    end; 
    finally 
    FreeLibrary(LibHandle); 
    end; 
end; 

function ResumeProcess(const PID: DWORD): Boolean; 
var 
    LibHandle: THandle; 
    ProcHandle: THandle; 
    NtResumeProcess: TProcFunction; 
begin 
    Result := False; 
    LibHandle := SafeLoadLibrary('ntdll.dll'); 
    if LibHandle <> 0 then 
    try 
    @NtResumeProcess := GetProcAddress(LibHandle, 'NtResumeProcess'); 
    if @NtResumeProcess <> nil then 
    begin 
     ProcHandle := OpenProcess(PROCESS_SUSPEND_RESUME, False, PID); 
     if ProcHandle <> 0 then 
     try 
     Result := NtResumeProcess(ProcHandle) = STATUS_SUCCESS; 
     finally 
     CloseHandle(ProcHandle); 
     end; 
    end; 
    finally 
    FreeLibrary(LibHandle); 
    end; 
end; 
+0

Sto iniziando a pensare che non sono funzioni ma procedure dal punto di vista di Delphi poiché restituiscono sempre False anche se il processo è congelato. – TLama

+4

Questa è la gioia delle funzioni non documentate. Ad ogni modo, 'OpenProcess' restituisce un handle di processo e non un handle del modulo, FWIW. –

+0

@David, buona cattura, grazie! Menjaraz, interessante sulla funzione 'NtSuspendProcess' è il suo comportamento. Blocca il processo, ma le finestre continuano a ricevere messaggi di Windows. Una volta rilasciato il processo, vengono elaborati. – TLama

5

Non esiste una chiamata API SuspendProcess in Windows. Quindi, quello che devi fare è:

  1. Enumerare tutti i thread nel processo. Vedi RRUZ's answer per il codice di esempio.
  2. Chiamare SuspendThread per ciascuna di queste discussioni.
  3. Per implementare la parte di ripresa del programma, chiamare ResumeThread per ogni thread.
+0

Sembra ragionevole emulare la funzionalità. Sospetto di API non documentate basate sull'uso di PsSuspend: 'pssuspend [-] [-r] [\\ computer [-u username] [-p password]] '. C'è un modo per accertare che non viene usato un tale api visto che è stato scritto da un esperto all'interno della stessa MS? – menjaraz

+2

Mark si è unito a MS qualche tempo dopo aver scritto PsSuspend. Allo stesso modo, può benissimo usare API non documentate. Ha anche scritto Windows Internals prima di entrare in MS così dentro o fuori fa poca differenza. Penso che il walker delle dipendenze in modalità profilo possa dirti quali sono le API utilizzate. –

+0

@menjaraz: Se mai esistesse, lo sapresti. Questa non è l'epoca medievale ... –

1

Ho appena trovato il seguente snippet here (Autore: steve10120).

Penso che siano oggetti di valore e non posso fare a meno di postarli anche come risposta alternativa alla mia domanda.


Riprendi processo:

function ResumeProcess(ProcessID: DWORD): Boolean; 
var 
    Snapshot,cThr: DWORD; 
    ThrHandle: THandle; 
    Thread:TThreadEntry32; 
begin 
    Result := False; 
    cThr := GetCurrentThreadId; 
    Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 
    if Snapshot <> INVALID_HANDLE_VALUE then 
    begin 
    Thread.dwSize := SizeOf(TThreadEntry32); 
    if Thread32First(Snapshot, Thread) then 
     repeat 
     if (Thread.th32ThreadID <> cThr) and (Thread.th32OwnerProcessID = ProcessID) then 
     begin 
     ThrHandle := OpenThread(THREAD_ALL_ACCESS, false, Thread.th32ThreadID); 
     if ThrHandle = 0 then Exit; 
     ResumeThread(ThrHandle); 
     CloseHandle(ThrHandle); 
     end; 
     until not Thread32Next(Snapshot, Thread); 
     Result := CloseHandle(Snapshot); 
    end; 
end; 

Sospendere processo:

function SuspendProcess(PID:DWORD):Boolean; 
var 
hSnap: THandle; 
THR32: THREADENTRY32; 
hOpen: THandle; 
begin 
    Result := FALSE; 
    hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 
    if hSnap <> INVALID_HANDLE_VALUE then 
    begin 
    THR32.dwSize := SizeOf(THR32); 
    Thread32First(hSnap, THR32); 
    repeat 
     if THR32.th32OwnerProcessID = PID then 
     begin 
     hOpen := OpenThread($0002, FALSE, THR32.th32ThreadID); 
     if hOpen <> INVALID_HANDLE_VALUE then 
     begin 
      Result := TRUE; 
      SuspendThread(hOpen); 
      CloseHandle(hOpen); 
     end; 
     end; 
    until Thread32Next(hSnap, THR32) = FALSE; 
    CloseHandle(hSnap); 
    end; 
end; 

Disclaimer:

Non li ho testati affatto. Si prega di godere e non dimenticare di feedback.

+0

Vedi il commento di Wombat. Questa non è una buona programmazione. – Lothar

4

Esiste una condizione di competizione per l'implementazione "sospendi tutti i thread": cosa accade se il programma che si sta tentando di sospendere crea uno o più thread tra il momento in cui si crea lo snapshot e il momento in cui si completa la sospensione?

È possibile eseguire il loop, ottenere un'altra istantanea e sospendere eventuali thread non sospesi, uscendo solo quando non ne è stato trovato nessuno.

La funzione non documentata evita questo problema.

Problemi correlati