Terminate Process Techniques

You will find below 4 different techniques to close/kill/terminate Windows process in pure WinAPI.

Techniques

  • TerminateProcess() : Classic method.
  • ExitProcess() : via Code Injection (32bit to 32bit ; 64bit to 64bit).
  • Crash Process : Inject code that will crash the process (32bit to 32bit ; 64bit to 64bit).
  • CTRL_CLOSE_EVENT / WM_CLOSE : Send “close” messages to target process windows.

TerminateAProcess() Method

Kill target process id following desired method : tmpAll, tpmTerminateProcess, tpmExitProcess, tpmCrash, tpmMessage

tmpAll attempt to kill process from cleanest way to dirtiest way until it succeed.

Code

{
    Jean-Pierre LESUEUR (@DarkCoderSc)
}

/// ...
uses Windows, SysUtils, tlhelp32;
/// ...

type
  TTerminateProcessMethod = (
                                tmpAll,
                                tpmTerminateProcess,
                                tpmExitProcess,
                                tpmCrash,
                                tpmMessage
  );

{
  Detect if a process id exists using the CreateToolHelp32Snapshot method from
  tlhelp32 lib.
}
function TLHelp32_ProcessIdExists(AProcessId : Cardinal) : Boolean;
var ASnapshot     : THandle;
    AProcessEntry : TProcessEntry32;
begin
  result := false;
  ///

  ASnapshot := CreateToolHelp32Snapshot(TH32CS_SNAPALL, 0);
  if ASnapshot = INVALID_HANDLE_VALUE then
    Exit();
  try
    ZeroMemory(@AProcessEntry, sizeOf(TProcessEntry32));
    AProcessEntry.dwSize := sizeOf(TProcessEntry32);

    if NOT Process32First(ASnapshot, AProcessEntry) then
      Exit();

    if (AProcessId = AProcessEntry.th32ProcessID) then begin
      result := true;
    end else begin
      while true do begin
        ZeroMemory(@AProcessEntry, sizeOf(TProcessEntry32));
        AProcessEntry.dwSize := sizeOf(TProcessEntry32);

        if NOT Process32Next(ASnapshot, AProcessEntry) then
          break;

        if (AProcessId = AProcessEntry.th32ProcessID) then begin
          result := true;

          break;
        end;
      end;
    end;
  finally
    CloseHandle(ASnapshot);
  end;
end;

{
  Method 1 : Terminate a process through TerminateProcess API. IMOO the cleanest
             way if it isn't a graphical application.
}
function TerminateProcess_TerminateProcess(AProcessID : Cardinal) : Boolean;
var hProc : THandle;
begin
  result := false;

  hProc := OpenProcess(PROCESS_TERMINATE, false, AProcessID);
  if (hProc = 0) then
    Exit();
  try
    if NOT WinAPI.Windows.TerminateProcess(hProc, 0) then
      Exit();

    result := true;
  finally
    CloseHandle(hProc);
  end;
end;

{
  Method 2 : Terminate Process through code injection on target process.
             This method works if both process (injecter and target) are using
             same process architecture.
}
function TerminateProcess_ExitProcess(AProcessID : Cardinal) : Boolean;
var hProc         : THandle;
    pExitProcess  : Pointer;
    hRemoteThread : THandle;
    dwThreadId    : Cardinal;
    Arg           : Integer;
begin
  result := false;
  ///
  SetLastError(0);
  pExitProcess := GetProcAddress(LoadLibrary('kernel32.dll'), 'ExitProcess');
  if (GetLastError() <> 0) then begin
    exit;
  end;

  hProc := OpenProcess(PROCESS_CREATE_THREAD  or
                       PROCESS_VM_OPERATION   or
                       PROCESS_VM_WRITE,
                       false, AProcessID);
  if (hProc = 0) then
    Exit();
  try
    Arg := 0; // EXIT VALUE

    hRemoteThread := CreateRemoteThread(hProc, nil, 0, pExitProcess, @Arg, 0, dwThreadId);
    if (hRemoteThread = 0) then
      Exit();

    WaitForSingleObject(hRemoteThread, INFINITE); // WAIT UNTIL REMOTE THREAD HAS END

    result := true;
  finally
    CloseHandle(hProc);
  end;
end;

{
  Method 3 : Terminate process by crashing target process with an access violation.
             This is not a recommended solution but still worth testing.
}
function TerminateProcess_Crash(AProcessID : Cardinal) : Boolean;
var hProc         : THandle;
    dwThreadId    : Cardinal;
    hRemoteThread : THandle;
begin
  hProc := OpenProcess(PROCESS_CREATE_THREAD  or
                       PROCESS_VM_OPERATION   or
                       PROCESS_VM_WRITE,
                       false, AProcessID);
  if (hProc = 0) then
    Exit;
  try
    hRemoteThread := CreateRemoteThread(hProc, nil, 0, Pointer(-1), nil, 0, dwThreadId);
    if (hRemoteThread = 0) then
      Exit();

    result := true;
  finally
    CloseHandle(hProc);
  end;
end;

{
  Method 4 : Terminate process via sending close event messages. IMOO the best
             method for process with GUI.
}
function _EnumWindowProc(AHwnd : HWND; param : LParam): BOOL; stdcall;
var AProcessID : Cardinal;
begin
  result := true;
  ///

  if AHwnd = 0 then
    Exit();

  GetWindowThreadProcessId(AHwnd, @AProcessID);

  if PCardinal(param)^ <> AProcessID then
     Exit();

  SendMessage(AHwnd, CTRL_CLOSE_EVENT, 0, 0);

  SendMessage(AHwnd, WM_CLOSE, 0, 0);
end;

function TerminateProcess_SendMessage(AProcessID : Cardinal) : boolean;
begin
  result := false;
  ///

  SetLastError(0);

  if NOT EnumWindows(@_EnumWindowProc, LPARAM(@AProcessID)) then begin
    exit;
  end;

  if TLHelp32_ProcessIdExists(AProcessID) then
    Exit;

  ///
  result := true;
end;

{
  Dispatach desired terminate process method.
}
function TerminateProcess(AProcessID : Cardinal; AMethod : TTerminateProcessMethod = tpmTerminateProcess) : Boolean;
begin
  result := false;
  ///

  if NOT TLHelp32_ProcessIdExists(AProcessID) then
    Exit();

  case AMethod of
    tmpAll : begin
      TerminateProcess_SendMessage(AProcessID);

      if NOT result then
        TerminateProcess_TerminateProcess(AProcessID);

      if NOT result then
        TerminateProcess_ExitProcess(AProcessID);

      if NOT result then
        TerminateProcess_Crash(AProcessID);
    end;

    tpmTerminateProcess : result := TerminateProcess_TerminateProcess(AProcessID);
    tpmExitProcess      : result := TerminateProcess_ExitProcess(AProcessID);
    tpmCrash            : result := TerminateProcess_Crash(AProcessID);
    tpmMessage          : result := TerminateProcess_SendMessage(AProcessID);
  end;
end;
comments powered by Disqus