Description
You can compile this unit as a classic Delphi Console Application. Feel free to edit both LFindWindowSignatures
and LProcessNameSignatures
to support more debuggers.
program SuspendThread;
{$APPTYPE CONSOLE}
uses
WinAPI.Windows, System.SysUtils, Generics.Collections, tlHelp32, Classes;
type
TProcessItem = class
private
FName : String;
FProcessId : Cardinal;
FThreads : TList<Cardinal>;
{@M}
procedure EnumThreads();
public
{@C}
constructor Create(AName : String; AProcessId : Cardinal; AEnumThreads : Boolean = True);
destructor Destroy(); override;
{@G}
property Name : String read FName;
property ProcessId : Cardinal read FProcessId;
property Threads : TList<Cardinal> read FThreads;
end;
TEnumProcess = class
private
FItems : TObjectList<TProcessItem>;
public
{@C}
constructor Create();
destructor Destroy(); override;
{@M}
function Refresh() : Cardinal;
procedure Clear();
function Get(AProcessId : Cardinal) : TProcessItem; overload;
function Get(AName : String) : TProcessItem; overload;
{@G}
property Items : TObjectList<TProcessItem> read FItems;
end;
{
Import API's From Kernel32
}
const THREAD_SUSPEND_RESUME = $00000002;
function OpenThread(
dwDesiredAccess: DWORD;
bInheritHandle: BOOL;
dwThreadId: DWORD
) : THandle; stdcall; external kernel32 name 'OpenThread';
{
Global Vars
}
var LFindWindowSignatures : TDictionary<String, String>;
LProcessNameSignatures : TStringList;
LProcesses : TEnumProcess;
{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Process Item (Process Name / Process Id / Process Main Thread Id)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{-------------------------------------------------------------------------------
___constructor
-------------------------------------------------------------------------------}
constructor TProcessItem.Create(AName : String; AProcessId : Cardinal; AEnumThreads : Boolean = True);
begin
FName := AName;
FProcessId := AProcessId;
FThreads := TList<Cardinal>.Create();
if AEnumThreads then
self.EnumThreads();
end;
{-------------------------------------------------------------------------------
___destructor
-------------------------------------------------------------------------------}
destructor TProcessItem.Destroy();
begin
if Assigned(FThreads) then
FreeAndNil(FThreads);
///
inherited Destroy();
end;
{-------------------------------------------------------------------------------
Enumerate Threads of process object
-------------------------------------------------------------------------------}
procedure TProcessItem.EnumThreads();
var ASnap : THandle;
AThreadEntry : TThreadEntry32;
procedure InitializeItem();
begin
ZeroMemory(@AThreadEntry, SizeOf(TThreadEntry32));
AThreadEntry.dwSize := SizeOf(TThreadEntry32);
end;
procedure AppendItem();
begin
if (AThreadEntry.th32OwnerProcessID <> FProcessId) then
Exit();
///
FThreads.Add(AThreadEntry.th32ThreadID);
end;
begin
if NOT Assigned(FThreads) then
Exit();
///
FThreads.Clear();
///
ASnap := CreateToolHelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (ASnap = INVALID_HANDLE_VALUE) then
Exit();
try
InitializeItem();
if NOT Thread32First(ASnap, AThreadEntry) then
Exit();
AppendItem();
while True do begin
InitializeItem();
if NOT Thread32Next(ASnap, AThreadEntry) then
break;
AppendItem();
end;
finally
CloseHandle(ASnap);
end;
end;
{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Enumerate Process Class
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{-------------------------------------------------------------------------------
___constructor
-------------------------------------------------------------------------------}
constructor TEnumProcess.Create();
begin
FItems := TObjectList<TProcessItem>.Create();
FItems.OwnsObjects := True;
///
self.Refresh();
end;
{-------------------------------------------------------------------------------
___destructor
-------------------------------------------------------------------------------}
destructor TEnumProcess.Destroy();
begin
if Assigned(FItems) then
FreeAndNil(FItems);
///
inherited Destroy();
end;
{-------------------------------------------------------------------------------
Enumerate Running Process.
@Return: Process Count
-------------------------------------------------------------------------------}
function TEnumProcess.Refresh() : Cardinal;
var ASnap : THandle;
AProcessEntry : TProcessEntry32;
procedure InitializeItem();
begin
ZeroMemory(@AProcessEntry, SizeOf(TProcessEntry32));
AProcessEntry.dwSize := SizeOf(TProcessEntry32);
end;
procedure AppendItem();
var AItem : TProcessItem;
begin
AItem := TProcessItem.Create(
AProcessEntry.szExeFile,
AProcessEntry.th32ProcessID,
True {Enum Threads: Default}
);
FItems.Add(AItem);
end;
begin
result := 0;
///
if NOT Assigned(FItems) then
Exit();
///
self.Clear();
ASnap := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (ASnap = INVALID_HANDLE_VALUE) then
Exit();
try
InitializeItem();
if NOT Process32First(ASnap, AProcessEntry) then
Exit();
AppendItem();
while True do begin
InitializeItem();
if NOT Process32Next(ASnap, AProcessEntry) then
break;
AppendItem();
end;
finally
CloseHandle(ASnap);
end;
end;
{-------------------------------------------------------------------------------
Clear Items (Process Objects)
-------------------------------------------------------------------------------}
procedure TEnumProcess.Clear();
begin
if Assigned(FItems) then
FItems.Clear;
end;
{-------------------------------------------------------------------------------
Get Process Item by Process Id or Name
-------------------------------------------------------------------------------}
function TEnumProcess.Get(AProcessId : Cardinal) : TProcessItem;
var AItem : TProcessItem;
I : Integer;
begin
result := nil;
///
for I := 0 to self.Items.count -1 do begin
AItem := self.Items.Items[I];
if NOT Assigned(AItem) then
continue;
///
if (AItem.ProcessId = AProcessId) then begin
result := AItem;
Break;
end;
end;
end;
function TEnumProcess.Get(AName : String) : TProcessItem;
var AItem : TProcessItem;
I : Integer;
begin
result := nil;
///
for I := 0 to self.Items.count -1 do begin
AItem := self.Items.Items[I];
if NOT Assigned(AItem) then
continue;
///
if (AItem.Name.ToLower = AName.ToLower) then begin
result := AItem;
Break;
end;
end;
end;
{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Main
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
{-------------------------------------------------------------------------------
Suspend Threads of target process.
-------------------------------------------------------------------------------}
function SuspendThreadsByProcessId(AProcessId : Cardinal) : Boolean;
var AItem : TProcessItem;
AThreadId : Cardinal;
I : Integer;
AThread : THandle;
begin
result := False;
///
if NOT Assigned(LProcesses) then
Exit();
AItem := LProcesses.Get(AProcessId);
if NOT Assigned(AItem) then
Exit();
///
if (AItem.Threads.count = 0) then
Exit();
///
for I := 0 to AItem.Threads.Count -1 do begin
AThreadId := AItem.Threads.Items[I];
///
AThread := OpenThread(THREAD_SUSPEND_RESUME, False, AThreadId);
if (AThread = 0) then
continue;
try
WriteLn(Format('Suspending: %s(%d), Thread Id: %d...', [
AItem.Name,
AItem.ProcessId,
AThreadId
]));
WinAPI.Windows.SuspendThread(AThread);
result := True;
finally
CloseHandle(AThread);
end;
end;
end;
{-------------------------------------------------------------------------------
FindWindow API Example
-------------------------------------------------------------------------------}
function method_FindWindow() : Boolean;
var AHandle : THandle;
AProcessId : Cardinal;
AClassName : String;
AWindowName : String;
pClassName : Pointer;
pWindowName : Pointer;
begin
result := False;
///
for AClassName in LFindWindowSignatures.Keys do begin
if NOT LFindWindowSignatures.TryGetValue(AClassName, AWindowName) then
continue;
///
pClassName := nil;
pWindowName := nil;
if NOT AClassName.isEmpty then
pClassName := PWideChar(AClassName);
if NOT AWindowName.isEmpty then
pWindowName := PWideChar(AWindowName);
AHandle := FindWindowW(pClassName, pWindowName);
if (AHandle > 0) then begin
GetWindowThreadProcessId(AHandle, @AProcessId);
if (AProcessId > 0) then
SuspendThreadsByProcessId(AProcessId);
///
result := True;
end;
end;
end;
{-------------------------------------------------------------------------------
Find Process Example (Uses the TEnumProcess Class) - See above
-------------------------------------------------------------------------------}
function method_FindProcess() : Boolean;
var AItem : TProcessItem;
AName : String;
I : Integer;
begin
result := False;
///
for I := 0 to LProcessNameSignatures.count -1 do begin
AName := LProcessNameSignatures.Strings[I];
AItem := LProcesses.Get(AName);
if (NOT Assigned(AItem)) then
continue;
///
SuspendThreadsByProcessId(AItem.ProcessId);
///
result := True;
end;
end;
{-------------------------------------------------------------------------------
___entry
-------------------------------------------------------------------------------}
begin
try
LProcesses := TEnumProcess.Create();
try
// FindWindow API
LFindWindowSignatures := TDictionary<String, String>.Create();
try
{
...
@Param1: ClassName (Empty = NULL)
@Param2: WindowName (Empty = NULL)
Add your own signatures bellow...
}
LFindWindowSignatures.Add('OLLYDBG', '');
{
...
}
method_FindWindow();
finally
if Assigned(LFindWindowSignatures) then
FreeAndNil(LFindWindowSignatures);
end;
// Find by Process Name
LProcessNameSignatures := TStringList.Create();
try
{
...
@Param1: Process Name (Example: OllyDbg.exe) - Case Insensitive
Add your own signatures bellow...
}
LProcessNameSignatures.Add('ImmunityDebugger.exe');
{
...
}
method_FindProcess();
finally
if Assigned(LProcessNameSignatures) then
FreeAndNil(LProcessNameSignatures);
end;
finally
if Assigned(LProcesses) then
FreeAndNil(LProcesses);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Author: Jean-Pierre LESUEUR (DarkCoderSc) / Target Platform: Windows
DWORD g_dwDebuggerProcessId = -1;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD dwProcessId = *(PDWORD)lParam;
DWORD dwWindowProcessId;
GetWindowThreadProcessId(hwnd, &dwWindowProcessId);
if (dwProcessId == dwWindowProcessId)
{
std::wstring wsWindowTitle{ string_heper::ToLower(std::wstring(GetWindowTextLengthW(hwnd) + 1, L'\0')) };
GetWindowTextW(hwnd, &wsWindowTitle[0], wsWindowTitle.size());
if (string_heper::FindSubstringW(wsWindowTitle, L"dbg") ||
string_heper::FindSubstringW(wsWindowTitle, L"debugger"))
{
g_dwDebuggerProcessId = dwProcessId;
return FALSE;
}
return FALSE;
}
return TRUE;
}
bool IsDebuggerProcess(DWORD dwProcessId) const
{
EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&dwProcessId));
return g_dwDebuggerProcessId == dwProcessId;
}
bool SuspendDebuggerThread()
{
THREADENTRY32 ThreadEntry = { 0 };
ThreadEntry.dwSize = sizeof(THREADENTRY32);
DWORD dwParentProcessId = process_helper::GetParentProcessId(GetCurrentProcessId());
if (-1 == dwParentProcessId)
return false;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwParentProcessId);
if(Thread32First(hSnapshot, &ThreadEntry))
{
do
{
if ((ThreadEntry.th32OwnerProcessID == dwParentProcessId) && IsDebuggerProcess(dwParentProcessId))
{
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ThreadEntry.th32ThreadID);
if (hThread)
SuspendThread(hThread);
break;
}
} while(Thread32Next(hSnapshot, &ThreadEntry));
}
if (hSnapshot)
CloseHandle(hSnapshot);
return false;
}
Author: External / Target Platform: Windows