如果设置了 GD 标志,读取调试寄存器是不是会引发异常?

Posted

技术标签:

【中文标题】如果设置了 GD 标志,读取调试寄存器是不是会引发异常?【英文标题】:Does reading a debug register raise an exception if the GD flag is set?如果设置了 GD 标志,读取调试寄存器是否会引发异常? 【发布时间】:2021-03-24 18:55:24 【问题描述】:

我最近一直在研究调试寄存器以及一些恶意软件程序如何将它们作为一种反调试策略进行操作。我现在读过几次的一件事是,可以通过使用 DR7 中的 General Detect 标志来防止这种情况,如果使用 MOV 指令访问 DR0-DR7 中的任何一个,则会引发调试异常。

但是,我不清楚的是访问的确切含义-例如,如果使用 mov 指令仅将 DR0-DR3 的地址放入通用寄存器中以便可以读取它,这仍然是设置 GD 标志时引发调试异常?还是仅当使用 MOV 指令实际更改寄存器的内容时​​才会发生这种情况?到目前为止,我所读到的内容对此有点模棱两可。

我在一段显示调试寄存器操作的文本中遇到了下面的程序集,但在这种情况下,mov 仅用于获取调试寄存器的地址,而实际修改是由 or 指令完成的,所以我没有确定如果设置了 GD,此代码是否会引发异常。

    xor eax, eax
    push offset except_callback
    push d fs:[eax]
    mov fs:[eax], esp
    int 3 ;force an exception to occur
    ...        

    except_callback:
     mov eax, [esp+0ch] ;get ContextRecord
     mov ecx, [eax+4] ;Dr0
     or ecx, [eax+8] ;Dr1
     or ecx, [eax+0ch] ;Dr2
     or ecx, [eax+10h] ;Dr3
     jne <Debugger_detected>

【问题讨论】:

确实,英特尔的手册有时会说“访问”,有时会说“修改”,例如在表 17-2,调试异常条件中。 您的示例根本不访问调试寄存器。 “ContextRecord”不是 CPU 固有的,也没有得到任何特殊处理(除了通常的内存分段和分页)。 @ecm 我添加了一些缺少的代码以获得更多上下文(没有双关语),以防它现在更有意义。原始指令是异常处理程序的一部分,该处理程序被推送到堆栈并随后被调用,从那里偏移量用于访问上下文记录。 @Rahl2500:添加的代码也不会直接访问任何调试寄存器。只有mov XXX, drX(xxx = 寄存器,x = 数字)形式的指令才能直接访问它们。 【参考方案1】:

英特尔对此非常清楚:

尝试读取或写入调试寄存器 从任何其他特权级别生成一般保护异常 (#GP)。

因此,在不以 CPL 0 运行时读取或写入调试寄存器将引发异常,与 GD 标志无关。

事实上,我已经分析了相当多的恶意软件,它们都没有直接访问调试寄存器。 他们获取当前线程上下文(GetThreadContext 或 NtGetContextThread 或类似的 WOW64 变体)并从那里检查调试寄存器的值,注意在这种情况下读取调试寄存器的是 Windows 的内核。 这种反调试技巧可以手动解决(在检索上下文的 API 上设置断点)或使用调试器插件。 以 CPL 0 运行的恶意软件可以使用 GD 标志,但到目前为止我还没有找到。

回答您的标题问题,如果设置了GD,对调试寄存器的任何读取或写入访问(在 CPL 0 处)都会引发 #GP。 我没有对其进行了测试,但考虑到它的预期用途(支持硬件调试器模拟器),我的想法是“虚拟化”调试寄存器。 然后,在软件中模拟的硬件调试器可以使用调试寄存器,即使被调试的操作系统已经在使用它们。 这是通过在每次访问时出错并正确交换操作系统与模拟器值来完成的。

如果只有写入错误,则模拟器无法阻止被调试的操作系统从调试寄存器中读取不正确的值(由模拟器放置在那里)。

启用(设置时)调试寄存器保护,这会导致 在访问调试寄存器的任何 MOV 指令之前生成调试异常。 当这样一个 检测到条件时,调试状态寄存器 DR6 中的 BD 标志在产生异常之前设置。这 提供条件以支持在线仿真器。 当仿真器需要访问调试寄存器时,仿真器软件可以设置 GD 标志以防止 来自当前在处理器上执行的程序的干扰。 处理器在进入调试异常处理程序时清除 GD 标志,以允许处理程序访问 调试寄存器。

【讨论】:

>"在 CPL 0 上运行的恶意软件可以使用 GD 标志,但到目前为止我还没有找到。"有趣的。由于 DR7 是调试寄存器,因此尝试修改 GD 标志本身不会触发 #GP 吗? @Rahl2500:软件开发人员手册 17.2.4:“处理器在进入调试异常处理程序时清除 GD 标志,以允许处理程序访问调试寄存器。”因此,如果未设置,您可以设置它(从 CPL 0 开始)。它保持设置,直到发生调试异常。此时它已被清除,如果您仍希望启用它,则处理程序应再次设置它。

以上是关于如果设置了 GD 标志,读取调试寄存器是不是会引发异常?的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向代码调试器开发 ( 代码调试器功能简介 | 设置断点 | 读写内存 | 读写寄存器 | 恢复运行 | Attach 进程 )

x86 ASM - cpuid 是不是设置标志?

单步中断

80X86保护模式及其编程

如果分配该数组引发异常,你应该释放一个数组吗?

GD32的RTC出问题了,有主意吗?