FindWindow Debugger Detection
Malware enumerates top-level windows looking for the class names of known analyst tools such as OllyDbg, x64dbg, WinDbg and Process Monitor to detect an analysis environment.
Reverse-engineering tools register windows with well-known class names. Malware uses FindWindowW/FindWindowExW (a direct lookup by class) or EnumWindows (walk every top-level window and compare) to spot those class names. If a debugger, disassembler, or monitoring tool window exists, the sample assumes it is being analysed and refuses to run or alters its behaviour.
This is a beginner-level GUI-based check that requires no special privileges and is trivial to add to any sample.
How it works
The malware queries for each known class name; a non-NULL handle means the tool is running.
#include <windows.h>
const wchar_t *kToolClasses[] = {
L"OLLYDBG", // OllyDbg
L"WinDbgFrameClass", // WinDbg
L"x64dbg", // x64dbg / x32dbg
L"ID", // Immunity Debugger
L"PROCMON_WINDOW_CLASS", // Process Monitor
};
BOOL AnalysisToolPresent(void)
{
for (int i = 0; i < 5; i++)
if (FindWindowW(kToolClasses[i], NULL) != NULL)
return TRUE;
return FALSE;
}The EnumWindows variant passes a callback that calls GetClassNameW on every window and string-compares against the same list, which avoids importing FindWindowW directly and is harder to spot statically.
Detection & bypass
- Static — Grep in IDA/Ghidra for imports of
FindWindowW/FindWindowExW/EnumWindows/GetClassNameW, and for the literal class stringsOLLYDBG,WinDbgFrameClass,x64dbg,ID,PROCMON_WINDOW_CLASS. These strings are often obfuscated, so also check for stack-string construction nearFindWindowcalls. - Dynamic — In x64dbg, breakpoint on
user32!FindWindowWanduser32!EnumWindows; inspect the class-name argument to learn exactly what the sample looks for. The return value (rax) reveals whether a match was found. - Patch / bypass — Rename the debugger window/class so the lookup misses (x64dbg supports changing its window title/class via plugins), or hook
FindWindowW/EnumWindows/GetClassNameWto return NULL/no-match. Simplest: NOP or invert the conditional jump that acts on the result. - Tools — ScyllaHide and HideWindow-style x64dbg plugins that hide or rename the debugger window; Frida
InterceptoronFindWindowW/EnumWindows; running analysis tools under renamed window classes.