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;
Written the Nov. 23, 2020, 10:16 a.m. by Jean-Pierre LESUEUR
Updated: ago.