anti-debugging-techniques

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SKILL: Anti-Debugging Techniques — Detection & Bypass Playbook

SKILL:反调试技术——检测与绕过指南

AI LOAD INSTRUCTION: Expert anti-debug techniques across Linux and Windows. Covers ptrace, PEB flags, NtQueryInformationProcess, timing attacks, signal-based detection, TLS callbacks, VEH tricks, and all corresponding bypass methods. Base models often miss the distinction between user-mode and kernel-mode detection and the correct patching strategy for each.
AI加载说明:涵盖Linux和Windows平台的专业反调试技术,包括ptrace、PEB标志、NtQueryInformationProcess、时序攻击、基于信号的检测、TLS回调、VEH技巧,以及所有对应的绕过方法。基础模型通常会混淆用户态和内核态检测的区别,也无法给出每种场景对应的正确补丁策略。

0. RELATED ROUTING

0. 相关路由

  • code-obfuscation-deobfuscation when the binary also uses control flow flattening, VM protection, or string encryption
  • vm-and-bytecode-reverse when the anti-debug sits inside a custom VM dispatcher
  • symbolic-execution-tools when you want to symbolically skip anti-debug checks entirely
  • 若二进制文件还使用了控制流平坦化、VM保护或字符串加密,参考code-obfuscation-deobfuscation
  • 若反调试逻辑位于自定义VM分发器内部,参考vm-and-bytecode-reverse
  • 若你想通过符号执行完全跳过反调试检查,参考symbolic-execution-tools

Advanced Reference

进阶参考

Also load ANTI_DEBUG_MATRIX.md when you need:
  • Complete cross-reference matrix of technique × OS × detection method × bypass method
  • Per-technique reliability ratings and false-positive notes
  • Tool compatibility chart (GDB, x64dbg, WinDbg, Frida, ScyllaHide)
若你需要以下内容,请同时加载ANTI_DEBUG_MATRIX.md
  • 技术×操作系统×检测方法×绕过方法的完整交叉参考矩阵
  • 每项技术的可靠性评级和误报说明
  • 工具兼容性对照表(GDB, x64dbg, WinDbg, Frida, ScyllaHide)

Quick bypass picks

快速绕过方案

Detection ClassFirst BypassBackup
ptrace-based (Linux)
LD_PRELOAD
hook
ptrace()
→ return 0
Kernel module to hide tracer
PEB.BeingDebugged (Windows)Patch PEB byte at
fs:[0x30]+0x2
ScyllaHide auto-patch
Timing check (rdtsc)Conditional BP after rdtsc, fix registersFrida hook
rdtsc
return
IsDebuggerPresentNOP the call / hook return 0x64dbg built-in hide
INT 2D / UD2 exceptionSet VEH to handle gracefullyTitanHide driver

检测类别首选绕过方法备选方法
基于ptrace(Linux)
LD_PRELOAD
hook
ptrace()
→ return 0
内核模块隐藏调试器
PEB.BeingDebugged(Windows)修补
fs:[0x30]+0x2
位置的PEB字节
ScyllaHide自动补丁
时序检查(rdtsc)在rdtsc后设置条件断点,修复寄存器值Frida hook
rdtsc
返回值
IsDebuggerPresentNOP掉调用 / hook返回0x64dbg内置隐藏功能
INT 2D / UD2 异常设置VEH优雅处理TitanHide驱动

1. LINUX ANTI-DEBUG TECHNIQUES

1. Linux反调试技术

1.1 ptrace(PTRACE_TRACEME)

1.1 ptrace(PTRACE_TRACEME)

The classic self-attach: a process calls
ptrace(PTRACE_TRACEME, 0, 0, 0)
. If a debugger is already attached, the call fails (returns -1).
c
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
    exit(1); // debugger detected
}
Bypass methods:
MethodHow
LD_PRELOAD
shim
Compile shared lib:
long ptrace(int r, ...) { return 0; }
and set
LD_PRELOAD
Binary patchNOP the
ptrace
call or patch return value check
GDB catch
catch syscall ptrace
→ modify
$rax
to 0 on return
Kernel moduleHook
sys_ptrace
to allow multiple tracers
经典的自附加逻辑:进程调用
ptrace(PTRACE_TRACEME, 0, 0, 0)
,如果已有调试器附加,调用会失败(返回-1)。
c
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) {
    exit(1); // 检测到调试器
}
绕过方法
方法实现方式
LD_PRELOAD
垫片
编译共享库:
long ptrace(int r, ...) { return 0; }
并设置
LD_PRELOAD
环境变量
二进制补丁NOP掉
ptrace
调用或者修改返回值校验逻辑
GDB捕获
catch syscall ptrace
→ 返回时修改
$rax
为0
内核模块Hook
sys_ptrace
允许多个调试器附加

1.2 /proc/self/status — TracerPid

1.2 /proc/self/status — TracerPid

c
FILE *f = fopen("/proc/self/status", "r");
// parse TracerPid: if non-zero → debugger attached
Bypass: Mount a FUSE filesystem over
/proc/self
, or
LD_PRELOAD
hook
fopen
/
fread
to filter
TracerPid
to 0.
c
FILE *f = fopen("/proc/self/status", "r");
// 解析TracerPid:如果非零 → 有调试器附加
绕过:在
/proc/self
上挂载FUSE文件系统,或者通过
LD_PRELOAD
hook
fopen
/
fread
TracerPid
过滤为0。

1.3 Timing Checks (rdtsc / clock_gettime)

1.3 时序检查(rdtsc / clock_gettime)

Measures elapsed time between two points; debugger single-stepping causes noticeable delay.
asm
rdtsc
mov ebx, eax       ; save low 32 bits
; ... protected code ...
rdtsc
sub eax, ebx
cmp eax, 0x1000    ; threshold
ja  debugger_detected
Bypass: Set hardware breakpoint after second
rdtsc
, modify
eax
to pass the comparison. Or use Frida to replace the timing function.
测量两个节点之间的耗时,调试器单步执行会产生明显的延迟。
asm
rdtsc
mov ebx, eax       ; 保存低32位
; ... 受保护代码 ...
rdtsc
sub eax, ebx
cmp eax, 0x1000    ; 阈值
ja  debugger_detected
绕过:在第二个
rdtsc
后设置硬件断点,修改
eax
值通过比较。或者使用Frida替换计时函数。

1.4 Signal-Based Detection (SIGTRAP)

1.4 基于信号的检测(SIGTRAP)

c
volatile int caught = 0;
void handler(int sig) { caught = 1; }
signal(SIGTRAP, handler);
raise(SIGTRAP);
if (!caught) exit(1); // debugger swallowed the signal
When a debugger is attached,
SIGTRAP
is consumed by the debugger rather than delivered to the handler. Bypass: In GDB, use
handle SIGTRAP nostop pass
to forward the signal.
c
volatile int caught = 0;
void handler(int sig) { caught = 1; }
signal(SIGTRAP, handler);
raise(SIGTRAP);
if (!caught) exit(1); // 调试器吞噬了信号
当有调试器附加时,
SIGTRAP
会被调试器消费而不会传递给处理函数。绕过:在GDB中使用
handle SIGTRAP nostop pass
转发信号。

1.5 /proc/self/maps & LD_PRELOAD Detection

1.5 /proc/self/maps & LD_PRELOAD检测

Checks for injected libraries or memory regions characteristic of debuggers/instrumentation.
c
FILE *f = fopen("/proc/self/maps", "r");
while (fgets(buf, sizeof(buf), f)) {
    if (strstr(buf, "frida") || strstr(buf, "LD_PRELOAD"))
        exit(1);
}
Bypass: Hook
fopen("/proc/self/maps")
to return a filtered version, or rename Frida's agent library.
检查是否存在调试器/插桩工具注入的库或特征内存区域。
c
FILE *f = fopen("/proc/self/maps", "r");
while (fgets(buf, sizeof(buf), f)) {
    if (strstr(buf, "frida") || strstr(buf, "LD_PRELOAD"))
        exit(1);
}
绕过:Hook
fopen("/proc/self/maps")
返回过滤后的内容,或者重命名Frida的agent库。

1.6 Environment Variable Checks

1.6 环境变量检查

Some protections check for
LD_PRELOAD
,
LINES
,
COLUMNS
(set by GDB's terminal), or debugger-specific env vars.
Bypass: Unset suspicious env vars before launch, or hook
getenv()
.

部分保护机制会检查
LD_PRELOAD
LINES
COLUMNS
(GDB终端设置)或者调试器专属环境变量。
绕过:启动前清除可疑环境变量,或者hook
getenv()

2. WINDOWS ANTI-DEBUG TECHNIQUES

2. Windows反调试技术

2.1 IsDebuggerPresent / CheckRemoteDebuggerPresent

2.1 IsDebuggerPresent / CheckRemoteDebuggerPresent

c
if (IsDebuggerPresent()) ExitProcess(1);

BOOL debugged = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &debugged);
if (debugged) ExitProcess(1);
Bypass: Hook
kernel32!IsDebuggerPresent
to return 0, or patch PEB directly.
c
if (IsDebuggerPresent()) ExitProcess(1);

BOOL debugged = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &debugged);
if (debugged) ExitProcess(1);
绕过:Hook
kernel32!IsDebuggerPresent
返回0,或者直接修改PEB。

2.2 PEB Flags

2.2 PEB标志

FieldOffset (x64)Debugged ValueNormal Value
BeingDebugged
PEB+0x02
10
NtGlobalFlag
PEB+0xBC
0x70
(FLG_HEAP_*)
0
ProcessHeap.Flags
Heap+0x40
0x40000062
0x00000002
ProcessHeap.ForceFlags
Heap+0x44
0x40000060
0
asm
mov rax, gs:[0x60]    ; PEB
movzx eax, byte [rax+0x02]  ; BeingDebugged
test eax, eax
jnz debugger_detected
Bypass: Zero all four fields. ScyllaHide does this automatically.
字段偏移(x64)被调试时值正常时值
BeingDebugged
PEB+0x02
10
NtGlobalFlag
PEB+0xBC
0x70
(FLG_HEAP_*)
0
ProcessHeap.Flags
Heap+0x40
0x40000062
0x00000002
ProcessHeap.ForceFlags
Heap+0x44
0x40000060
0
asm
mov rax, gs:[0x60]    ; PEB
movzx eax, byte [rax+0x02]  ; BeingDebugged
test eax, eax
jnz debugger_detected
绕过:将这四个字段清零,ScyllaHide会自动完成该操作。

2.3 NtQueryInformationProcess

2.3 NtQueryInformationProcess

InfoClassValueDebugged Return
ProcessDebugPort
0x07Non-zero port
ProcessDebugObjectHandle
0x1EValid handle
ProcessDebugFlags
0x1F0 (inverted!)
Bypass: Hook
ntdll!NtQueryInformationProcess
to return clean values per info class.
信息类被调试时返回值
ProcessDebugPort
0x07非零端口
ProcessDebugObjectHandle
0x1E有效句柄
ProcessDebugFlags
0x1F0(反向判断!)
绕过:Hook
ntdll!NtQueryInformationProcess
根据信息类返回正常数值。

2.4 Hardware Breakpoint Detection

2.4 硬件断点检测

c
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(GetCurrentThread(), &ctx);
if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3)
    ExitProcess(1);
Bypass: Hook
GetThreadContext
to zero DR0–DR3, or use
NtSetInformationThread(ThreadHideFromDebugger)
preemptively (ironically, the anti-debug technique itself).
c
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(GetCurrentThread(), &ctx);
if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3)
    ExitProcess(1);
绕过:Hook
GetThreadContext
将DR0–DR3清零,或者提前调用
NtSetInformationThread(ThreadHideFromDebugger)
(讽刺的是,这本身就是反调试技术)。

2.5 INT 2D / INT 3 / UD2 Exception Tricks

2.5 INT 2D / INT 3 / UD2 异常技巧

INT 2D
is the kernel debug service interrupt. Without a debugger, it raises
STATUS_BREAKPOINT
; with a debugger, behavior differs (byte skipping).
asm
xor eax, eax
int 2dh
nop          ; debugger may skip this byte
; ... divergent execution path ...
Bypass: Handle in VEH or patch the interrupt instruction.
INT 2D
是内核调试服务中断。没有调试器时会抛出
STATUS_BREAKPOINT
;有调试器时行为会不同(字节跳过)。
asm
xor eax, eax
int 2dh
nop          ; 调试器可能跳过该字节
; ... 执行路径分歧 ...
绕过:在VEH中处理或者补丁中断指令。

2.6 TLS Callbacks

2.6 TLS回调

TLS callbacks execute before
main()
/
WinMain()
. Anti-debug checks placed here run before the debugger's initial break.
Bypass: In x64dbg, set "Break on TLS Callbacks" option. In WinDbg, use
sxe ld
to break on module load.
TLS回调会在
main()
/
WinMain()
之前执行,放在这里的反调试检查会在调试器初始断点之前运行。
绕过:在x64dbg中开启“TLS回调时中断”选项,在WinDbg中使用
sxe ld
在模块加载时中断。

2.7 NtSetInformationThread(ThreadHideFromDebugger)

2.7 NtSetInformationThread(ThreadHideFromDebugger)

c
NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);
After this call, the thread becomes invisible to the debugger — breakpoints and single-stepping stop working silently.
Bypass: Hook
NtSetInformationThread
to NOP when
ThreadInfoClass == 0x11
.
c
NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);
调用后线程对调试器不可见,断点和单步执行会静默失效。
绕过:Hook
NtSetInformationThread
,当
ThreadInfoClass == 0x11
时NOP掉调用。

2.8 VEH-Based Detection

2.8 基于VEH的检测

Registers a Vectored Exception Handler that checks
EXCEPTION_RECORD
for debugger-specific behavior (single-step flag, guard page violations with debugger semantics).
Bypass: Understand the VEH logic and ensure the exception chain behaves identically to non-debugged execution.

注册向量化异常处理程序,检查
EXCEPTION_RECORD
中调试器专属行为(单步标志、符合调试器特征的守卫页违规)。
绕过:理解VEH逻辑,确保异常链行为和非调试状态完全一致。

3. ADVANCED MULTI-LAYER TECHNIQUES

3. 高级多层技术

3.1 Self-Debugging (fork + ptrace)

3.1 自调试(fork + ptrace)

The process forks a child that attaches to the parent via ptrace. If an external debugger is already attached, the child's ptrace fails.
c
pid_t child = fork();
if (child == 0) {
    if (ptrace(PTRACE_ATTACH, getppid(), 0, 0) == -1)
        kill(getppid(), SIGKILL);
    else
        ptrace(PTRACE_DETACH, getppid(), 0, 0);
    _exit(0);
}
wait(NULL);
Bypass: Patch the
fork()
return or kill/detach the watchdog child.
进程fork出子进程,子进程通过ptrace附加到父进程。如果已有外部调试器附加,子进程的ptrace会失败。
c
pid_t child = fork();
if (child == 0) {
    if (ptrace(PTRACE_ATTACH, getppid(), 0, 0) == -1)
        kill(getppid(), SIGKILL);
    else
        ptrace(PTRACE_DETACH, getppid(), 0, 0);
    _exit(0);
}
wait(NULL);
绕过:修改
fork()
返回值,或者杀死/解绑监控子进程。

3.2 Multi-Process Debugging Detection

3.2 多进程调试检测

Parent and child cooperatively check each other's debug state, creating a mutual-watch pattern.
Bypass: Attach to both processes (GDB
follow-fork-mode
, or two debugger instances).
父进程和子进程合作检查对方的调试状态,形成互相监控的模式。
绕过:同时附加到两个进程(GDB使用
follow-fork-mode
,或者启动两个调试器实例)。

3.3 Timing-Based with Multiple Checkpoints

3.3 多检查点时序检测

Distributes timing checks across multiple functions, comparing cumulative drift. Single patches fail because the total still exceeds threshold.
Bypass: Frida
Interceptor.replace
all timing sources (
rdtsc
,
clock_gettime
,
QueryPerformanceCounter
) to return controlled values.
时序检查分散在多个函数中,对比累计偏差。单次补丁会失效,因为总耗时仍然超过阈值。
绕过:使用Frida
Interceptor.replace
替换所有计时源(
rdtsc
clock_gettime
QueryPerformanceCounter
)返回可控值。

3.4 Nanomite / INT3 Patching

3.4 Nanomite / INT3补丁

Original conditional jumps are replaced with
INT3
(0xCC). A parent debugger process handles each
INT3
, evaluates the condition, and sets the child's EIP accordingly.
Bypass: Reconstruct the original jump table by tracing all
INT3
handlers, then patch the binary.

原始条件跳转被替换为
INT3
(0xCC),父调试器进程处理每个
INT3
,判断条件后设置子进程的EIP。
绕过:跟踪所有
INT3
处理逻辑重建原始跳转表,然后补丁二进制文件。

4. COUNTERMEASURE TOOLS

4. 对抗工具

ToolPlatformCapability
ScyllaHideWindows (x64dbg/IDA/OllyDbg)Auto-patches PEB, hooks NtQuery*, hides threads, fixes timing
TitanHideWindows (kernel driver)Kernel-level hiding for all user-mode checks
FridaCross-platformScript-based hooking of any function, timing spoofing
LD_PRELOAD shimsLinuxReplace ptrace, getenv, fopen at load time
GDB scriptsLinux
catch syscall
, conditional BP, register fixup
QilingCross-platformFull-system emulation, bypass all hardware checks

工具平台能力
ScyllaHideWindows(x64dbg/IDA/OllyDbg)自动补丁PEB、hook NtQuery*接口、隐藏线程、修正时序
TitanHideWindows(内核驱动)内核级隐藏,绕过所有用户态检查
Frida跨平台基于脚本的任意函数hook、时序伪造
LD_PRELOAD垫片Linux加载时替换ptrace、getenv、fopen等函数
GDB脚本Linux
catch syscall
、条件断点、寄存器修复
Qiling跨平台全系统仿真,绕过所有硬件级检查

5. SYSTEMATIC BYPASS METHODOLOGY

5. 系统化绕过方法论

Step 1: Static analysis — identify anti-debug calls
  └─ Search for: ptrace, IsDebuggerPresent, NtQuery, rdtsc,
     GetTickCount, SIGTRAP, INT 2D, TLS directory entries

Step 2: Classify each check
  ├─ API-based → hook or patch the call
  ├─ Flag-based → patch PEB/proc fields
  ├─ Timing-based → spoof time source
  ├─ Exception-based → forward/handle exception correctly
  └─ Multi-process → handle both processes

Step 3: Apply bypass (order matters)
  1. Load ScyllaHide / set LD_PRELOAD (covers 80% of checks)
  2. Handle TLS callbacks (break before main)
  3. Patch remaining custom checks (Frida or binary patch)
  4. Verify: run with breakpoints, confirm no premature exit

Step 4: Validate bypass completeness
  └─ Set BP on ExitProcess/exit/_exit — if hit unexpectedly,
     a check was missed → trace back from exit call

步骤1:静态分析 —— 识别反调试调用
  └─ 搜索关键词:ptrace、IsDebuggerPresent、NtQuery、rdtsc、
     GetTickCount、SIGTRAP、INT 2D、TLS目录条目

步骤2:分类每个检查
  ├─ 基于API → hook或者补丁调用
  ├─ 基于标志 → 补丁PEB/proc字段
  ├─ 基于时序 → 伪造计时源
  ├─ 基于异常 → 正确转发/处理异常
  └─ 多进程 → 同时处理所有进程

步骤3:应用绕过(顺序很重要)
  1. 加载ScyllaHide / 设置LD_PRELOAD(覆盖80%的检查)
  2. 处理TLS回调(在main前中断)
  3. 补丁剩余自定义检查(Frida或二进制补丁)
  4. 验证:设置断点运行,确认没有提前退出

步骤4:验证绕过完整性
  └─ 在ExitProcess/exit/_exit上设置断点 —— 如果意外命中,
     说明遗漏了检查 → 从exit调用回溯排查

6. DECISION TREE

6. 决策树

Binary exits/crashes under debugger?
├─ Crashes immediately before main?
│  └─ TLS callback anti-debug
│     └─ Enable TLS callback breaking in debugger
├─ Crashes at startup?
│  ├─ Linux: check for ptrace(TRACEME)
│  │  └─ LD_PRELOAD hook or NOP patch
│  └─ Windows: check IsDebuggerPresent / PEB
│     └─ ScyllaHide or manual PEB patch
├─ Crashes after some execution?
│  ├─ Consistent crash point → API-based check
│  │  ├─ NtQueryInformationProcess → hook return values
│  │  ├─ /proc/self/status → filter TracerPid
│  │  └─ Hardware BP detection → hook GetThreadContext
│  │
│  ├─ Variable crash point → timing-based check
│  │  └─ Hook rdtsc / QueryPerformanceCounter
│  │
│  └─ Crash on breakpoint hit → exception-based check
│     ├─ INT 2D / INT 3 trick → handle in VEH
│     └─ SIGTRAP handler → GDB: handle SIGTRAP pass
├─ Debugger loses control silently?
│  └─ ThreadHideFromDebugger
│     └─ Hook NtSetInformationThread
├─ Child process detects and kills parent?
│  └─ Self-debugging (fork+ptrace)
│     └─ Patch fork() or handle both processes
└─ All basic bypasses applied but still detected?
   └─ Multi-layer / custom checks
      ├─ Use Frida for comprehensive API hooking
      ├─ Full emulation with Qiling
      └─ Trace all calls to exit/abort to find remaining checks

二进制在调试器下退出/崩溃?
├─ 在main前立即崩溃?
│  └─ TLS回调反调试
│     └─ 在调试器中开启TLS回调中断
├─ 启动时崩溃?
│  ├─ Linux:检查ptrace(TRACEME)
│  │  └─ LD_PRELOAD hook或NOP补丁
│  └─ Windows:检查IsDebuggerPresent / PEB
│     └─ ScyllaHide或手动PEB补丁
├─ 运行一段时间后崩溃?
│  ├─ 崩溃点固定 → 基于API的检查
│  │  ├─ NtQueryInformationProcess → hook返回值
│  │  ├─ /proc/self/status → 过滤TracerPid
│  │  └─ 硬件断点检测 → hook GetThreadContext
│  │
│  ├─ 崩溃点不固定 → 基于时序的检查
│  │  └─ Hook rdtsc / QueryPerformanceCounter
│  │
│  └─ 断点命中时崩溃 → 基于异常的检查
│     ├─ INT 2D / INT 3 技巧 → 在VEH中处理
│     └─ SIGTRAP处理函数 → GDB:配置SIGTRAP转发
├─ 调试器静默失去控制?
│  └─ ThreadHideFromDebugger
│     └─ Hook NtSetInformationThread
├─ 子进程检测到调试器并杀死父进程?
│  └─ 自调试(fork+ptrace)
│     └─ 补丁fork()或同时处理两个进程
└─ 所有基础绕过都应用后仍然被检测?
   └─ 多层/自定义检查
      ├─ 使用Frida进行全量API hook
      ├─ 用Qiling进行全仿真
      └─ 跟踪所有exit/abort调用找到剩余检查

7. CTF & REAL-WORLD PATTERNS

7. CTF与真实场景模式

Common CTF Anti-Debug Patterns

常见CTF反调试模式

PatternFrequencyQuick Bypass
Single
ptrace(TRACEME)
Very common
LD_PRELOAD
one-liner
IsDebuggerPresent
+
NtGlobalFlag
CommonScyllaHide
rdtsc timing in loopModeratePatch comparison threshold
signal(SIGTRAP) + raiseModerateGDB signal forwarding
fork + ptrace watchdogRare but trickyKill child or patch fork
Nanomite INT3 replacementRare (advanced)Reconstruct jump table
模式出现频率快速绕过
单个
ptrace(TRACEME)
非常常见
LD_PRELOAD
单行命令
IsDebuggerPresent
+
NtGlobalFlag
常见ScyllaHide
循环中的rdtsc时序检查中等修改比较阈值
signal(SIGTRAP) + raise中等GDB信号转发
fork + ptrace监控进程少见但复杂杀死子进程或补丁fork
Nanomite INT3替换少见(高级)重建跳转表

Real-World Protections

真实场景保护

ProtectorPrimary Anti-DebugRecommended Tool
VMProtectPEB + timing + driver-levelTitanHide + ScyllaHide
ThemidaMulti-layer PEB + SEH + timingScyllaHide + manual patches
Enigma ProtectorIsDebuggerPresent + CRC checksx64dbg + ScyllaHide
UPX (custom)Usually none (just packing)Standard unpack
Custom (malware)Varies widelyFrida + Qiling for analysis

保护工具核心反调试手段推荐工具
VMProtectPEB + 时序 + 驱动级TitanHide + ScyllaHide
Themida多层PEB + SEH + 时序ScyllaHide + 手动补丁
Enigma ProtectorIsDebuggerPresent + CRC校验x64dbg + ScyllaHide
自定义UPX通常无(仅加壳)标准脱壳
自定义(恶意软件)差异极大Frida + Qiling分析

8. QUICK REFERENCE — BYPASS CHEAT SHEET

8. 快速参考——绕过速查表

Linux One-Liners

Linux单行命令

bash
undefined
bash
undefined

LD_PRELOAD anti-ptrace

LD_PRELOAD反ptrace

echo 'long ptrace(int r, ...) { return 0; }' > /tmp/ap.c gcc -shared -o /tmp/ap.so /tmp/ap.c LD_PRELOAD=/tmp/ap.so ./target
echo 'long ptrace(int r, ...) { return 0; }' > /tmp/ap.c gcc -shared -o /tmp/ap.so /tmp/ap.c LD_PRELOAD=/tmp/ap.so ./target

GDB: catch and bypass ptrace

GDB:捕获并绕过ptrace

(gdb) catch syscall ptrace (gdb) commands
set $rax = 0 continue end
undefined
(gdb) catch syscall ptrace (gdb) commands
set $rax = 0 continue end
undefined

Frida Anti-Debug Bypass (Cross-Platform)

Frida反调试绕过(跨平台)

javascript
// Hook IsDebuggerPresent (Windows)
Interceptor.replace(
  Module.getExportByName('kernel32.dll', 'IsDebuggerPresent'),
  new NativeCallback(() => 0, 'int', [])
);

// Hook ptrace (Linux)
Interceptor.replace(
  Module.getExportByName(null, 'ptrace'),
  new NativeCallback(() => 0, 'long', ['int', 'int', 'pointer', 'pointer'])
);

// Timing spoof
Interceptor.attach(Module.getExportByName(null, 'clock_gettime'), {
  onLeave(retval) {
    // manipulate timespec to hide debugger delay
  }
});
javascript
// Hook IsDebuggerPresent(Windows)
Interceptor.replace(
  Module.getExportByName('kernel32.dll', 'IsDebuggerPresent'),
  new NativeCallback(() => 0, 'int', [])
);

// Hook ptrace(Linux)
Interceptor.replace(
  Module.getExportByName(null, 'ptrace'),
  new NativeCallback(() => 0, 'long', ['int', 'int', 'pointer', 'pointer'])
);

// 时序伪造
Interceptor.attach(Module.getExportByName(null, 'clock_gettime'), {
  onLeave(retval) {
    // 调整timespec隐藏调试器延迟
  }
});

x64dbg ScyllaHide Quick Setup

x64dbg ScyllaHide快速配置

  1. Plugins → ScyllaHide → Options
  2. Check: PEB BeingDebugged, NtGlobalFlag, HeapFlags
  3. Check: NtQueryInformationProcess (all classes)
  4. Check: NtSetInformationThread (HideFromDebugger)
  5. Check: GetTickCount, QueryPerformanceCounter
  6. Apply → restart debugging session
  1. 插件 → ScyllaHide → 选项
  2. 勾选:PEB BeingDebugged、NtGlobalFlag、HeapFlags
  3. 勾选:NtQueryInformationProcess(所有类)
  4. 勾选:NtSetInformationThread(HideFromDebugger)
  5. 勾选:GetTickCount、QueryPerformanceCounter
  6. 应用 → 重启调试会话