由于软件断点与硬件断点不同,它确实会更改代码,因此编写一个对自身执行校验和的程序作为反调试器技术相对容易。是否可以对硬件断点做类似的事情?
检测硬件断点
逆向工程
反调试
断点
2021-06-15 10:19:14
1个回答
这是一个非常好的问题,因为该主题不像检测软件断点的反调试技术那样受欢迎。由于您没有提到架构,我们必须牢记硬件断点,正如其名称所暗示的那样,取决于您正在运行的硬件,因此此类断点的实现在每个架构之间是不同的。由于我们无法在此答案中涵盖所有架构,因此我将假设我们正在讨论Windows 上的英特尔 x86 架构。
简而言之,答案是肯定的。检测硬件断点基本上有两种常用的方法:
- 使用线程的上下文访问调试寄存器
- 制作一个SEH(结构化异常处理),然后引发异常并访问调试寄存器
为了理解每种方法,我们应该首先了解硬件断点是什么以及(简而言之)它是如何工作的。
硬件断点
在x86架构中,调试器使用一组调试寄存器来应用硬件断点。存在 8 个调试寄存器来控制调试过程,范围从DR0到DR7。这些寄存器不能从ring3 权限访问,而只能从 CPL0(当前权限级别,ring0)访问。因此,在任何其他特权级别执行时尝试读取或写入调试寄存器会导致一般保护错误。调试寄存器允许调试器在访问存储器进行读或写时中断程序执行并将控制权转移给它。
x86 调试寄存器
- DR0 - 线性断点地址 0
- DR1 - 线性断点地址 1
- DR2 - 线性断点地址 2
DR3 - 线性断点地址 3
DR4 - 保留。英特尔未定义
DR5 - 保留。英特尔未定义
DR6 - 断点状态
- DR7 - 断点控制
DR0-DR3 存储断点的线性地址。存储的地址可以与物理地址相同,也可以转换为物理地址。DR6指示哪个断点被激活。DR7通过访问模式定义断点激活模式:read、write或execute。
检测硬件断点
方法一——ThreadContext Win API
下面的例子是基于一个例子这种文章从CodeProject。该示例被注释以描述每段代码:
bool IsHWBreakpointExists()
{
// This structure is key to the function and is the
CONTEXT ctx;
ZeroMemory(&ctx, sizeof(CONTEXT));
// The CONTEXT structure is an in/out parameter therefore we have
// to set the flags so Get/SetThreadContext knows what to set or get.
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
// Get a handle to our thread
HANDLE hThread = GetCurrentThread();
// Get the registers
if(GetThreadContext(hThread, &ctx) == 0)
return false;
if ((ctx.Dr0) || (ctx.Dr1) || (ctx.Dr2) || (ctx.Dr3)) {
return true;
}
else {
return false;
}
}
方法 2 - SEH
操作调试寄存器的 SEH 方法更常见,并且更容易在汇编中实现,如下面的示例所示,同样来自 CodeProject:
ClrHwBpHandler proto
.safeseh ClrHwBpHandler
ClearHardwareBreakpoints proc
assume fs:nothing
push offset ClrHwBpHandler
push fs:[0]
mov dword ptr fs:[0], esp ; Setup SEH
xor eax, eax
div eax ; Cause an exception
pop dword ptr fs:[0] ; Execution continues here
add esp, 4
ret
ClearHardwareBreakpoints endp
ClrHwBpHandler proc
xor eax, eax
mov ecx, [esp + 0ch] ; This is a CONTEXT structure on the stack
mov dword ptr [ecx + 04h], eax ; Dr0
mov dword ptr [ecx + 08h], eax ; Dr1
mov dword ptr [ecx + 0ch], eax ; Dr2
mov dword ptr [ecx + 10h], eax ; Dr3
mov dword ptr [ecx + 14h], eax ; Dr6
mov dword ptr [ecx + 18h], eax ; Dr7
add dword ptr [ecx + 0b8h], 2 ; We add 2 to EIP to skip the div eax
ret
ClrHwBpHandler endp
参考:
其它你可能感兴趣的问题