assembly endbr64指令实际上是做什么的?

1tuwyuhd  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(638)

我一直在尝试理解GCC生成的汇编语言代码,并且经常在包括_start()在内的许多函数的开头遇到此指令,但找不到任何解释其用途的指南:

31-0000000000001040 <_start>:
32:    1040:    f3 0f 1e fa             endbr64 
33-    1044:    31 ed                   xor    ebp,ebp
mqxuamgl

mqxuamgl1#

它代表“结束分支64位”(也有一个32位计数器部分)-或者更准确地说,终止间接分支64位。
操作如下:

IF EndbranchEnabled(CPL) & EFER.LMA = 1 & CS.L = 1
  IF CPL = 3
  THEN
    IA32_U_CET.TRACKER = IDLE
    IA32_U_CET.SUPPRESS = 0
  ELSE
    IA32_S_CET.TRACKER = IDLE
    IA32_S_CET.SUPPRESS = 0
  FI
FI;

如果指令不能清除TRACKER标志,则CPU生成#CP异常。换句话说,如果黑客能够改变间接跳转的目的地址,即使目的是法律的的汇编代码,程序也很可能终止。
否则,该指令被认为是NOP
在其他情况下,CET特性用于确保间接分支实际上转到有效位置。这允许额外的安全性。以下是Intel的一段话:
ENDBRANCH(详见第73节)是一条新指令,用于标记程序中间接调用和跳转的有效跳转目标地址。该指令操作码被选择为是遗留机器上的NOP的指令操作码,使得用ENDBRANCH新指令编译的程序在没有CET实施的情况下继续在旧机器上起作用。在支持CET的处理器上,ENDBRANCH仍然是NOP,并且主要被处理器流水线用作标记指令以检测控制流违规。CPU实现跟踪间接jmp和call指令的状态机。当看到其中一条指令时,状态机将从IDLE转到WAIT_FOR_ENDBRANCH状态。在WAIT_FOR_ENDBRANCH状态下,程序流中的下一条指令必须是ENDBRANCH。如果未看到ENDBRANCH,则处理器导致控制保护异常(#CP),否则状态机移回IDLE状态。
作为旁注,可以告诉处理器不允许ENDBR 64。这是用前缀(3Eh)完成的。这对于地址位于只读存储器中的表中的交换机等情况非常有用。但是,CPU在许多情况下会忽略该前缀。

xtupzzrd

xtupzzrd2#

endbr64(和endbr32)是Intel's Control-Flow Enforcement Technology (CET)的一部分(参见Intel Software Developer Manual, Volume 1, Chapter 18)。
英特尔CET提供了针对Return-oriented Programming (ROP)Jump/Call-oriented Programming (JOP/COP)攻击的硬件保护,这些攻击操纵控制流,以便将现有代码重新用于恶意目的。
它的两大特点是

  • 一个shadow stack用于跟踪返回地址和
  • 间接分支跟踪,endbr64是其中的一部分。

虽然CET在当前的处理器代中才慢慢可用,但它是already supported as of GCC 8,默认情况下插入endbrXX指令。操作码在较旧的处理器上被选择为无操作,使得如果不支持CET,则忽略该指令;同样的情况发生在具有CET能力的处理器上,其中间接分支跟踪被禁用。
endbr64是做什么的?

    • 前提条件:**
  • 必须通过将控制寄存器标志CR4.CET设置为1来使能CET。
  • IA32_U_CET(用户模式)或IA32_S_CET(管理程序模式)MSR中设置间接分支跟踪的适当标志。

CPU建立一个小的状态机来跟踪最后一个分支的类型。举个例子:

some_function:
    mov rax, qword [vtable+8]
    call rax
    ...

check_login:
    endbr64
    ...
authenticated:
    mov byte [is_admin], 1
    ...
    ret

现在让我们简要地看两个场景。

    • 无攻击:**
  1. some_functionvirtual method tablevtable中检索虚拟方法check_login的地址并调用它。
    1.由于这是间接调用,CET状态机被激活并设置为在下一条指令(TRACKER = WAIT_FOR_ENDBRANCH)上触发。
    1.下一个指令是endbr64,因此间接调用被认为是“安全的”,并且继续执行(endbr64仍然表现为no-op)。状态机复位(TRACKER = IDLE)。
    • 攻击:**

攻击者以某种方式操纵了vtable,使得vtable+8现在指向authenticated

  1. some_function从虚拟方法表vtable中检索authenticated的地址并调用它。
    1.由于这是一个间接调用,因此CET状态机被激活并设置为在下一条指令(TRACKER = WAIT_FOR_ENDBRANCH)时触发。
    1.下一条指令是mov byte [is_admin], 1,而不是预期的endbr64指令。CET状态机推断控制流被操纵,并引发#CP故障,终止程序。
    如果没有CET,控制流操作将不会被注意到,攻击者将获得管理员权限。
    总之,英特尔CET的间接分支跟踪功能可确保间接调用和跳转只能重定向到以endbr64指令开头的函数。
    请注意,这并不能确保调用 * right * 函数--如果攻击者改变控制流,跳转到另一个同样以endbr64开头的函数,状态机将不会抱怨并继续执行程序。然而,这仍然大大减少了攻击面,因为大多数JOP/COP攻击的目标是功能中间的指令(甚至直接“跳转到”指令中)。

相关问题