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

Mah*_*35h 5 assembly x86-64 intel

我一直在尝试理解由GCC生成的汇编语言代码,并经常在包括_start()在内的许多函数启动时遇到此指令,但找不到任何说明其用途的指南。

31-0000000000001040 <_start>:
32:    1040:    f3 0f 1e fa             endbr64 
33-    1044:    31 ed                   xor    ebp,ebp
Run Code Online (Sandbox Code Playgroud)

Jan*_*ann 78

endbr64(和)是英特尔控制流强制技术(CET)endbr32的一部分(另请参阅英特尔软件开发人员手册,第 1 卷,第 18 章)。

英特尔 CET 提供硬件保护,防止面向返回的编程 (ROP)面向跳转/调用的编程 (JOP/COP)攻击,这些攻击会操纵控制流,以便出于恶意目的重新使用现有代码。

其两大特点是

  • 用于跟踪返回地址的影子堆栈
  • 间接分支跟踪,这endbr64是的一部分。

虽然 CET 在当前一代处理器中才慢慢变得可用,但从 GCC 8 开始就已经支持它,endbrXX默认情况下会插入指令。在较旧的处理器上,操作码被选择为无操作,这样,如果不支持 CET,则该指令将被忽略;同样的情况也发生在支持 CET 的处理器上,其中间接分支跟踪被禁用。


那么它有什么endbr64作用呢?

前提条件:

  • 必须通过将控制寄存器标志设置为 1 来启用 CET CR4.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
Run Code Online (Sandbox Code Playgroud)

现在让我们简单地看一下两个场景。

无攻击:

  1. some_functioncheck_login虚拟方法表 中检索虚拟方法的地址vtable并调用它。
  2. 由于这是间接调用,因此 CET 状态机被激活并设置为在下一条指令 ( TRACKER = WAIT_FOR_ENDBRANCH) 上触发。
  3. 下一条指令是endbr64,因此间接调用被认为是“安全的”并且继续执行(endbr64仍然表现为无操作)。状态机复位 ( TRACKER = IDLE)。

攻击:攻击者以某种方式
设法操纵现在指向。vtablevtable+8authenticated

  1. some_functionauthenticated从虚拟方法表中检索并调用它的地址vtable
  2. 由于这是间接调用,因此 CET 状态机被激活并设置为在下一条指令 ( TRACKER = WAIT_FOR_ENDBRANCH) 上触发。
  3. 下一条指令是mov byte [is_admin], 1,不是预期的endbr64指令。CET 状态机推断控制流已被操纵并引发故障#CP,终止程序。

如果没有 CET,控制流操作将不会被注意到,并且攻击者将获得管理员权限。


综上所述,Intel CET 的间接分支跟踪功能确保间接调用和跳转只能重定向到以指令开头的函数endbr64

请注意,这并不能确保调用正确的函数 - 如果攻击者更改控制流以跳转到同样以该函数开头的不同函数endbr64,状态机不会抱怨并继续执行程序。然而,这仍然大大减少了攻击面,因为大多数 JOP/COP 攻击的目标是指令中间功能(甚至直接跳到“指令”)。

  • `CR4` 只能在环 0 中更改,因此需要内核支持。 (4认同)
  • 如果没有操作系统必须保存和恢复的额外状态,我不明白这两种情况之间的行为有何不同。 (2认同)

Ale*_*lke 6

它代表“ 64位结束分支”-更准确地说,是终止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;
Run Code Online (Sandbox Code Playgroud)

该指令否则被视为NOP

CET功能用于确保您的间接分支实际到达有效位置。这样可以增加安全性。这是英特尔关于它的一段:

ENDBRANCH(有关详细信息,请参见第73节)是一条新指令,用于标记程序中间接调用和跳转的有效跳转目标地址。该指令操作码被选择为在旧机器上的NOP,以便使用ENDBRANCH新指令编译的程序可以继续在旧机器上运行,而无需执行CET。在支持CET的处理器上,ENDBRANCH仍然是NOP,并且主要由处理器管道用作标记指令以检测违反控制流的行为。CPU实现了一个状态机,该状态机跟踪间接的jmp和调用指令。当看到这些指令之一时,状态机将从IDLE移到WAIT_FOR_ENDBRANCH状态。在WAIT_FOR_ENDBRANCH状态下,程序流中的下一条指令必须为ENDBRANCH。