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
#include <windows.h>
BOOL RemoteDebuggerCheck(void)
{
BOOL bDebuggerPresent = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent);
return bDebuggerPresent;
}Direct NtQueryInformationProcess call (ProcessDebugPort)
#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
NtQueryInformationProcessand patches the output forProcessDebugPort,ProcessDebugFlags, andProcessDebugObjectHandleautomatically. - 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'), ...)— checkargs[1]for class7and zero the output buffer.
Static / automated detection:
- CAPA rule U0121 / B0001.002: flags imports or dynamic calls to
CheckRemoteDebuggerPresentandNtQueryInformationProcess. - YARA: string search for
"NtQueryInformationProcess"in PEs under 1 MB; combine with the constant0x07in nearby bytes for higher confidence. - Technique IDs: U0120 (NtQueryInformationProcess), U0121 (CheckRemoteDebuggerPresent).