欢迎进入环球UG官网(UG环球),环球UG官方网站:www.ugbet.us开放环球UG网址访问、环球UG会员注册、环球UG代理申请、环球UG电脑客户端、环球UG手机版下载等业务。

首页科技正文

万利矿业(www.ipfs8.vip):揭秘Apple Silicon中的新硬件特征:SPRR与GXF珍爱机制(下)

admin2021-06-0117技术

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

(接上文)

通过Python探索未知的系统寄存器

现实上,m1n1最大的特点就是:允许直接通过python shell来操作硬件,而不是重新编译和重新加载shellcode,以及通过python来处置数据提取和所有这些恼人的琐事。marcan最近还合并了我的USB gadget代码,因此,人人要想复现这些实验的话,只要一台M1 Mac和一根通俗的USB线就能搞定了。

让我们从运行proxyclient/shell.py最先。不幸的是,接见用户态的SPRR寄存器只是触发了一个异常。(但我注重到,m1n1很快从这个异常中恢复过来了,基本不需要重启!)

>>> u.mrs((3, 6, 15, 1, 5))
TTY> Exception: SYNC
TTY> Exception taken from EL2h
TTY> Running in EL2
TTY> MPIDR: 0x80000000
TTY> Registers: (@0x8046b3db0)
TTY>   x0-x3: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
TTY>   x4-x7: 0000000810cb8000 0000000000007a69 0000000804630004 0000000804630000
TTY>  x8-x11: 0000000000000000 00000000ffffffc8 00000008046b3eb0 000000000000002c
TTY> x12-x15: 0000000000000003 0000000000000001 0000000000000000 00000008046b3b20
TTY> x16-x19: 00000008045caa80 0000000000000000 0000000000000000 000000080462b000
TTY> x20-x23: 00000008046b3f78 00000008046b3fa0 0000000000000002 00000008046b3f98
TTY> x24-x27: 00000008046b3f70 0000000000000000 0000000000000001 0000000000000001
TTY> x28-x30: 00000008046b3fa0 00000008046b3eb0 00000008045bad90
TTY> PC:       0x810cb8000 (rel: 0xc70c000)
TTY> SP:       0x8046b3eb0
TTY> SPSR_EL1: 0x60000009
TTY> FAR_EL1:  0x0
TTY> ESR_EL1:  0x2000000 (unknown)
TTY> L2C_ERR_STS: 0x11000ffc00000000
TTY> L2C_ERR_ADR: 0x0
TTY> L2C_ERR_INF: 0x0
TTY> SYS_APL_E_LSU_ERR_STS: 0x0
TTY> SYS_APL_E_FED_ERR_STS: 0x0
TTY> SYS_APL_E_MMU_ERR_STS: 0x0
TTY> Recovering from exception (ELR=0x810cb8004)
Traceback (most recent call last):
  File "/opt/homebrew/Cellar/python@3.9/3.9.4/Frameworks/Python.framework/Versions/3.9/lib/python3.9/code.py", line 90, in runcode
    exec(code, self.locals)
  File "
  File "/Users/speter/asahi/git/m1n1/proxyclient/utils.py", line 80, in mrs
    raise ProxyError("Exception occurred")
proxy.ProxyError: Exception occurred
>>>

然则,内核必须能够在上下文切换时代修改这个寄存器。这就意味着可能存在一些使能位。幸运的是,m1n1存储库中已经提供了一个现成的python工具,可用于查找所有可用的系统寄存器。该工具的内部运作方式为:为所有寄存器天生响应的mrs指令,并从未界说寄存器引起的异常中恢复。下面,让我们运行它并寻找四周的寄存器: 

$ python3 proxyclient/find_all_regs.py | grep s3_6_c15_c1_
s3_6_c15_c1_0 (3, 6, 15, 1, 0) = 0x0
s3_6_c15_c1_2 (3, 6, 15, 1, 2) = 0x0
s3_6_c15_c1_4 (3, 6, 15, 1, 4) = 0x0

这里给出了三个候选寄存器。若是将0x1写入第一个候选寄存器,似乎会导致m1n1无法正常事情——很显著,这说明m1n1是从具有rwx权限的页面运行的。SPRR寄存器最初的值为0x0,这意味着没有任何接见权限。若是SPRR突然启动,使CPU以为rwx现实上是---,会发生什么?一切都完了,由于没有可以读取或执行的内存了。 

现在,让我们禁用MMU,并再次将0x1这些寄存器(并很快注重到第三个寄存器似乎只是引发了故障并忽略了该故障),然后,查找所有寄存器,最后确定新的寄存器。这一切都可以通过几行python代码来完成: 

with u.mmu_disabled():
    for reg in [(3, 6, 15, 1, 0), (3, 6, 15, 1, 2)]:
        old_regs = find_regs()
        u.msr(reg, 1)
        new_regs = find_regs()
 
        diff_regs = new_regs - old_regs
 
        print(reg)
        for r in sorted(diff_regs):
            print("  %s" % list(r))
 
    u.msr((3, 6, 15, 1, 2), 0)
    u.msr((3, 6, 15, 1, 0), 0)

哦,天哪,有许多新的寄存器被启用了!

启用的系统寄存器

接下来,让我们把S3_6_C15_C1_0更名为SPRR_CONFIG_EL1。这里的第1位启用了SPRR,设置所有的位似乎可以锁定所有的SPRR寄存器,以作进一步的修改。S3_6_C15_1_2和它所启用的寄存器对于第二部门内容来说是异常主要的。

而我们现在确实可以翻转S3_6_C15_C1_5的所有位了:

>>> p.mmu_shutdown()
TTY> MMU: shutting down...
TTY> MMU: shutdown successful, clearing cache
>>> u.msr((3, 6, 15, 1, 0), 1)
>>> u.mrs((3, 6, 15, 1, 5))
0x0
>>> u.msr((3, 6, 15, 1, 5), 0xffffffffffffffff)
>>> u.mrs((3, 6, 15, 1, 5))
0xffffffffffffffff
>>>

虽然这个寄存器可能适用于EL0,但我们在这里的运行级别为EL2。我们可以做一个有凭证的展望,假设新启用的寄存器S3_6_C15_C1_6可能是用于EL1级其余,S3_6_C15_C1_7用于EL2。M1总是与HCR_EL2.E2H一起运行,它(除其他外)将对EL1寄存器的接见重定向到其EL2对应的寄存器。我们可以用下面的实验来验证我们的展望:

>>> u.msr((3, 6, 15, 1, 6), 0xdead0000)
>>> u.mrs((3, 6, 15, 1, 7))
0xdead0000
>>>

到现在为止,看起来还很顺遂:现在,我们可以启用SPRR机制了,而且发现了一个可疑的寄存器——它很可能与EL2权限有关。下面,我们将重复在用户态下面的实验了,以领会这些寄存器中上面先容的四位以外的内容了。

逆向剖析SPRR寄存器

我们可以编写一些python代码,来确立一个简朴的页表,然后重复我们在用户态下面所做的那些实验。首先,映射一个页面,使其具备S3_6_C15_C1_6对应的权限,然后,实验对其中的内存举行读/写/执行操作。 

为了通过python代码完成上述操作,必须对m1n1自己举行一些侵入性的修改,使其从r-x内存页运行,并将其客栈分配到具有rw-权限的内存页中。我们要力争通过Python完成尽可能多的设置事情,然后,编写一些shellcode并在其他CPU核上运行,这能够让事情容易得多:纵然其中一个挂掉了,在重启之前,至少尚有其他的可用。   

pagetable = ARMPageTable(heap.memalign, heap.free)
pagetable.map(0x800000000, 0x800000000, 0xc00000000, 0)   , normal memory, we run from here
pagetable.map(0xf800000000, 0x800000000, 0xc00000000, 1)  , probe memory, we'll try to read/write/execute this
, ...
code_page = build_and_write_code(heap, """
    // [...]
                // prepare and enable MMU
                ldr x0, =0x0400ff
                msr MAIR_EL1, x0
                ldr x0, =0x27510b510 // borrowed from m1n1's MMU code
                msr TCR_EL1, x0
                ldr x0, =0x{ttbr:x}
                msr TTBR0_EL1, x0
                mrs x0, SCTLR_EL1
                orr x1, x0, ,5
                msr SCTLR_EL1, x1
                i *** 
    // [...]
""".format(ttbr=pagetable.l0)
, ...
ret = p. *** p_call_sync(1, code_page, sprr_val)
, ...

这样一来,已往的信号处置程序现在酿成了一个小型的异常向量。我们在这里所做的只是修改一个寄存器来指示故障,然后在返回之前让程序计数器再跳过两条指令即可。第一条指令是发生故障的那条,我们不想再运行它了。第二条指令是mov x10, 0x80,示意接见乐成,若是我们遇到了异常,接见一定就不乐成了。

_fault_handler:
, store that we failed
mov x10, 0xf1
 
mrs x12, ELR_GL2  , get the PC that faulted
add x12, x12, 8   , skip two instructions
msr ELR_GL2, x12  , store the updated PC
 
i *** 
, eret restores the state from before the exception was taken
eret
 
 
_sprr_test:
, ...
 
, test read access, x1 contains an address to a page for which we modify the SPRR register values
mov x10, 0    , x10 is our success/failure indicator
ldr x1, [x1]  , this instruction will fault if we can't read from [x1]
mov x10, 0x80 , this instruction will be skipped if the previous one faulted

通过上面的事情,我们最终获得了所有16种可能设置的寄义:

  

很显著,这里有些地方很新鲜。在大多数情形下,较低的两个比特指定了权限。但有两个破例情形,较高的位也会以某种方式改变权限。0111似乎不允许接见一个本应是rw-权限的页面,而1001通常应该是可读和可执行的,但这里只有可执行权限。

按理说,基本就没有需要再虚耗两个比特来编码这个权限。乍一看,这可能是用于处置用户与内核的write-or-execute权限。但我们知道,EL0使用的是一个完全差其余寄存器。那么,这还能是什么作用呢?

受珍爱的异常级别/GXF

从上一节我们知道,在PPR寄存器中编码了一些新鲜的器械。此外,之前我们也曾提到了受珍爱的异常级别,它与通例的异常级别是差其余。显然,这些是由0x00201420和0x00201400这两条被称为genter和gexit的定制指令触发的。 

让我们把XNU附加到反汇编程序中,看看能否通过otool -xv /System/Library/Kernels/kernel.release.t8101找到一些可疑的器械。在查找这些指令时,发现了如下所示的可疑指令,它也恰幸亏初始化早期被挪用: 

fffffe00071f80f0        mov     x0, ,0x1
fffffe00071f80f4        msr     S3_6_C15_C1_2, x0
fffffe00071f80f8        adrp    x0, 2025 ; 0xfffffe00079e1000
fffffe00071f80fc        add     x0, x0, ,0x9d8
fffffe00071f8100        msr     S3_6_C15_C8_2, x0
fffffe00071f8104        adrp    x0, 2025 ; 0xfffffe00079e1000
fffffe00071f8108        add     x0, x0, ,0x9dc
fffffe00071f810c        msr     S3_6_C15_C8_1, x0
fffffe00071f8110        i *** 
fffffe00071f8114        mov     x0, ,0x0
fffffe00071f8118        msr     ELR_EL1, x0
fffffe00071f811c        i *** 
fffffe00071f8120        .long   0x00201420
fffffe00071f8124        ret

还记得S3_6_C15_C1_2吗?(我那时印象深刻,由于对我来说,所有这些数字看起来都一样。)这是我们前面找到的第二个使能寄存器,也是这里使用的第一个寄存器。然后,将两个指针写入未知系统寄存器,最后执行未界说的指令0x00201420。第一个指针只是指向一个无限循环,但第二个指针指向一个函数,它似乎也使用了我们前面找到的SPRR寄存器。

因此,S3_6_C15_C8_1中可能是一个指针,一旦0x00201420被执行,处置器就会跳转到这个指针。第二条未知指令0x00201420似乎在那时恢复执行。这一切听起来与治理程序挪用的事情方式异常相似。0x00201420对应于 *** c,以捕捉到EL3权限,0x00201400是eret,将我们带回EL2级别。差其余是,对于这种新的执行模式,没有找到差其余页表。还记得SPRR寄存器中未知的两个位吗?若是这些对应于GL2的页面权限呢? 

我们可以通过使用与之前相同的方式,再次用m1n1快速验证这一点。我们在珍爱性执行模式下设置异常向量,并重复同样的实验。 

然则,我们若何在这种新模式下设置异常向量呢?通常有一个叫VBAR的寄存器来实现这个目的。让我们简朴看看S3_6_C15_C10_2所指向的代码,它是XNU在genter之后首先设置的寄存器之一。   

fffffe00079e0000        b       0xfffffe00079e15d0
fffffe00079e0004        nop
fffffe00079e0008        nop
fffffe00079e000c        nop
[...]
fffffe00079e007c        nop
fffffe00079e0080        b       0xfffffe00079e1000
fffffe00079e0084        nop
[...]
fffffe00079e00fc        nop
fffffe00079e0100        b       0xfffffe00079e11f0
fffffe00079e0104        nop
[...]

唷,这看起来像是一个异常向量表,这意味着S3_6_C15_C10_2是VBAR_GL1。 

这样的话,我们就获得了一个完整的权限表,并破解了SPRR寄存器的所有位的隐秘。

这个完整的权限表看起来正是我们要找的:SPRR寄存器的值为0100、0110或1111时,若是从EL2跳转到代码时,内核似乎就会溃逃。所有这些值都对应于这样一个内存页:该页显然不能从EL2执行,但能从GL2执行。若是这些故障由于某种缘故原由转移到差其余地址,效果会怎样?不要再旁敲侧击了,这正是现在所发生的情形。这三个特殊的故障使用了XNU指向无限循环的系统寄存器,即 

·    当EL2试图跳转到只能在GL2中执行的代码时,引发的异常终止将转到S3_6_C15_C8_2(我称之为GXF_ABORT_EL2);

·    任何其他来自EL2的异常终止都转到VBAR_EL2;

·    任何其他来自GL2的异常终止都转到VBAR_GL2。 

这样的话,我们再次就获得了一个完整的权限表,从而破解了SPRR寄存器的所有位的隐秘。

,

USDT场外交易网

U交所(www.payusdt.vip),全球頂尖的USDT場外擔保交易平臺。

,

 

下面,让我们详细领会一下通过GL权限位修改EL权限位寄义的两种特殊情形:

·  第一种情形(0111)确保无法确立在GL中可执行、在EL中可写入的内存页。这为防止软件破绽提供了分外的硬件层珍爱。若是能够从EL中改变在GL中运行的代码的话,将使整个横向珍爱变得毫无意义。

·  第二种情形(1001)将r-x EL权限替换为--x权限,若是该内存页只能从GL中读取的话。我不知道为什么要强制执行这个珍爱。也许是为了能够对EL隐藏一些隐秘代码,或者作为对我不熟悉的平安破绽的一些分外缓解措施?我很想知道为什么这样的映射会有辅助,若是有人能够给出一个很好的注释的话。

行使Python探测GL2

掌握了这些知识,我们现在旧可以很轻松地在GL2和m1n1中添加对运行自界说payload的支持了。我们所要做的,就是行使已经存在的框架将运行级别降到EL1/EL0。为此,我们只需要禁用MMU(由于m1n1假设它是从具有rwx权限的内存页运行的,而我们在启用SPRR的情形下无法做到这一点),然后跳转到payload,最后,在返回之前再次启用MMU。

这使得我们可以很轻松地探测GL2,例如,看看S3_6_C15_C10_3是否就是SPSR_GL2: 

>>> u.mrs((3, 6, 15, 10, 3), call=p.gl_call)
0x60000009
>>> u.mrs(SPSR_EL2)
0x60000009

或者,我们可以直接重新运行MSR查找器,但这次是在GL2中: 

gxf_regs = find_regs(call=p.gl_call)
 
print("GXF")
for r in sorted(gxf_regs - all_regs):
    print("  %s" % list(r))

这样,我们就发现一大堆神秘的新系统寄存器,它们只有在该上下文中才气找到:

GXF
  [3, 6, 15, 0, 1]
  [3, 6, 15, 0, 2]
  [3, 6, 15, 1, 1]
  [3, 6, 15, 2, 6]
  [3, 6, 15, 8, 5]
  [3, 6, 15, 8, 7]
  [3, 6, 15, 10, 2]
  [3, 6, 15, 10, 3]
  [3, 6, 15, 10, 4]
  [3, 6, 15, 10, 5]
  [3, 6, 15, 10, 6]
  [3, 6, 15, 10, 7]
  [3, 6, 15, 11, 1]
  [3, 6, 15, 11, 2]
  [3, 6, 15, 11, 3]
  [3, 6, 15, 11, 4]
  [3, 6, 15, 11, 5]
  [3, 6, 15, 11, 6]
  [3, 6, 15, 11, 7]

也许以3、6、15、10开头的是GL1,以3、6、15、11开头的是GL2,或者反过来?这很容易搞清晰:只要在EL2中启用SPRR和GXF后,将运行级别下降到EL1,并重新举行同样的实验即可。这一次我们只获得如下所示的新寄存器: 

  [3, 6, 15, 0, 1]
  [3, 6, 15, 8, 7]
  [3, 6, 15, 10, 1]
  [3, 6, 15, 10, 2]
  [3, 6, 15, 10, 3]
  [3, 6, 15, 10, 4]
  [3, 6, 15, 10, 5]
  [3, 6, 15, 10, 6]
  [3, 6, 15, 10, 7]

这意味着3、6、15、10组确实代表EL1寄存器。这一点并不主要,由于M1总是以HCR_EL2.E2H运行,这意味着_EL1寄存器在EL2级别运行时被重定向到_EL2。同样的情形似乎也适用于GL1和GL2寄存器。 

我们能不能也搞清晰它们简直切寄义呢?幸运的是,一个早期的开源XNU版本含有如下所示的一些名称:

,define KERNEL_MODE_ELR      ELR_GL11
,define KERNEL_MODE_FAR      FAR_GL11
,define KERNEL_MODE_ESR      ESR_GL11
,define KERNEL_MODE_SPSR     SPSR_GL11
,define KERNEL_MODE_ASPSR    ASPSR_GL11
,define KERNEL_MODE_VBAR     VBAR_GL11
,define KERNEL_MODE_TPIDR    TPIDR_GL11

我不清晰为什么这些寄存器带有GL11的后缀,但除此之外,它们可以很容易地与上面发现的未知寄存器匹配起来。ASPSR至少包罗一个位,它决议了gexit是否应该返回到珍爱性执行或正常执行。

纵然只是这两个扩展,也尚有许多未知的寄存器和谜团。若是你想一起玩,就拿起最新的m1n1,看看到底能搞清晰什么:-)

XNU中的SPRR和GXF

最后,我们来考察一下XNU是若何使用这些新功效的。现实上,这里并没有什么可考察的,由于Jonathan已经在一篇文章中先容了SPR和GXF的使用情形。SPRR只是取代了已往APRR的功效:制止内核对页面执行写操作,以及制止它执行PPL代码。

最大的差异在于GXF:不需要全心设计一个修改APRR寄存器的小蹦床函数,只需要设置GXF入口向量:页表权限就会自动翻转,而且,genter就可以直接指向PPL了。 

让我们通过查看XNU若何初始化SPR来确认这一点:启动函数通过SPRR将EL1 SPR权限寄存器初始化为0x2020A505F020F0F0。这个代码序列与所有的CPU chicken位纠缠在一起。marcan甚至准确地猜到了写的是什么,并将它们从现实的chicken位序列中剥离出来。 

稍后,初始的GL指导代码会将EL1的权限更新为0x2020A506F020F0E0,然后锁定所有内容,以防止进一步的修改。 

然后,受珍爱的执行模式入口点被设置为一个来自正常内核的text区段的函数,而且该函数必须迅速跳转到PPLTEXT的开头位置。PPL入口函数首先会验证SPRR权限的设置是否准确,之后的行为,详细如Jonathan的文章所述。

最后,我们来看看XNU使用的种种SPRR页权限(这里没有显示的条目对所有级别都没有接见权限。在chicken位序列中设置的原始值也将GL权限设为EL级别):

这一切看起来都很合理。GL的权限可能会被进一步锁定,例如,不允许GL执行通例的内核代码(参见第10项),不允许它接见任何用户数据(参见第7项)。

除此以外,感受这就像以前的APRR硬件的一个增强版。这些转变不仅使整个系统不容易失足(寄存器可以被锁定,内核->PPL的转换完全通过硬件实现,内核和PPL的异常向量现在被明确的星散隔来),而且加倍天真。APRR已往只能剥离权限,但SPRR现在允许随便重新映射权限——只要不需要rwx页的话。遗憾的是,在Linux中还没有将它用起来。

小结

Apple Silicon通过了两个“隐秘”功效,两者可以通过亲热协作,来提供分外的防御机制。GXF引入了横向异常级别,称为GL1和GL2,它们使用的页表与响应的EL使用的相同,但具有差其余页面权限。SPRR允许重新界说EL和GL的页表项中的权限位。苹果公司行使这一点在GL中隐藏所有的页表操作代码,而且制止EL修改任何页表。这有用地引入了一个具有较小攻击面的低开销治理程序,纵然在内核模式下运行的代码也可以很好地珍爱页表。对于本文来说,其中大部门义务可以借助Python和m1n1举行逆向剖析。

这对于将Linux移植到M1上并没有什么用处,然则一旦我们将XNU虚拟化,以便追踪其MMIO接见,我们可能就会遇到这种情形。

开放性问题

在EL1中使用Hypervisor.framework时,是否可以启用SPRR和GXF?

是的! Longhorn指出,存在一个com.apple.private.hypervisor.vmapple权限,允许macOS下的EL1虚拟机也使用这些系统寄存器。

SPRR_CONFIG和GXF_CONFIG中的其他位是做什么用的?

启用SPR和GXF有什么其他影响?至少HCR_EL2不再可以从EL2写入,而是需要GL2权限了,我很一定这绝对不是唯一的区别。

当我们处于珍爱性执行模式时,中止会被送到那里?我以为它们会被送到VBAR_GLx,但我还没有确认这一点。

当在EL2中运行时,应该有一个差其余寄存器用于治理EL0的权限,例如HCR_EL2.TGE = 0和HCR_EL2.TGE = 1。也应该有一种方式可以从EL2接见EL1寄存器(类似于常见的._EL12的寄存器)。哪些寄存器可以做到这一点?

marcan已经在一则视频中把它们讲清晰了;现在它们已经被纪录在m1n1中。

siguza发现了涉及PAN和WXN的一些艰涩的硬件bugundefined行为——这个问题仍然存在,照样SPRR也有类似的问题?

SPR和GXF代表什么?可能是“shadow permission remap register(影子权限重映射寄存器)”和“guarded execution feature(受珍爱的执行功效)”。

本文翻译自: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矿机出售、租用、招商等业务。

网友评论

最新文章