PEB 中的 BeingDebugged 标志位位于 PEB 结构偏移 0x2 处,为单字节字段,被调试时值为 1,否则为 0,是最轻量且常被检测的反调试手段之一。

什么是 PEB 中的 BeingDebugged 标志位
Windows 进程启动时,系统会在进程地址空间中创建一个 PEB(Process Environment Block)结构,其中偏移 0x2 处是一个单字节字段 BeingDebugged。只要进程被调试器(如 x64dbg、WinDbg、Visual Studio)附加,该字节就会被设为 1;否则为 0。这是最轻量、最常被检测的反调试手段之一。
如何在 C++ 中安全读取 BeingDebugged 字段
直接硬编码偏移读取 PEB 地址风险高:不同 Windows 版本、32/64 位、是否启用 CFG 等都可能影响结构布局或触发异常。推荐通过 NtQueryInformationProcess 或 __readgsqword(x64)/__readfsdword(x86)获取 PEB 首地址,再加偏移访问:
// x64 示例(需链接 ntdll.lib)
#include <windows.h>
#include <winternl.h>
bool IsBeingDebugged() {
auto peb = reinterpret_cast<byte>(__readgsqword(0x60));
return peb[0x2] != 0;
}</byte></winternl.h></windows.h>
- 使用
__readgsqword(0x60)比解析NT_TIB更快,且绕过部分用户态钩子 - 不要用
GetModuleHandleA("ntdll.dll")+GetProcAddress调用NtQueryInformationProcess—— 容易被 inline hook 拦截 - 读取前建议先检查
peb是否为有效地址(如非零、可读),避免触发ACCESS_VIOLATION
BeingDebugged 检测的局限性和绕过方式
这个标志仅反映「当前是否被调试器附加」,无法识别远程调试、内核调试器(如 WinDbg KD)、或调试器未设置 DEBUG_PROCESS 权限的情况。更重要的是,它极易被绕过:
- 调试器启动后手动修改内存:
mov byte ptr ds:[rax+2], 0(x64dbg 中右键 PEB → “转到地址” → 修改字节) - 使用
SetThreadContext在入口点前篡改PEB->BeingDebugged - 某些沙箱(如 Cuckoo)默认清零该字段以隐藏自身调试行为
- Windows 10 RS5+ 引入了
KernelDebugControl机制,BeingDebugged不再可靠反映内核调试状态
实际工程中要不要依赖 BeingDebugged
可以作为第一层快速检测,但绝不能单独用于关键逻辑保护(比如解密密钥、跳过 license 校验)。真实对抗场景中必须组合其他信号:
- 检查
NT_GLOBAL_FLAG(偏移0xBC)是否含FLG_HEAP_ENABLE_TAIL_CHECK等调试相关标志 - 调用
CheckRemoteDebuggerPresent(注意:该 API 内部也读BeingDebugged,本质同源) - 枚举父进程名(如
vsjitdebugger.exe、windbg.exe)或检查IsDebuggerPresent返回值 - 更隐蔽的:尝试打开
"\Device\PhysicalMemory"(需 SeDebugPrivilege)、或检测OutputDebugStringA是否被 hook
单独靠 BeingDebugged 字段,就像用门锁防撬棍——能拦住随手试探的人,但对有准备的分析者几乎没门槛。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











