EpochZero Learn
EpochZero LearnMulti-Domain Tech Learning Hub
Courses
LeaderboardAbout
Dashboard
EpochZero
EpochZero Learn
Multi-Domain Tech Learning Hub

Structured learning for Reverse Engineering, Cloud Security, Cryptography, and Web Development. Articles, videos, tests, and peer discussion.

Learn

  • Learning Path
  • All Articles
  • Video Lessons
  • Podcast
  • eBooks & PDFs
  • Question Banks
  • Cheatsheets
  • MCQ Banks

Tests & Forum

  • All Tests
  • REMA Tests
  • Cloud Tests
  • Forum
  • REMA Forum
  • Cloud Forum
  • Crypto Forum
  • Web Dev Forum

Campus

  • REMA Club
  • Full Stack Dev Club
  • Extension Activity
  • Events
  • CTF Competitions
  • Workshops
  • Industrial Visits

Platform

  • Dashboard
  • Leaderboard
  • About
  • Verify Certificate

© 2026 EpochZero Learn. Educational content for learning purposes.

Course Instructor: Ashish Revar

All articles
Educationanti-debugpebscyllahide

Debugger Detection Techniques

Every major debugger detection technique — API-based, PEB-based, timing, hardware breakpoint scanning, TLS callbacks, trap flag, and interrupt-based — with the exact bypass for each.

Ashish Revar12 May 202620 min read2 views

Sign in to mark this article as read and track your progress.

Related to this topic

Continue learning

Listen

The Art of Deception: Unmasking Anti-Analysis & Evasion Techniques

A technical examination of the self-defence mechanisms used by self-defending malware — how threats detect sandboxes, sabotage debuggers, and hide from automated analysis, and how analysts defeat each technique.

Reference material

eBook
REMA eBook 2026
v1.0
Open resource
Cheatsheet
REMA Cheatsheet 2026
v1.0
Open resource
MCQ Bank
REMA MCQ Bank 2026
v1.0
Open resource
Question Bank
REMA Question Bank 2026
v1.0
Open resource

External references

ScyllaHide — Complete Anti-Debug Bypass Plugin

Open-source x64dbg plugin defeating PEB checks, NtQueryInformationProcess, timing, and debug register queries simultaneously.

tool
MITRE ATT&CK — Debugger Evasion (T1622)

ATT&CK technique for debugger evasion with documented real-world procedure examples from threat actor tools.

reference
More articlesTest your knowledge

Overview

When a debugger attaches to a process, the OS modifies several internal data structures. Malware queries these structures to determine whether it is being analysed. Debugger detection is like a suspect checking the rear-view mirror for police cars. Some checks are obvious; others subtle. The analyst''s job is to be the unmarked car that does not trip any of these checks.

API-Based Detection

The simplest checks call Windows API functions that directly report debugger presence.

IsDebuggerPresent

Reads the BeingDebugged byte at offset 0x02 in the Process Environment Block (PEB).

CALL  IsDebuggerPresent   ; returns 1 (debugger) or 0 (clean) in EAX
TEST  EAX, EAX
JNZ   exit_quietly        ; jump if debugger detected

Bypass options:

  1. Step over the CALL, set EAX = 0 in the register panel, continue
  2. Navigate to PEB+0x02 in the dump, change byte from 01 to 00
  3. ScyllaHide → hooks IsDebuggerPresent to always return 0

CheckRemoteDebuggerPresent

Calls NtQueryInformationProcess internally with class ProcessDebugPort (0x07).

LEA   EAX, [EBP+bDebuggerPresent]
PUSH  EAX                 ; output: pointer to BOOL
PUSH  GetCurrentProcess()
CALL  CheckRemoteDebuggerPresent

Bypass: ScyllaHide patches the output parameter to FALSE automatically.

NtQueryInformationProcess

Three information classes reveal debugger presence:

ClassValueWhat It Returns
ProcessDebugPort0x07Non-zero if user-mode debugger attached
ProcessDebugFlags0x1F0 if debugger attached (inverted logic)
ProcessDebugObjectHandle0x1ENon-null handle if debugger attached

Bypass: ScyllaHide hooks all three classes. Manual bypass: set breakpoint on NtQueryInformationProcess, modify return buffer to expected clean values.

PEB-Based Detection

The Process Environment Block contains several fields that leak debugger information without calling any API.

BeingDebugged (PEB+0x02)

Set to 1 by Windows when a debugger attaches.

MOV  EAX, FS:[30h]        ; EAX = PEB base address
MOV  AL, [EAX+2]          ; AL = BeingDebugged flag
TEST AL, AL
JNZ  debugger_detected

Bypass: In x64dbg, open Memory Map → find PEB → go to offset 0x02 → change byte to 00.

NtGlobalFlag (PEB+0x68)

When a process is created by a debugger, Windows sets three heap debug flags in NtGlobalFlag:

  • FLG_HEAP_ENABLE_TAIL_CHECK (0x10)
  • FLG_HEAP_ENABLE_FREE_CHECK (0x20)
  • FLG_HEAP_VALIDATE_PARAMETERS (0x40)

Combined value: 0x70

MOV  EAX, FS:[30h]        ; PEB base
CMP  DWORD PTR [EAX+68h], 70h   ; check NtGlobalFlag
JE   debugger_detected

Bypass: Set PEB+0x68 to 0x00 in the dump. Or set environment variable _NO_DEBUG_HEAP=1 before launching the sample — prevents heap flags from being set.

ProcessHeap Flags

When created under a debugger, heap headers contain non-standard flag values. The check reads directly from the heap structure:

MOV  EAX, FS:[30h]        ; PEB
MOV  EAX, [EAX+18h]       ; ProcessHeap pointer
CMP  DWORD PTR [EAX+0Ch], 2  ; Flags field (normally 2, debug = 50000062h)
JNE  debugger_detected

Bypass: _NO_DEBUG_HEAP=1 environment variable, or ScyllaHide heap flag patching.

Timing-Based Detection

A debugged process runs slower due to single-stepping overhead. Malware measures execution time between two points and exits if the elapsed time exceeds a threshold.

Timing MethodResolutionBypass
RDTSC instructionCPU cyclesScyllaHide RDTSC hook; NOP the comparison
QueryPerformanceCounterSub-microsecondModify return value; NOP check
GetTickCountMillisecondsModify return value; NOP comparison
timeGetTimeMillisecondsModify return value
RDTSC                     ; first timestamp in EDX:EAX
MOV  [t1], EAX
; ... code being timed ...
RDTSC                     ; second timestamp
SUB  EAX, [t1]            ; elapsed cycles
CMP  EAX, 0x9999999       ; threshold check
JA   exit_debugger        ; too slow → debugger present

NOP bypass: select the JA exit_debugger instruction in x64dbg → right-click → Binary → Fill with NOPs.

Hardware and Interrupt Detection

0xCC Self-Scan (Software Breakpoint Detection)

Malware scans its own code region for 0xCC bytes (INT 3 opcode — the software breakpoint):

    mov  ecx, function_length
    lea  esi, [function_start]
scan_loop:
    cmp  byte ptr [esi], 0CCh    ; look for INT 3
    je   breakpoint_detected
    inc  esi
    loop scan_loop

Bypass: Use hardware breakpoints (DR0–DR3) instead of software breakpoints — they do not write 0xCC into code.

Debug Register Detection

Malware reads DR0–DR3 via GetThreadContext or a SEH exception handler. Non-zero values indicate hardware breakpoints.

Bypass: ScyllaHide clears debug registers in returned context structures automatically.

TLS Callbacks (Pre-Entry-Point Execution)

Thread Local Storage callbacks execute before the debugger-visible entry point. Anti-debug checks placed here run before the analyst has a chance to set breakpoints.

Bypass: In x64dbg → Options → Events → check "Break on TLS Callback". The debugger will pause at each TLS callback before it executes.

Trap Flag (Single-Step Exception)

PUSHFD                    ; save EFLAGS
OR   DWORD PTR [ESP], 100h  ; set Trap Flag (TF)
POPFD                     ; restore with TF set
; next instruction causes single-step exception
; if SEH handler fires: no debugger
; if debugger intercepts: debugger detected

Bypass: Configure x64dbg to pass single-step exceptions to the program: Options → Preferences → Exceptions → add single-step to the "pass to program" list.

INT 2D Anti-Debug

INT 2D is a kernel-mode debugger interrupt. Under a user-mode debugger, it causes a one-byte skip in the instruction stream — the byte following INT 2D is skipped.

INT  2Dh                  ; if debugger: next byte skipped
NOP                       ; becomes this instruction under debugger

Bypass: ScyllaHide handles INT 2D. Manual bypass: NOP out the INT 2D instruction.

Bypass Priority

Step 1: Enable ScyllaHide VMProtect profile → defeats 80% of checks
Step 2: Set _NO_DEBUG_HEAP=1 → defeats heap-based checks
Step 3: Configure x64dbg exception passthrough → defeats SEH/TF checks
Step 4: Use hardware breakpoints exclusively → defeats 0xCC scan
Step 5: Enable "Break on TLS Callback" → defeats TLS-based checks
Step 6: Manually patch remaining checks as encountered