Description
Feel free to edit both fw_debuggers
and contains_in_title
to extend the search of known debuggers.
import ctypes
import os
from ctypes.wintypes import BOOL, HWND, LPARAM,\
LPWSTR, INT, MAX_PATH,\
LPDWORD, DWORD, HANDLE,\
HMODULE
def found(description, hwnd):
"""
When a Window handle is found it will output to console several information about spotted process.
:param description: Description of found object.
:param hwnd: Handle of found object.
"""
lpdwProcessId = ctypes.c_ulong()
output = "-" * 60 + "\r\n"
output += description + "\r\n"
output += "-" * 60 + "\r\n"
output += f"Handle: {hwnd}\r\n"
_GetWindowThreadProcessId(hwnd, ctypes.byref(lpdwProcessId))
if (lpdwProcessId is not None) and (lpdwProcessId.value > 0):
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010
procHandle = ctypes.windll.kernel32.OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
False,
lpdwProcessId.value
)
if procHandle > 0:
output += f"Process Id: {lpdwProcessId.value}\r\n"
lpFilename = ctypes.create_unicode_buffer(MAX_PATH)
if _GetModuleFileNameEx(procHandle, 0, lpFilename, MAX_PATH) > 0:
path, process_name = os.path.split(lpFilename.value)
output += f"Process Name: {process_name}\r\n"
output += f"Image Path: {path}\r\n"
ctypes.windll.kernel32.CloseHandle(procHandle)
output += "-" * 60 + "\r\n\r\n"
print(output)
def enum_window_proc(hwnd, lparam):
"""
EnumWindows API CallBack
:param hwnd: Current Window Handle
:param lparam: Not used in our case
:return: Always True in our case
"""
if hwnd > 0:
nMaxCount = ctypes.windll.user32.GetWindowTextLengthW(hwnd)+1
if nMaxCount > 0:
lpWindowName = ctypes.create_unicode_buffer(nMaxCount)
if _GetWindowText(hwnd, lpWindowName, nMaxCount) > 0:
for description, in_title in contains_in_title:
if in_title in lpWindowName.value:
found(description, hwnd)
return True
if __name__ == '__main__':
'''
Description | Window Class Name (lpClassName) | Window Title (lpWindowName)
'''
fw_debuggers = [
("OllyDbg", "OLLYDBG", None),
("x64dbg (x64)", None, "x64dbg"),
("x32dbg (x32)", None, "x32dbg"),
# ......... #
]
'''
Description | Text contained in debugger title.
'''
contains_in_title = [
("Immunity Debugger", "Immunity Debugger"),
# ......... #
]
# Define GetWindowThreadProcessId API
_GetWindowThreadProcessId = ctypes.windll.user32.GetWindowThreadProcessId
_GetWindowThreadProcessId.argtypes = HWND, LPDWORD
_GetWindowThreadProcessId.restype = DWORD
# Define GetModuleFileNameEx API
_GetModuleFileNameEx = ctypes.windll.psapi.GetModuleFileNameExW
_GetModuleFileNameEx.argtypes = HANDLE, HMODULE, LPWSTR, DWORD
_GetModuleFileNameEx.restype = DWORD
'''
Search for Debuggers using the FindWindowW API with ClassName /+ WindowName
'''
for description, lpClassName, lpWindowName in fw_debuggers:
handle = ctypes.windll.user32.FindWindowW(lpClassName, lpWindowName)
if handle > 0:
found(description, handle)
'''
Search for Debuggers using EnumWindows API.
We first list all Windows titles then search for a debugger title pattern.
This is useful against debuggers or tools without specific title / classname.
'''
# Define EnumWindows API
lpEnumFunc = ctypes.WINFUNCTYPE(
BOOL,
HWND,
LPARAM
)
_EnumWindows = ctypes.windll.user32.EnumWindows
_EnumWindows.argtypes = [
lpEnumFunc,
LPARAM
]
# Define GetWindowTextW API
_GetWindowText = ctypes.windll.user32.GetWindowTextW
_GetWindowText.argtypes = HWND, LPWSTR, INT
_GetWindowText.restype = INT
# Enumerate Windows through Windows API
_EnumWindows(lpEnumFunc(enum_window_proc), 0)
Author: Jean-Pierre LESUEUR (DarkCoderSc) / Target Platform: Windows
Description
You can build this snippet as a classic Delphi Console Application and add your own signatures for detecting debuggers and related tools.
program FindWindowAPI;
{$APPTYPE CONSOLE}
uses
System.SysUtils, WinAPI.Windows, Generics.Collections, psAPI;
{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TFindWindowSignature Class
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
type
TFindWindowSignature = class
private
FDescription : String;
FClassName : String;
FWindowName : String;
public
{@C}
constructor Create(ADescription, AClassName, AWindowName : String);
{@G}
property Description : String read FDescription;
property ClassName : String read FClassName;
property WindowName : String read FWindowName;
end;
{-------------------------------------------------------------------------------
___constructor
-------------------------------------------------------------------------------}
constructor TFindWindowSignature.Create(ADescription, AClassName, AWindowName : String);
begin
FDescription := ADescription;
FClassName := AClassName;
FWindowName := AWindowName;
end;
{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Main
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
var LFindWindowSignatures : TObjectList<TFindWindowSignature>;
LEnumWindowsSignatures : TDictionary<String, String>;
{-------------------------------------------------------------------------------
When a Window handle is found it will output to console several information
about spotted process.
-------------------------------------------------------------------------------}
procedure Found(ADescription : String; AHandle : THandle);
const CRLF = #13#10;
var AStdout_TXT : String;
AProcessId : Cardinal;
AProcessHandle : THandle;
ARet : DWORD;
pImagePath : PWideChar;
begin
try
AStdout_TXT := AStdout_TXT + StringOfChar('-', 60) + CRLF;
AStdout_TXT := AStdout_TXT + ADescription + CRLF;
AStdout_TXT := AStdout_TXT + StringOfChar('-', 60) + CRLF;
AStdout_TXT := AStdout_TXT + Format('Handle: %d%s', [AHandle, CRLF]);
GetWindowThreadProcessId(AHandle, @AProcessId);
if (AProcessId > 0) then begin
AProcessHandle := OpenProcess(
(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ),
False,
AProcessId
);
if (AProcessHandle > 0) then begin
AStdout_TXT := AStdout_TXT + Format('Process Id: %d%s', [AProcessId, CRLF]);
pImagePath := nil;
try
GetMem(pImagePath, (MAX_PATH * 2));
ARet := GetModuleFileNameExW(AProcessHandle, 0, pImagePath, (MAX_PATH * 2));
if (ARet > 0) then begin
AStdout_TXT := AStdout_TXT + Format('Process Name: %s%s', [ExtractFileName(String(pImagePath)), CRLF]);
AStdout_TXT := AStdout_TXT + Format('Image Path: %s%s', [ExtractFilePath(String(pImagePath)), CRLF]);
end;
finally
if Assigned(pImagePath) and (ARet > 0) then
FreeMem(pImagePath, ARet);
end;
end;
end;
AStdout_TXT := AStdout_TXT + StringOfChar('-', 60) + CRLF + CRLF;
///
finally
WriteLn(AStdout_TXT);
end;
end;
{-------------------------------------------------------------------------------
Find Debuggers by Window Name or Class Name using FindWindow API
-------------------------------------------------------------------------------}
function Locate_FindWindow() : Boolean;
var AFindWindowSignature : TFindWindowSignature;
i : Integer;
pClassName : Pointer;
pWindowName : Pointer;
AHandle : THandle;
begin
result := False;
///
for i := 0 to LFindWindowSignatures.Count -1 do begin
AFindWindowSignature := LFindWindowSignatures.Items[i];
if NOT Assigned(AFindWindowSignature) then
continue;
///
pClassName := nil;
pWindowName := nil;
if NOT AFindWindowSignature.ClassName.isEmpty then
pClassName := PWideChar(AFindWindowSignature.ClassName);
if NOT AFindWindowSignature.WIndowName.isEmpty then
pWindowName := PWideChar(AFindWindowSignature.WindowName);
AHandle := FindWindowW(pClassName, pWindowName);
if (AHandle > 0) then begin
Found(AFindWindowSignature.Description, AHandle);
///
result := True;
end;
end;
end;
{-------------------------------------------------------------------------------
Find Debuggers by Window Name (via Window Name Pattern) using EnumWindows API
-------------------------------------------------------------------------------}
function EnumWindowProc(AHandle : THandle; AParam : LPARAM) : BOOL; stdcall;
var AMaxCount : Integer;
AWindowName : String;
AOldLen : Cardinal;
APattern : String;
AKey : String;
begin
result := True;
///
if (AHandle = 0) then
Exit();
///
AMaxCount := GetWindowTextLength(AHandle) + 1;
if (AMaxCount = 0) then
Exit();
SetLength(AWindowName, AMaxCount); // Other technique instead of using GetMem / FreeMem a new Pointer.
try
if (GetWindowTextW(AHandle, PWideChar(AWindowName), AMaxCount) = 0) then
Exit();
///
AOldLen := Length(AWindowName);
for AKey {Description} in LEnumWindowsSignatures.keys do begin
if NOT LEnumWindowsSignatures.TryGetValue(AKey, APattern) then
continue;
AWindowName := StringReplace(AWindowName, APattern, '', []);
if (Length(AWindowName) <> AOldLen) then begin
Found(AKey, AHandle);
break;
end;
end;
finally
SetLength(AWindowName, 0);
end;
end;
function Locate_EnumWindows() : Boolean;
begin
EnumWindows(@EnumWindowProc, 0);
end;
{-------------------------------------------------------------------------------
Append FindWindow Technique Signature
-------------------------------------------------------------------------------}
procedure AppendFindWindowSignature(ADescription, AClassName, AWindowName : String);
var AFindWindowSignature : TFindWindowSignature;
begin
if NOT Assigned(LFindWindowSignatures) then
Exit();
///
AFindWindowSignature := TFindWindowSignature.Create(ADescription, AClassName, AWindowName);
LFindWindowSignatures.Add(AFindWindowSignature);
end;
{-------------------------------------------------------------------------------
___entry
-------------------------------------------------------------------------------}
begin
try
LFindWindowSignatures := TObjectList<TFindWindowSignature>.Create();
LEnumWindowsSignatures := TDictionary<String, String>.Create();
try
{
Configure debuggers signatures here for FindWindow API technique.
}
AppendFindWindowSignature('OllyDbg', 'OLLYDBG', '');
AppendFindWindowSignature('x64dbg (x64)', '', 'x64dbg');
AppendFindWindowSignature('x32dbg (x32)', '', 'x32dbg');
// ...
// AppendFindWindowSignature('...', '...', '...');
// ...
{
Configure debuggeers signatures here for EnumWindows API technique.
}
LEnumWindowsSignatures.Add('Immunity Debugger', 'Immunity Debugger');
// ...
// AEnumWindowsSignatures.Add('...', '...');
// ...
{
Fire !!!
}
Locate_FindWindow();
Locate_EnumWindows();
readln;
finally
if Assigned(LFindWindowSignatures) then
FreeAndNil(LFindWindowSignatures);
if Assigned(LEnumWindowsSignatures) then
FreeAndNil(LEnumWindowsSignatures);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Author: Jean-Pierre LESUEUR (DarkCoderSc) / Target Platform: Windows