最近,苹果公司推出了自家研发的芯片M1 SoC,其中含有许多有趣且未公然的硬件新特征,例如SPRR机制可用于重新界说页表权限位的寄义,而GXF机制则引入了横向执行级别。在这篇文章中,我们将为读者详细先容这些新特征,以及苹果公司是若何行使它们来珍爱macOS系统的。

简介

一年多以前,siguza揭晓了一篇关于Apple的APRR机制的文章。现实上,APRR是一个定制的ARM扩展,用于重新界说页表权限,并珍爱内核的某些部门不受其影响。往后,苹果公司宣布了M1芯片,该芯片不仅具有更新的APRR版本,而且在启动后不久就可以轻松地运行裸机代码。虽然关于新版本的听说颇多,但苹果公司尚未公然其使用文档。

现在,是时刻改变这种状态了!

在本文的第一部门中,我们将对aarch64架构的内存治理、页表和用户/内核模式举行简朴先容。同时,我们还将简要回首APRR,与之前的Apple SoC功效相当。若是您已经熟悉这部门内容的话,读起来可能会对照无聊,以是不妨跳过这部门内容。 

之后,我们将进入本文的主题,即通过逆向剖析,领会SPRR和GXF机制的事情原理及其作用。若是您想知道我是若何应对这一挑战的,那么这一部门会让您很感兴趣。若是您只想领会SPRR和GXF到底是什么东东的话,请直接接见Asahi Linux的维基页面。

MMU、页表与内核

对于ARM架构来说,CPU是在所谓的异常级别中运行的;在x86架构种,这些运行级别被称为环。其中,EL0是应用程序的运行级别,EL1(通常)是内核自己的运行级别,EL2是治理程序的运行级别。此外,EL3用于固件或Trust Zone的运行级别,但M1并不支持这个级别。

在具有虚拟化主机扩展特征的ARM64 CPU上,还提供了一种可以使EL2看起来像EL1的方式,这样一来,内核也可以很容易地在EL2级别运行。 

内核的义务之一,就是给运行在用户空间的每个应用程序制造一种假象,让它们以为整个地址空间都是被它自己独占的。现实上,内核是通过内存治理单元来做到这一点的。行使MMU,可以确立从虚拟地址到现实物理地址(好比内存的物理地址)的别名。这种映射的最小粒度被称为页,页的长度通常为4KiB。而且,每个内存页都有一个虚拟地址和一个物理地址。当一个应用程序或内核自己的指令试图接见位置x处的内存时,MMU会在其页表中查找该页,并返回位于另一个地址y处的内存。这就是内核为每个用户空间中的应用程序“变出”一套自力的内存空间的魔术:只需为各个历程确立一组差其余页表即可。

除了举行上述映射之外,MMU还为每个内存页预留了四个比特位,用来编码某些接见标志。这些标志决议了是否允许用户态应用程序或内核自己对该内存页举行读写接见,或者从该内存页执行。在ARMv8-A CPU的每个页表项中可以找到以下四个位。 

·    UXN(Unprivileged Execute never,UXN):绝不允许用户态(即EL0运行级别)的代码从这一页执行。

·    PXN(Privileged execute never,PXN):绝不允许内核(即EL1运行级别)的代码从这一页执行

·    AP0和AP1:它们只是一种略显杂乱的方式,用于编码内核和用户态的四种读写权限:rw/--、rw/rw、r-/-和r-/r-。 

在确定最终的接见标志时,还涉及其他一些庞大的机制(PAN,分层控制),本文就不多讲了。这里需要注重的是,用户态和内核态的权限是慎密耦合的,也就是说,我们不能能确立这样一个内存页:用户态代码对该内存页的接见权限为rw-,同时,内核态代码对该内存页的接见权限为r-。

APRR

如前所述,每个内存页都有四个标志位,用来控制EL0/1(用户模式/内核模式)的接见权限(读/写/执行)。然则,APRR完全改变了这种做法:不是将这四个标志位存储到页表项中,而是将其用作一个单独的表的索引(即,不是直接对接见权限举行编码,而是将这些位合并为一个4位的索引,即[AP1][AP0][PXN][UXN])。然后,通过这个单独的表对内存页的现实权限举行编码。此外,还可以通过某些寄存器进一步限制用户空间的这些权限。这些寄存器对于内核和用户空间也是自力的,因此,使得确立内存页的权限时具有很大的天真性。 

APRR通过这种方式为页表权限引入了一个间接层,以便于通过单个寄存器写操作来异常高效地一次翻转多个页面的接见权限。通常情形下,这需要一个开销异常伟大的页面遍历历程来逐个修改页表项。

此外,这方面的更多的细节请参阅siguza的相关文章。

JIT编译器

通常,应用程序需要先从高级语言编译为机械代码,然后再举行分发。这种情形下,由于该代码是牢靠的,也就是说,代码在运行时通常不会再举行修改了,因此可以将其权限映射为r-x。

与上面差其余是,JIT编译器是动态天生气器代码的。在传统上,这需要将内存区域映射为rwx权限,这样才气把天生的机械代码写入内存并执行。

不外,苹果公司打心底里不喜欢这种映射,由于在他们的心目中,最好对iPhone的CPU上执行的每一条指令都举行署名。若是任何应用程序都可以请求rwx映射,那么这个设想就变得毫无意义,由于应用程序可以直接运行它想要的任何指令。纵然只有一些应用程序有权举行这种映射,这些应用程序也会成为被攻击的目的。一旦某个内存区域存在rwx映射,攻击者所需要做的事情就是在那里编写shellcode并跳转执行这些代码。固然,找到这样的内存区域并获得随便写入和跳转gadget仍然是一个挑战。 

然则,苹果公司仍然希望使用JIT编译器。或者说,好吧,他们真的是别无选择:之以是需要JIT编译器,是由于Javascript已经无处不在。 

那么,若何解决这个难题呢?固然是借助于APRR。某些用户态应用程序(好比,iOS上的Safari,macOS上的每个应用程序)能够请求一个特殊的内存区域(使用mmap、MAP_JIT和pthread_jit_write_protect_np——凭证saagarjha的说法,Safari现实上使用了os_thread_self_restrict_rwx_to_r{w,x},这可能具有同样的效果),该内存区域可以在rw-和r-x之间快速切换。现实上,这种切换是通过翻转APRR寄存器中的两个位来实现的,从而“盖住”JIT内存页的w权限并“露出”x权限,从而立刻将所有这些内存页的权限从rw-变为r-x,反之亦然。

内存页珍爱层

如前所述,若是可能的话,苹果希望在所有可执行内存页上强制执行代码署名。在iOS上,这些署名必须来自苹果自己,而在macOS上,使用内陆确立的暂且署名就足够了。通常情形下,代码署名是由内核强制执行的。然则,内核也有许多不相关的代码,好比装备驱动程序,这就形成了一个伟大的攻击面:任何驱动程序中的任何错误都足以绕过代码署名(这种说法并不完全准确,由于攻击者还需要借助于信息泄露破绽,才气以ROP的方式对页表举行写操作)。不外,这个问题在良久以前就已经被视频游戏机解决了:微软的Xbox 360治理程序只是一小段代码,基本上只执行代码署名和同样主要的义务。与其确保所有内核代码中没有可行使的平安破绽,不如确保治理程序自己没有严重的平安破绽就够了。然则,只要在治理程序中发现一个严重的平安破绽,也可能导致整个防线溃逃。 

,

Usdt第三方支付平台

菜宝钱包(www.caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

,

同样地,苹果公司使用APRR在内核自己内部实现了一个对性能影响很低的治理程序。首先,将页表(和其他存有主要数据结构的内存)重新映射为只有内核自己才气举行只读操作。此外,一小部门特权代码,称为PPL,也被映射为只读权限。然后,使用一个小型的蹦床函数,通过APRR将页表重新映射为rw-,将PPL代码重新映射为r-x,然后跳到那里。由于这个小蹦床函数是PPL代码的唯一入口,以是,它类似于一个hypercall指令,而PPL自己就像一个开销异常低的治理程序。更多的细节,请参阅Jonathan的相关文章。

SPRR

用户态JIT

如前所述,Apple Silicon上的JIT可以分配一个特殊内存区域,其权限可以在rw-和r-x之间快速切换。在以前的SoC中,这是用APRR来实现的,这为研究SPRR提供了一个好的起点。

凭证苹果公司关于JIT编译器的官方文档中的先容,_pthread_jit_write_protect_np函数在M1上仍然执行上述权限切换。现实上,我们可以先用otool -xv /usr/lib/system/libsystem_pthread.dylib来弄清晰幕后发生了什么。下面展示的是来自这个函数的相关指令:

_pthread_jit_write_protect_np:
[...]
0000000000007fdc        movk    x0, ,0xc118
0000000000007fe0        movk    x0, ,0xffff, lsl ,16
0000000000007fe4        movk    x0, ,0xf, lsl ,32
0000000000007fe8        movk    x0, ,0x0, lsl ,48
0000000000007fec        ldr     x0, [x0]                ; Latency: 4
0000000000007ff0        msr     S3_6_C15_C1_5, x0
0000000000007ff4        i *** 
[...]

首先,上面的代码从常量地址0xfffffc118处加载一个64位整数,然后,把它写到系统寄存器S3_6_C15_C1_5中。厥后的代码功效与之类似,区别在于这次是从0xfffc110处加载新的系统寄存器值。这些地址属于一个被称为commpage的内存区域。现实上,这个页面将被映射到每个用户态历程中,其中包罗了由内核露出给用户空间的种种变量。

不出所料,在commpage中设置这些变量的代码并没有公然在开源的XNU代码中。然而,在XNU代码中,有对前一代APR代码所使用的cp_aprr_shadow_jit_rw的引用。 

下面,我们用一个小巧的c程序来转储这些代码:

,include
,include
 
int main(int argc, char *argv[])
{
  uint64_t *sprr = (uint64_t *)0xfffffc110;
  printf("%llx %llx\n", sprr[0], sprr[1]);
}

这里天生了两个值,即0x2010000030300000和0x2010000030100000,它们用于实现JIT页面的r-x和rw-权限之间切换。到现在为止,看起来一切都还不错。这与APRR已往的事情方式异常类似,但这里使用了差其余寄存器,其中包罗差其余幻数,以是,我们必须搞清晰其中的奇妙。

有了这个关于SPRR的大略看法,我们现在就可以反汇编内核的代码,以寻找使用这些或周围寄存器的函数。不外,我已经不像以前那样喜欢折腾反汇编了。(但话说回来,我确实喜欢低级硬件逆向工程,以是当涉及到兴趣时,我的话您也不必全信)。不外,内核也纷歧定能够辅助我们领会各个位简直切寄义:寄存器可能只是用一个神奇的常数初始化了一次,然后就再也没有碰过了。

幸运的是,我们另有另一种选择:暴力测试!不停实验翻转我们找到的寄存器中的位,看看有何反映。我们甚至可以从一个在M1上运行的通俗用户空间程序最先下手。

我们可以做的第一件事是实验将每一个位设置为0和1。 

,include
,include
,include
,include
 
 
void write_sppr(uint64_t v)
{
    __a *** __ __volatile__("msr S3_6_c15_c1_5, %0\n"
                         "i ***  sy\n" ::"r"(v)
                         :);
}
 
uint64_t read_sppr(void)
{
    uint64_t v;
    __a *** __ __volatile__("i ***  sy\n"
                         "mrs %0, S3_6_c15_c1_5\n"
                         : "=r"(v)::"memory");
    return v;
}
 
 
int main(int argc, char *argv[])
{
    for (int i = 0; i < 64; ++i) {
        write_sppr(1ULL<<i);
        printf("bit %02d: %016llx\n", i, read_sppr());
    }
}

我们很快就发现,除了我们在commpage中发现的两个位之外,险些所有的位都被锁定为初始值。我们还发现,这些征象在某种水平上与JIT页面的权限有关。我们可以用mmap来映射这样的页面。由于从一个受读或写珍爱的页面中读出或写入会发生一个SIGBUS信号;跳转到一个不能执行的页面会发生一个SIGSEV信号,因此,我们可以通过设置信号处置程序来捕捉用户态应用程序中的这些信号。我们只需要这些工具就可以领会这些位若何映射到页面权限!

为了从接见受珍爱页面中恢复过来,我们设置了下面的信号处置程序,它将把x0设置为一个魔术常量,然后在返回之前递增程序计数器:

void bus_handler(int signo, siginfo_t *info, void *cx_)
{
    ucontext_t *cx = cx_;
    cx->uc_mcontext->__ss.__x[0] = 0xdeadbeef;
    cx->uc_mcontext->__ss.__pc += 4;
}
 
从执行不能执行的内存页中举行恢复的历程与之类似:将程序计数器设置为链接寄存器,并在x0中存储一个魔术值:
 
void sev_handler(int signo, siginfo_t *info, void *cx_)
{
    ucontext_t *cx = cx_;
    cx->uc_mcontext->__ss.__x[0] = 0xdeadbeef;
    cx->uc_mcontext->__ss.__pc = cx->uc_mcontext->__ss.__lr;
}

剩下的事情,就是用MAP_JIT映射一个内存页面,并实验对该内存举行读、写或执行操作,看看它们对应于系统寄存器哪些值(共有四个可能的取值)。

SPRR JIT测试代码

下面,我们给出寄存器的值与页面权限之间的对应关系:

 

 这比APRR的事情方式简朴多了:与APRR使用两个寄存器来设置权限并屏障其他的权限差异,这里只能将其改为上面的四个值中的一个。此外,对于履历老道的黑客来说,可以行使APRR在用户空间确立rwx映射;不外,该方式在这里就行不通了:由于没有设施对其举行编码。据推测,系统寄存器中的差异字节对应于页表项中编码的16种差其余可能权限。这使得一半的系统寄存器的寄义完全未知!

我们现在可能已经从macOS用户空间中找到了所有我们能找到的器械,现在是时刻拿出一些更壮大的工具来真正明白这个新的硬件功效是若何事情的了。

原本,我还以为可以直接行使苹果的Hypervisor.framework在EL1级别中运行自己的代码,并研究SPRR在那里的显示。然则,不幸的是,每一次对可能与SPR有关的寄存器的接见总是泛起问题。哦,好吧。幸运的是,我们有更壮大的工具可以在“裸机”上运行EL2级其余代码。

m1n1

在此之前,iPhone黑客必须对XNU举行静态逆向剖析,或者通过其他途径获得EL1级其余权限,然后通过实验来领会新硬件。这使得他们的所有成就加倍令人印象深刻。然而,现在就不用这么穷苦了:苹果公司已经宣布了M1,它不仅提供了新的硬件特征,还允许我们在指导历程的早期运行未署名的代码。

作为旨在为M1引入上游Linux支持的Asahi Linux项目的一部门,marcan曾向导开发了一个小型指导加载程序/硬件实验平台,名为m1n1。m1n1与XNU一样,都能在所有硬件保持原始状态的情形下获得控制权。虽然以下所有的事情也可以通过手动编写shellcode在EL2中运行来完成,但若是使用m1n1的话,则可以让这些事情变得很有趣(条件是您认同我对有趣的界说)。

小结

最近,苹果公司推出了自研芯片M1 SoC,其中含有许多有趣且未公然的硬件新特征,例如SPRR机制可用于重新界说页表权限位的寄义,而GXF机制则引入了横向执行级别。在这篇文章中,我们将为读者详细先容这些新特征,以及苹果公司是若何行使它们来珍爱macOS系统的。由于篇幅较长,我们将分为上下文举行揭晓,更多精彩内容,敬请期待! 

本文翻译自:https://blog.svenpeter.dev/posts/m1_sprr_gxf/

万利逆熵

万利逆熵网(www.ipfs8.vip)是FiLecoin致力服务于使用FiLecoin存储和检索数据的官方权威平台。IPFS网实时更新FiLecoin(FIL)行情、当前FiLecoin(FIL)矿池、FiLecoin(FIL)收益数据、各类FiLecoin(FIL)矿机出售信息。并开放FiLecoin(FIL)交易所、IPFS云矿机、IPFS矿机出售、租用、招商等业务。

Allbet声明:该文看法仅代表作者自己,与www.allbetgame.us无关。转载请注明:ipfs算力(www.ipfs8.vip):揭秘Apple Silicon中的新硬件特征:SPRR与GXF珍爱机制(上)
发布评论

分享到:

baccarat:难舍!26年迈字号易主 中超官宣河南建业更名河南嵩山龙门
2 条回复
  1. 新二皇冠最新手机登录(www.22223388.com)
    新二皇冠最新手机登录(www.22223388.com)
    (2021-09-17 00:05:11) 1#

    Allbet注册www.aLLbetgame.us),欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

    真的征服到我了

  2. usdt套利(www.usdt8.vip)
    usdt套利(www.usdt8.vip)
    (2021-11-15 00:01:55) 2#

    同时,配合实价登录2.0,预售屋生意亦纳入「房地合一2.0」局限,税基为卖出价钱与购置价钱的赚钱金额,盘算持有时间为购入签约时间与卖出签约时间。若预售屋转为成屋,持有年度将重新盘算。作者大大好棒

发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。