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

news/2025/2/27 7:15:14
cle class="baidu_pl">
cle_content" class="article_content clearfix">
content_views" class="htmledit_views">

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

c="https://i-blog.csdnimg.cn/direct/face0b8968d5412393052c324577c056.png" width="980" />

c="https://i-blog.csdnimg.cn/direct/bea7401d402c4c109d9ddbb3bc2dc159.png" width="1360" />
c="https://i-blog.csdnimg.cn/direct/c4490f9e02c240eab57ffebb42a2cf5e.png" width="1328" />

 来跟踪一下class="tags" href="/tags/WINDOWS.html" title=windows>windows的TF异常

  1. 查看1号向量的处理函数c="https://i-blog.csdnimg.cn/direct/30de7d281fc34ac28e8d7815f66a7627.png" width="771" />
  2. 在IDA中断到处理程序,可以看到处理器已经帮我们在栈中压入了参数c="https://i-blog.csdnimg.cn/direct/217536cde99942abbcebf2298660d411.png" width="1249" />
  3. 如果是3环的单步调试,class="tags" href="/tags/WINDOWS.html" title=windows>windows切换了栈,rsp从KPCR.Prcb.RspBase 获得
    并复制了CPU压入的值c="https://i-blog.csdnimg.cn/direct/0b28c78847d34381b473b9e6e7f187eb.png" width="1087" />
  4. 进入KxDebugTrapOrFault函数,它清掉了栈上的TF标志,看调试器如何处理,如果没有人处理,那么执行IRET执行后,不会继续执行单步c="https://i-blog.csdnimg.cn/direct/3172b40e8154415aaced9f33fa29f476.png" width="886" />
  5. 可以看到EFLAGS寄存器从原来的0x306h变成了0x206H ,清除了[8]TF位
    c="https://i-blog.csdnimg.cn/direct/b889f7d3aed2427989bd26611676a01e.png" width="842" />
  6. 我们使用P命令,单步执行,按照逻辑,windbg应该要修改这个地址,并重新设置TF标志位.所以在windbg中使用写时中断指令, 希望在写这个地址的时候中断下来,看看是怎么处理的c="https://i-blog.csdnimg.cn/direct/2ff82ebe398c482296e0a00a9a3b4f25.png" width="1763" />
  7. 这里可以看到,如果要继续执行使用单步调试, 除了重新设置上TF标志位时,,class="tags" href="/tags/WINDOWS.html" title=windows>windows还设置了RF标志位.这是为什么呢?

c="https://i-blog.csdnimg.cn/direct/ae6a4ae6d7c742808cd906dd0e14b555.png" width="897" />

RF标志位的作用

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

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

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

ckquote>

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

ckquote>

 所以邓志的书中有误导,将RF和TF标志位一起介绍,这是错误的,RF标志位只是为了防止指令断点的重入,因为他是fault类型的异常,可以理解为:指令执行前,CPU的检查到有指令断点.
c="https://i-blog.csdnimg.cn/direct/fd61193385f041ec8ba8396247c79c99.png" width="927" />

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

class="image"> c="https://i-blog.csdnimg.cn/direct/9ccf08feaf824764825a92ad94eefdf7.png" width="902" /> caption> 不设置RF标志 caption>
class="image"> c="https://i-blog.csdnimg.cn/direct/c7d296e07d1e4704b583e4fba7e9b784.png" width="840" /> caption> 设置RF标志
 
caption>

RF 标志的管理规则:

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

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

  3. 异常处理

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

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

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

asm

复制

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

    1. 第 1 次迭代(ECX=3 → ECX=2):正常执行 <code>MOVSBcode>。

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

  • 处理器行为

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

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

    • 由于 <code>RF=1code>࿰c;第 3 次迭代的 <code>MOVSBcode> 不会触发指令断点(即使存在断点)。

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

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

  • 处理器行为

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

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


http://www.niftyadmin.cn/n/5869699.html

相关文章

一周学会Flask3 Python Web开发-Jinja2模板继承和include标签使用

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 不管是开发网站还是后台管理系统&#xff0c;我们页面里多多少少有公共的模块。比如博客网站&#xff0c;就有公共的头部&…

策略模式环境类的实现方式对比

文章目录 1、策略模式2、聚合策略类实现方式一3、聚合策略类实现方式二4、对比5、补充&#xff1a;ApplicationContextAware接口 1、策略模式 近期工作中&#xff0c;需要处理4.x和5.x两个版本的数据&#xff0c;所以自然想到的是策略模式&#xff0c;写一个抽象类&#xff0c…

DeepSeek-R1的一些影响

DeepSeek-R1火爆全球&#xff0c;肯定不仅仅是开源了一篇论文、一个模型那么简单&#xff0c;更多的是其带来的一些影响&#xff0c;这里简单聊聊。 跳出大模型固有开发范式 NLP&大模型技术发展历程大致如下&#xff1a; 规则方法统计学习方法深度学习方法深度学习预训练…

智慧城市招标进入“资质严审期”!谁主数字孪生技术话语权?

2025年1月&#xff0c;《全国统一大市场建设指引》明确要求招标项目需杜绝“逐利性执法”&#xff0c;技术资质审查更趋透明化。与此同时&#xff0c;住建部《危险性较大的分部分项工程专项施工方案严重缺陷清单》将数字孪生平台的数据治理能力纳入工程验收标准。在此背景下&am…

记录Liunx安装Jenkins时的Package ‘jenkins‘ has no installation candidate

1、确保是否安装了Java&#xff0c;如果没有&#xff0c;可通过以下命令进行安装&#xff1a; sudo apt update sudo apt install openjdk-21-jre2、安装Jenkins sudo apt update sudo apt install jenkins执行sudo apt install jenkins时&#xff0c;可能会出现 意思是&…

C语言-6.数据类型

目录 6.1数据类型6.1.1数据类型:C语言有哪些是基础数据类型,sizeof可以做什么6.1.2数据类型:除了int,还有多少整数类型6.1.3整数的内部表达式:整数是如何表达的,尤其是负数如何表达的6.1.4整数的范围:如何推断整数类型所能表达的范围,越界了会咋样6.1.5整数的格式化:如…

flask 是如何分发请求的?

这篇博客会涉及一些 WSGI 的知识&#xff0c;不了解的可以看这篇博客&#xff0c;简单了解一下。 Python 的 WSGI 简单入门 一、请求在 flask 中的处理过程 我们先来看一下 werkzeug.routing 包下 Map 和 Rule 方法的使用&#xff0c;这里给出一个官方的示例&#xff08;我进…

构建逻辑思维链(CoT)为金融AI消除幻觉(保险理赔篇)

在上一篇文章中&#xff0c;我们介绍了如何利用亚马逊云科技的Amazon Bedrock GuardRails自动推理检查为金融行业的AI应用提升准确性&#xff0c;消除幻觉。在本案例中&#xff0c;我们将探讨一个利用AI副主保险公司评估长期护理保险理赔审核的场景。 自动推理检查配置 在本方…