原理
如果程序设置了硬件断点,则 dr0 - dr7 寄存器的值就会改变,其中 dr0 - dr3
存放硬件断点的地址,dr4 - dr5 保留,dr6 存放调试事件的详细信息,dr7 存放断点触发的条件。
可以使用 GetThreadContext 获取线程上下文环境,然后读取当前的 dr0 - dr3 有没有值,有的话就说明调试器设置了硬件断点,说明有调试器。
但是缺点就是如果调试器没有设置硬件断点的话就无法检测调试器,所以这种方法一般都和其他反调试计数配合使用。😦
函数介绍
/*
检索线程上下文
返回值:失败返回 0
*/
BOOL GetThreadContext(
HANDLE hThread, // 线程句柄
LPCONTEXT lpContext // CONTEXT 结构体指针
);
x64 下的 CONTEXT 结构:
typedef struct DECLSPEC_ALIGN(16) DECLSPEC_NOINITALL _CONTEXT {
// 忽略,用于将来扩展
DWORD64 P1Home;
DWORD64 P2Home;
DWORD64 P3Home;
DWORD64 P4Home;
DWORD64 P5Home;
DWORD64 P6Home;
// 控制位
DWORD ContextFlags;
DWORD MxCsr;
// 段寄存器
WORD SegCs;
WORD SegDs;
WORD SegEs;
WORD SegFs;
WORD SegGs;
WORD SegSs;
DWORD EFlags;
// 调试寄存器
DWORD64 Dr0;
DWORD64 Dr1;
DWORD64 Dr2;
DWORD64 Dr3;
DWORD64 Dr6;
DWORD64 Dr7;
// 通用寄存器
DWORD64 Rax;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rbx;
DWORD64 Rsp;
DWORD64 Rbp;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;
// 程序计数器
DWORD64 Rip;
// 浮点运算寄存器
union {
XMM_SAVE_AREA32 FltSave;
struct {
M128A Header[2];
M128A Legacy[8];
M128A Xmm0;
M128A Xmm1;
M128A Xmm2;
M128A Xmm3;
M128A Xmm4;
M128A Xmm5;
M128A Xmm6;
M128A Xmm7;
M128A Xmm8;
M128A Xmm9;
M128A Xmm10;
M128A Xmm11;
M128A Xmm12;
M128A Xmm13;
M128A Xmm14;
M128A Xmm15;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
// vector(向量)寄存器
M128A VectorRegister[26];
DWORD64 VectorControl;
// 调试控制寄存器
DWORD64 DebugControl;
DWORD64 LastBranchToRip;
DWORD64 LastBranchFromRip;
DWORD64 LastExceptionToRip;
DWORD64 LastExceptionFromRip;
} CONTEXT, *PCONTEXT;
代码示例
// Test_Console_1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
// 初始化 CONTEXT 结构
PCONTEXT ctx = (PCONTEXT)VirtualAlloc(NULL, sizeof(CONTEXT), MEM_COMMIT, PAGE_READWRITE);
if (ctx == NULL) {
cout << "VirtualAlloc failed." << endl;
goto main_end;
}
RtlSecureZeroMemory(ctx, sizeof(CONTEXT));
// 指定检索线程上下文的哪些部分
ctx->ContextFlags = CONTEXT_DEBUG_REGISTERS;
// 获取 dr0 - dr3 的值
if (GetThreadContext(GetCurrentThread(), ctx)) {
if(ctx->Dr0 != 0 || ctx->Dr1 != 0 || ctx->Dr2 != 0 || ctx->Dr3 != 0) {
cout << "发现调试器!" << endl;
}
else {
cout << "没有调试器!" << endl;
}
}
else {
cout << "GetThreadContext failed." << endl;
}
main_end:
getchar();
return 0;
}
效果图
x64dbg 设置硬件断点后:
正常运行时: