arm64e
定义
arm64e是苹果为AArch64(arm64)平台定义的一种应用二进制接口变体,它在保留原有arm64调用约定的同时,追加了指针认证(Pointer Authentication)相关的约定与指令[4]。严格来说,它属于ABI而非指令集架构(ISA),因为真正定义指令的是ARMv8.3-A对AArch64的扩展,arm64e只是在编译器与运行时层面规定如何使用这些指令[2]。由于arm64e包含arm64的全部能力,arm64e设备可以直接运行arm64二进制文件,反向则不成立[5]。
在苹果的构建工具链中,arm64e被实现为一个AArch64子架构,默认对应apple-a12处理器,从而能够生成指针认证代码[6]。
原理
指针认证的基本思路,是在存储指针之前,向指针中未被地址使用的若干高位写入一段加密签名,即指针认证码(Pointer Authentication Code,PAC);读取指针时再由另一条指令移除并校验该签名。两次访问之间对被存储值的任何改动都会令签名失效,CPU会把认证失败视为内存损坏,通过置位高位使指针失效,进而导致程序崩溃。
每段PAC由原始指针值、一个最多64位的修饰值(modifier)以及一枚硬件的128位密钥共同派生,可写作 $PAC = H_K(A_p, M)$,其中 $K$ 为密钥,$A_p$ 为指针地址,$M$ 为修饰值[7][8]。ARMv8.3-A为此提供了若干密钥,包括指令用A密钥、指令用B密钥、数据用A密钥与数据用B密钥;常见指令有用于签名的PACIA、PACIB与用于认证的AUTIA、AUTIB,以及把认证与跳转合并执行的BLRAA、BLRAB等[7][9]。
修饰值的选取决定了防护的粒度。若修饰值包含指针的存储地址,则同一指针存放在不同位置会得到不同签名,攻击者无法直接把指针复制过去使用;若使用常量修饰值,则可通过声明或类型派生,例如对声明文本或类型文本取哈希得到16位常量[10][11]。在arm64e的约定中,返回地址使用每进程唯一的密钥并以栈指针派生的盐值签名,函数指针使用跨进程固定的密钥,虚方法表条目则使用全应用共享的密钥并以方法签名派生盐值。
发展历程
指针认证的硬件能力源自ARM在Armv8.3-A中对AArch64的扩展,该扩展加入检测指针值被篡改的功能,用于缓解栈破坏等攻击并提高面向返回编程(ROP)的难度[12]。相关支持在GCC与LLVM/Clang中以返回地址签名选项的形式出现,并陆续进入ARMv8.3及其后续的架构规范[8]。
苹果自Apple A12处理器起在芯片中引入这一技术,A12即用于iPhone XR、iPhone XS等机型[1]。2018年发布的Xcode 10.1加入了对arm64e的预览支持,开发者可在目标的架构设置中加入arm64e以构建该切片,但当时的App Store与TestFlight不接受含arm64e内容的提交,分发时Xcode会移除相关内容。
此后随着PAC实现被发现弱点并被修复,苹果多次调整arm64e的ABI。iOS 14与Xcode 12(或clang 1200及更新版本)起,该ABI发生变更,新编译器产出的二进制与iOS 12.0至13.7上的arm64e实现不再兼容[13]。苹果自身的内核缓存、系统应用与整个动态链接共享缓存都以arm64e编译,而面向第三方的arm64e支持长期被认为尚未稳定[3]。
应用
arm64e主要运行在具备相应硬件的苹果平台上。使用Apple A12或更新A系列处理器的设备,例如iPhone XS、iPhone XS Max、iPhone XR与第二代Apple TV 4K,以及Apple Watch Series 4及更新机型、搭载Apple芯片的Mac与iPad均支持该架构。测试这类二进制必须在实体设备上进行,模拟器无法用于验证。
在系统层面,苹果把指针认证用于保护控制流:编译器会自动对间接分支相关的指针进行签名与认证,覆盖函数返回地址、C函数指针、C++虚函数以及经由全局偏移表(GOT)的符号导入等场景[11]。工具链还为确需手动处理的场景提供了ptrauth头文件与相关内建接口,用于剥离或重签指针。为兼顾新旧代码,应用可采用胖二进制的方式同时包含arm64与arm64e两个切片,以分别适配两套ABI[4]。
局限
指针认证只是一种近似的指针完整性机制,并不能提供完全的防护。攻击者可以通过重用已有的PAC来绕过校验,例如当两条函数返回地址使用相同的栈指针修饰值时,签名之间可能变得可互换[8]。在arm64e的实现中,常量修饰值被限制为16位,碰撞虽不常见但仍可能发生[10]。
签名机制也会对代码施加限制。当修饰值包含存储地址时,指针无法用memcpy这类逐字节复制的方式搬移,需要重新签名[11]。开启指针认证还可能暴露出既有代码中原本隐藏的问题,例如在C++中用与定义不同的声明调用虚方法,在arm64上往往能通过,在arm64e上却会触发认证失败。
此外,认证失败与其它非法内存访问的表象可能相似:高阶位被错误设置时,也可能表现出类似指针认证失败的症状,这给问题定位带来困难。ABI的多次调整也意味着不同版本工具链产出的arm64e二进制之间存在兼容性限制[13]。
参见
参考资料
- [llvm-dev] [RFC] Pointer authentication for arm64e [引用日期2026-10-14]
- stackoverflow.com 上的网页 [引用日期2026-10-14]
- Revisions to Arm64e architecture for iOS framework [引用日期2026-10-14]
- JEP draft: Arm64e support for MacOS/AArch64 [引用日期2026-10-14]
- googlesource.com 上的网页 [引用日期2026-10-14]
- ToolChain [引用日期2026-10-14]
- iu.edu 上的网页 [引用日期2026-10-14]
- A! [引用日期2026-10-14]
- arm.com 上的网页 [引用日期2026-10-14]
- Pointer Authentication# [引用日期2026-10-14]
- What is arm64e? [引用日期2026-10-14]
- iu.edu 上的网页 [引用日期2026-10-14]
- arm64e Deployment - You signed in with another tab or window [引用日期2026-10-14]