Pointer Authentication
Pointer Authentication
指针签名。
64 位机型有大量 bit 位是没有存储信息的,xnu 写死最大 VA 地址是 0x0000000FC0000000ULL,用到 36 位就行了。
https://github.com/apple/darwin-xnu/blob/master/osfmk/mach/arm/vm_param.h#L157
指针签名可以用剩下的比特位来存储。当最高位 tag 位没使用时也可以用来存 pac,最高位 tag 位使用时那就是一个 tag pointer 了,不能用。在 macOS 上 tag 位是最低位,Mac 反正不用 arm 处理器也无所谓了。
objc 源码中搞了这种区分,最高位有效的 tag pointer mask 是 1<<63;最低位有效的 tag pointer mask 是 1。
从这些位操作来看,Mac 或者 iPhone 换 CPU 架构,下辈子吧。
新增的指令
PAC* 系列
原指针 + 上下文 + key = 加签指针
举个栗子,对程序返回地址的保护:
pacia lr, sp 用 sp 作为上下文,APIAKey 作为秘钥对 lr 加签,加签的结果存放到 lr 寄存器里。
authia lr, sp 用 sp 作为上下文,APIAKey 作为秘钥对 lr 验签,验签结果存放到 lr 寄存器里。
ret lr 就受到了保护。
还可以简写成 paciasp 等于 pacia lr, sp
新鲜出炉的 pac 异常,pacibsp。和 paciasp 功能一样,只不过用 b key 加密。
AUT* 和 XPAC*
aut* 就是验签,验证成功后把签名拿掉,得到的结果就是 original pointer;验证失败只能拿到一个 invalid pointer
xpac* 就是裁掉,把签名无差别擦掉,不做验证
使用的算法
苹果魔改过的 QARMA
正向开发的挑战
没啥挑战,dirty work 都在底层,正向开发感受不到。除了……
crash
PAC 验签失败导致的 crash 需要你认真甄别一下 https://developer.apple.com/documentation/security/preparing_your_app_to_work_with_pointer_authentication?language=objc
Exception Subtype: KERN_INVALID_ADDRESS at 0x0040000105394398 -> 0x0000000105394398 (possible pointer authentication failure)
比如这种 crash,苹果想告诉你有地址的 PAC 验签失败了,原地址是 0x0000000105394398,高位被改了,然后必然触发段错误,随后进崩溃基操流程。当然,这里的 PAC 肯定是事先被拿掉了,不拿掉容易被分析。
然后呢,苹果给了一些忠告
Return addresses are signed with a key that’s unique per process, using a salt derived from the stack pointer.
Function pointers are signed with a key that’s fixed across all processes, allowing sharing of library code between processes.
Virtual method table entries are signed with a key that’s shared across all apps, using a salt derived from the method signature.
程序调用里的返回地址用栈指针加盐加签,key 是每个进程独享的,盐就是上下文。实际上就是 paciasp
函数指针 key 是固定的,进程间共享。像这种情况的,内核 reboot 后 key 应该是要刷新了。
虚拟方法表地址 xxxx 看不懂,没用过,C++ 才有的吧
还是 crash
主要是搜集 crash 的那些 Kit,碰到 PAC 的指针得裁一下。不然符号化失败。
看下巨硬的人给提的 PR https://github.com/microsoft/PLCrashReporter-Fork/pull/15/commits
看下是不是 64 位的,是的话直接拿 0x0000000fffffffff 把高位的裁掉。
uint64_tnormalizedInstructionPointer=lp64? (frameInfo.instructionPointer&0x0000000fffffffff) : frameInfo.instructionPointer;
逆向的攻防
https://googleprojectzero.blogspot.com/2019/02/examining-pointer-authentication-on.html
https://speakerdeck.com/marcograss/2pac-2furious-envisioning-an-ios-compromise-in-2019
参考
https://events.static.linuxfound.org/sites/events/files/slides/slides_23.pdf