快速连接
👉👉👉【精选】ARMv8/ARMv9架构入门到精通-目录 👈👈👈
1、Stack smashing and execution permissions
最传统的一种攻击方式是栈溢出(stack smashing)。 有很多类型的栈溢出。 栈溢出的基本形式涉及恶意软件将新的操作码写入内存,然后尝试执行写入的内存。如下演示了这个过程 :
通常,用来发起攻击的内存是堆栈内存。 这就是名称stack smashing 的由来。 为了防止栈溢出,现代处理器架构,如Arm架构,有执行权限(execution permissions)的设置。 在Armv8-A中,主要的控制是 翻译表中的执行比特位。 如下列出translation engine1的EL0和EL1的执行权限:
- UXN User (EL0) Execute-never
- PXN Privileged Execute-never
设置其中一个位将页面标记为不可执行。 这意味着任何分支到该页内某个地址的尝试都会触发一个异常,以Permission错误的形式出现。 有单独的特权和非特权位。 这是因为应用程序代码需要在用户空间(EL0)中执行,但不应该使用内核权限(EL1或EL2)执行。 另一种形式的攻击包括滥用系统调用,试图获得特权代码来从用户内存调用代码。
下图显示了运行在操作系统(OS)下、具有预期执行权限的应用程序的简化但典型的虚拟地址空间:
该体系结构还在系统控制寄存器SCTLR_ELx中提供了控制位,以使<font color=red size=4>所有可写地址不可执行</font>。 启用此控件将使堆栈等位置不可执行。
无论PXN和SCTLR_ELx控件如何配置,在EL0上可写的位置永远不会在EL1上可执行
这些控制加在一起可以为我们所描述的各种攻击提供强大的保护。 翻译表属性和写入控件可以阻止任何位置的执行,恶意代码可以写入,如下图所示:
2、Return-oriented programming(ROP)
术语: Pointer Authentication Code (PAC)
像我们所描述的执行权限这样的特性使得执行任意代码变得越来越困难。 这意味着攻击者使用其他方法,如面向返回编程(ROP)。 ROP利用了许多现代系统中软件堆栈的规模优势。 攻击者分析系统中的软件,寻找小工具。 gadget是一段有用的代码,通常以函数return结尾.
我们正常的程序中,一般都是在进入函数的时候,将返回地址(LR寄存器)做了一个压栈的操作,函数返回之前,再将LR从栈中还原.
ROP的模型,就是修改栈中LR的值,使其按照攻击者预设的flow返回. 攻击者将一串gadget串在一起,形成一个有效的由现有代码片段组成的新程序:
进程地址空间中可用的任何库都是gadget的潜在来源。 例如,C库包含许多函数,每个函数都提供了潜在的gadget。 有了这么多可用的小工具,统计上就有足够多的小工具可以组成任意的新程序。 有些编译器甚至被设计为编译到gadget,而不是汇编器。 ROP攻击是有效的,因为它是由现有的合法代码组成的,所以它不会被执行权限或从可写内存执行的检查捕获。 对于攻击者来说,查找小工具并创建生成新程序所需的序列是非常耗时的。 但是,这个过程可以自动化,并且可以重用来攻击多个系统。 <font color=red size=4>地址空间随机化(ASLR)</font>可以帮助防止自动和多次攻击的实践。
Armv8.3-A引入了<font color=red size=5>pointer authentication</font>选项。 pointer authentication可以减轻ROP攻击。
指针身份验证利用了指针以64位格式存储的,其实并不是所有这些位都需要表示 地址。 虚拟地址空间的布局如下图所示:
可以看到,任何有效的虚拟地址的前12位都是0x000或0xFFF。 当pointer authenticatio启用时,高比特位用于存储签名,而不作为地址的一部分。 这个签名也被称为Pointer Authentication Code (PAC).
PAC使用指针的高比特位。 bit55位保留来表示是访问顶部区域还是底部区域。 如下所示:
PAC可用的确切位数取决于虚拟地址空间的配置大小,以及是否被标记指针被启用。 虚拟地址空间越小,可用位就越多。
为了防止ROP攻击,在函数的开头对LR中的返回地址进行签名。 这意味着以较高的顺序添加PAC
寄存器的位。 返回前,返回地址是通过PAC认证的,如果检查失败,则返回时产生异常。 下图显示了一个例子:
系统提供了5个128-bit keys. 每一个key都存在64-bit系统寄存器中:
• Two keys, A and B, for instruction pointers
• Two keys, A and B, for data pointers
• One key for general use
这些寄存器只能被EL1及其以上的异常级别操作.
指针签名的模型:
How is the PAC checked?
如下图所示,采用PAC*指令,进行指针签名和指针验签的模型:
instructions introduce
- PACI<font color=red size=4>x</font>SP Sign LR, using SP as the modifier.
- PACIxZ Sign LR, using 0 as the modifier.
- PACIx Sign Xn, using a general-purpose register as modifier.
- AUTIxSP Authenticate LR, using SP as the modifier.
- AUTIxZ Authenticate LR, using 0 as the modifier.
- AUTIx Authenticate Xn, using a general-purpose register as modifier.
- BRAx Indirect branch with pointer authentication.
- BLRAx Indirect branch with link, with pointer authentication.
- RETAx Function return with pointer authentication.
- ERETAx Exception return with pointer authentication.
(<font color=red size=4>注: x是指使用A密钥还是使用B密钥</font>)
Use of the NOP space
为了兼容,在不支持Pointer authentication的处理器上,使用NOP代替AUTIASP
Enabling pointer authentication
SCTLR_ELx:
• EnIx - Enables instruction pointer authentication using key x
• EnDx - Enables data pointer authentication using key x
3、Jump-oriented programming
术语:Jump-Oriented Programming (JOP)
攻击者利用BLR或BR指令可以跳转任何可执行地址,攻击模型如下所示:
Branch target instructions
为了帮助防范JOP攻击,Armv8.5-A引入了Branch target instruction(BTIs)。 BTIs也被称为landing pads。 可以对处理器进行配置,使间接分支(BR和BLR)只能允许目标着陆台指令。 如果一个间接分支的目标不是一个着陆台,一个分支目标异常会生成,如图所示:
Enabling branch target checking
在翻译表中使用一个新的位(GP位),为每个页面启用了对landing pad的支持。 每个页面控件允许文件系统包含landing pad保护代码和legacy代码的混合物,如下所示:
How BTI is implemented?
PSTATE包含一个字段BTYPE,该字段记录了分支类型。 在执行跳转分支时,跳转分支的类型被记录在PSTATE.BTYPE中。 下面的列表显示了BTYPE对于不同跳转分支指令的值:
• BTYPE=11: BR, BRAA, BRAB, BRAAZ, BRABZ with any register other than X16 or X17
• BTYPE=10: BLR, BLRAA, BLRAB, BLRAAZ, BLRABZ
• BTYPE=01: BR, BRAA, BRAB, BRAAZ, BRABZ with X16 or X17
执行任何其他类型的指令,包括直接分支,都会导致BTYPE被设置为b00
关注"Arm精选"公众号,备注进ARM交流讨论区。