当前位置: 首页 > news >正文

X64 TF位和Single-step单步调试的研究

如果在执行指令时,处理器检测到 EFLAGS 寄存器中的 TF 标志被设置,则会生成单步调试异常。该异常属于陷阱类异常,因为异常是在指令执行之后生成的。处理器不会在设置 TF 标志的指令之后立即生成此异常。例如,如果使用 POPF 指令设置 TF 标志,则单步陷阱不会发生,直到 POPF 指令后面的指令执行之后


 来跟踪一下windows的TF异常

  1. 查看1号向量的处理函数
  2. 在IDA中断到处理程序,可以看到处理器已经帮我们在栈中压入了参数
  3. 如果是3环的单步调试,windows切换了栈,rsp从KPCR.Prcb.RspBase 获得
    并复制了CPU压入的值
  4. 进入KxDebugTrapOrFault函数,它清掉了栈上的TF标志,看调试器如何处理,如果没有人处理,那么执行IRET执行后,不会继续执行单步
  5. 可以看到EFLAGS寄存器从原来的0x306h变成了0x206H ,清除了[8]TF位
  6. 我们使用P命令,单步执行,按照逻辑,windbg应该要修改这个地址,并重新设置TF标志位.所以在windbg中使用写时中断指令, 希望在写这个地址的时候中断下来,看看是怎么处理的
  7. 这里可以看到,如果要继续执行使用单步调试, 除了重新设置上TF标志位时,,windows还设置了RF标志位.这是为什么呢?

RF标志位的作用

RF标志的主要功能是允许在指令断点条件导致的调试异常后重新启动指令。在这里,调试软件必须在堆栈上的EFLAGS映像中设置此标志,然后才能使用IRETD返回中断的程序(以防止指令断点导致另一个调试异常)。然后,在返回的指令成功执行后,处理器会自动清除此标志,再次启用指令断点故障。

另请参见:第18.3.1.1节,“指令断点异常条件”
-----来自因特尔白皮书 Vol. 3A 2-11

由于指令断点的调试异常在指令执行前触发,若异常处理程序未移除断点,处理器在重启指令时会再次检测到断点并触发异常。为避免死循环,Intel 架构通过 EFLAGS 寄存器中的 RF 标志(Resume Flag) 控制:当 RF=1 时,处理器忽略指令断点。
调试异常处理程序可通过设置栈中 EFLAGS 镜像的 RF 标志,避免指令断点重复触发。当通过 IRETD/IRETQ 或任务切换返回时,栈中的 RF 值会被复制到 EFLAGS 寄存器,使处理器忽略下一条指令的断点。

 这里强调的是 instruction-breakpoint  (指令断点,在英特尔白皮书中 instruction-breakpoint  指的是使用DR寄存器的情况)

 所以邓志的书中有误导,将RF和TF标志位一起介绍,这是错误的,RF标志位只是为了防止指令断点的重入,因为他是fault类型的异常,可以理解为:指令执行前,CPU的检查到有指令断点.

 如果没有设置RF标志位,CPU执行前检查,发现符合指令断点条件,那么将导致循环触发指令断点

不设置RF标志
设置RF标志
 

RF 标志的管理规则:

  1. 清除时机:在指令开始执行时(检查指令断点、代码段限制违规和浮点异常后),RF 被清除。

  2. 上下文切换:任务切换和 IRETD/IRETQ 指令会将 RF 从 TSS/栈复制到 EFLAGS 寄存器。

  3. 异常处理

    • 非指令断点的故障类异常:压入栈的 EFLAGS 镜像中 RF=1

    • 指令断点调试异常:压入栈的 EFLAGS 镜像中 RF 保持原值。

    • 中断或陷阱类异常:若发生在重复字符串指令的非最后一次迭代中,RF=1

asm

复制

mov ecx, 3          ; 循环次数 ECX=3
lea esi, [src]      ; 源地址
lea edi, [dest]     ; 目标地址
rep movsb           ; 重复复制字节:执行 3 次 MOVSB
场景 1:陷阱类异常发生在非最后一次迭代
  • 迭代过程

    1. 第 1 次迭代(ECX=3 → ECX=2):正常执行 MOVSB

    2. 第 2 次迭代(ECX=2 → ECX=1):执行 MOVSB 时触发 陷阱类异常(如除零异常)。

  • 处理器行为

    • 压入栈的 EFLAGS 镜像中 RF=1(因异常发生在非最后一次迭代)。

    • 异常处理程序返回后,处理器继续执行 第 3 次迭代(ECX=1 → ECX=0)。

    • 由于 RF=1第 3 次迭代的 MOVSB 不会触发指令断点(即使存在断点)。

场景 2:陷阱类异常发生在最后一次迭代
  • 迭代过程

    1. 第 3 次迭代(ECX=1 → ECX=0):执行 MOVSB 时触发陷阱类异常。

  • 处理器行为

    • 压入栈的 EFLAGS 镜像中 RF=0(因异常发生在最后一次迭代)。

    • 异常处理程序返回后,若存在指令断点,仍会触发调试异常。

相关文章:

  • 渗透第二次作业
  • spring结合mybatis多租户实现单库分表
  • 洛谷-新二叉树python
  • Flink SQL怎么用?
  • 深度学习模型可视化:通俗易懂的全面解读
  • 基础算法整理
  • C++20 三路比较运算符 `<=>` 与 `operator==() = default` 的深度剖析及实际应用
  • VUE向外暴露文件,并通过本地接口调用获取,前端自己生成接口获取public目录里面的文件
  • Linux进程控制
  • leetcode 73. 矩阵置零
  • 鸿蒙新版开发工具DevEco Studio不能新建模拟的解决方法
  • 两台互通的服务器使用Docker部署一主两从MySQL8.0.35
  • 【Qt】为程序增加闪退crash报告日志
  • Nginx面试宝典【刷题系列】
  • 广州无人机考试培训收费标准(附报名流程)
  • 【开源免费】基于SpringBoot+Vue.JS美食烹饪互动平台(JAVA毕业设计)
  • python 剪切音频
  • [特殊字符]️ ‌Selenium元素存在性判断的5种方法‌
  • 归纳总结一下Tensorflow、PaddlePaddle、Pytorch构建神经网络基本流程,以及使用NCNN推理的流程
  • 快速上手 Uniapp:从入门到精通的捷径
  • 河北邯郸一酒店婚宴发生火灾:众人惊险逃生,酒店未买保险
  • 黑灰产工作室为境外诈骗集团养号引流,冒充美女与男性裸聊后敲诈勒索
  • 优秀“博主”在上海杨浦购房最高补贴200万元,有何条件?
  • 竞彩湃|霍芬海姆看到保级曙光,AC米兰专注于意大利杯
  • 中方就乌克兰危机提出新倡议?外交部:中方立场没有变化
  • 人民时评:透过上海车展读懂三组密码