(Python) Detecting Window with FindWindow API by Jean-Pierre LESUEUR

Created the Wednesday 02 September 2020. Updated 3 years, 7 months ago.

Description:

Feel free to edit both fw_debuggers and contains_in_title to extend the search of known debuggers.

Code

            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)