Skip to content

CheckRemoteDebuggerPresent

Malware calls CheckRemoteDebuggerPresent (or NtQueryInformationProcess with ProcessDebugPort) to detect a user-mode debugger attached to the process.

CheckRemoteDebuggerPresent is a kernel32.dll wrapper that sets its output parameter to (BOOL)-1 (i.e. TRUE) when a user-mode debugger is attached to the specified process. Under the hood it calls NtQueryInformationProcess with ProcessInformationClass = ProcessDebugPort (7): the kernel returns a non-zero debug-port handle when a debugger is present.

By calling NtQueryInformationProcess directly, malware can achieve the same result without importing the obvious CheckRemoteDebuggerPresent symbol.

How it works

High-level wrapper

c
#include <windows.h>

BOOL RemoteDebuggerCheck(void)
{
    BOOL bDebuggerPresent = FALSE;
    CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent);
    return bDebuggerPresent;
}

Direct NtQueryInformationProcess call (ProcessDebugPort)

c
#include <windows.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI *pfnNtQIP)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);

BOOL NtQueryDebugPort(void)
{
    HANDLE hNtdll = GetModuleHandleW(L"ntdll.dll");
    pfnNtQIP NtQIP = (pfnNtQIP)GetProcAddress(hNtdll, "NtQueryInformationProcess");
    DWORD_PTR dwPort = 0;
    NtQIP(GetCurrentProcess(), (PROCESSINFOCLASS)7, &dwPort, sizeof(dwPort), NULL);
    return dwPort != 0;
}

A related class, ProcessDebugFlags (0x1F), returns 0 when a debugger is present (inverted semantics). ProcessDebugObjectHandle (0x1E) returns a non-NULL handle while being debugged.

Detection & bypass

During debugging:

  • ScyllaHide intercepts NtQueryInformationProcess and patches the output for ProcessDebugPort, ProcessDebugFlags, and ProcessDebugObjectHandle automatically.
  • Manual hook: use a debugger plugin or inline patch at the call site to force dwPort = 0.
  • Frida: Interceptor.attach(Module.getExportByName('ntdll.dll', 'NtQueryInformationProcess'), ...) — check args[1] for class 7 and zero the output buffer.

Static / automated detection:

  • CAPA rule U0121 / B0001.002: flags imports or dynamic calls to CheckRemoteDebuggerPresent and NtQueryInformationProcess.
  • YARA: string search for "NtQueryInformationProcess" in PEs under 1 MB; combine with the constant 0x07 in nearby bytes for higher confidence.
  • Technique IDs: U0120 (NtQueryInformationProcess), U0121 (CheckRemoteDebuggerPresent).
Votes

Comments(0)