arm64e 架构简介——指针验签

18,231 阅读3分钟

基本概念

  • arm64e基于ARMv8.3架构,相对于arm64增加了一系列功能,其中最重要的一个是:指针验签
  • ARMv8.3在苹果A12 CPU上可用(2018年9月以后发布的iPhone机型,如iPhone XR/XS
  • AArch64ARMv8-A以后支持的一种64位运行模式
    • AArch32是32位运行模式,早期的ARM架构都支持

指针验签

  • 是一种安全防御机制
  • 能保证控制流不被篡改(CFI),也提供有限的数据完整性保证
  • 对程序运行过程中操作的指针内容进行签名,并在使用前验签,以防止被恶意篡改

解决的问题

  • 内存溢出攻击
    • 黑客在掌握内存溢出漏洞后,会试图修改间接跳转的指针地址以重定向到他指定的代码位置,然后通过ROPJOP等方式构造特定的指令执行序列来完成攻击流程
  • 指针验签通过防止指针重定向来避免内存溢出攻击

攻击方式

  • 攻击者首先找到一系列需要的指令片段(gadgets
    • 攻击者希望执行以下指令:
    • 攻击者实际找到的指令片段:
  • 攻击者需要按一定的顺序调用这些指令片段,一般有以下两种方式:
    • ROPReturn-Oriented Programming):重定向方法return时执行的目标,通过控制方法返回的顺序来控制执行流程
    • JOPJump-Oriented Programming):重定向方法调用的目标,构造一系列方法跳转顺序来控制执行流程

工作原理

  • 对所有的代码段指针都增加一段签名
    • 部分数据段指针也会签名
  • 在所有间接跳转前验签
    • 数据段指针是在读内存前验签
  • 签名数据存在指针数据的高位部分
    • 指针一共64位,其中高位的25位没有使用,就用这些位来存放签名数据
    • 签名算法为:hash(pointer, key, salt),其中:
      • key是有限的集合(ABI决定)
      • 主要变量在saltABI决定),取决于:
        • 是否支持地址多样性
          • salt中含有存储指针的变量地址信息
          • 同一指针的不同实例也会有不同的签名
          • 指针拷贝需要重新签名
          • memcpy不兼容,导致拷贝开销增大
        • 如何选择较小的常量数值
          • 16位整型常数
          • 对变量声明取hash
          • 对变量类型取hash
      • 以下涉及跳转的代码都会受到验签保护(编译器决定)
        • return
          • 盐值来自自栈指针(sp)哈希,整个进程唯一
        • c函数指针
          • 盐值是所有进程唯一的,方便各进程共享库代码
        • switch
        • c++虚函数
          • 盐值来自方法签名,所有app之间共享
        • 导入函数(GOT
        • 其他
  • 签名、验签流程
    • 指针内容(如:c方法地址
    • 签名:根据签名算法得到签名,填充到指针数据高位
      • 指令:PACIA Xd, Xn
    • 验签:取出高位的签名数据,验证后,将高位清零,使指针成为系统合法的指针
      • 指令:AUTDB Xd, Xn

编译生成产物和流程示意

  • LLVM IR:

  • 机器指令:

参考资料

最后,欢迎大家关注我的微信公众号,有空多多交流