iOS系统安全以及越狱的一些基本知识

0x00 背景

最近我在想,如果能对iOS内核进行patch或者写一个kext,那岂不是能完全隐藏机器对越狱情况?于是我对iOS10和iOS11的越狱工具、也就是yalu和electra进行了一点分析,看看它们是如何对内核进行patch的。

0x01 yalu102

yalu102使用了一个叫KPP bypass的方法,具体可以看J大神的*OS Internals III第13章和第24章,更深入一点可以看Xerub的这篇文章

在iOS10,且为iphone7之前的机型的情况下,KPP是软件实现,它的代码就在kernelcache的尾部。iOS的用户态运行在EL0级别,内核运行在EL1级别,而KPP的代码运行在EL3级别。EL0->EL1可以通过SVC命令进入,同理,EL1->EL3可以通过SMC或者MSR CPACR_EL1, Xt命令进入。每当进入EL3的时候,KPP就会运行检查内核的代码是否被篡改。当然SMC这种调用实在太频繁,每次进入EL3都运行一次KPP的话会使机器性能大幅下降,所以Apple选择了一个折中的方法,只有在MSR CPACR_EL1, Xt命令时才真正运行KPP检查代码篡改,而这个命令是用来触发浮点数计算的。也就是说,每次进行浮点数运算时,KPP会被触发进行代码完整性检测。

有了这个背景,yalu使用的KPP bypass就比较好理解了,大概流程是把MSR CPACR_EL1, Xt命令替换成BL命令,跳转到自己的一段trampoline代码:kppsh1。在kppsh1这段代码中,把TTBR_EL1的状态保存在X1中,由于我们修改了内核的代码,这时的TTBR_EL1的状态是compromised的。而非compromised的TTBR_EL1本身在越狱开始时早已被保存起来,此时把这个保存起来的状态加载到TTBR_EL1里并调用MSR CPACR_EL1, Xt触发KPP。这时由于TTBR_EL1是原本的值,它指向的页表,page都是没有被篡改的(这里由于Copy on Write的存在,我们篡改的内核代码其实是保存在物理内存上的一个副本上的,如果页表不指向这个副本而是指向原本的page,则KPP是无法感知到这个副本的)所以KPP无法发现内核代码被篡改了。当KPP执行完成后,再把保存在X1中的值加载回TTBR_EL1里,这时内核看到的内存空间又变成我们篡改后的代码的空间了,于是在EL1级别上继续执行时就可以执行我们篡改后的代码了。

这个流程其实跟用户态的hook很相似。

由于只有在浮点计算时才会进行KPP检测,而浮点运算一般十几秒或者二三十分钟才发生一次,所以我们篡改的代码有充足的时间窗口被运行。

0x02 electra

electra可以对iOS11和任何型号的iPhone进行越狱,这有点不可思议。因为yalu102的KPP bypass是建立在KPP为软件实现的基础上的,而从iPhone7开始,Apple引入了KTTR,这是一个硬件实现的KPP,根本是无法被patch的。那么为什么electra可以无视KPP进行越狱呢?

原因很简单,因为electra的越狱并不需要对内核代码进行patch。grep一下electra的代码,它的所有内核写(kwrite)都只是在写一些内核数据结构,而不是内核代码区域,这些内核数据结构本身就是变量,并不在KPP保护范围内,所以不需要进行KPP bypass,它的越狱方法称为Kppless越狱。

0x03 回到背景

回到我写这篇文章的motivation,我本来是想patch iOS的内核,hook所有syscall,但是由于KPP和KTTR的存在,这个想法基本不可能实现了,iOS的内核代码区不用说是在KPP的保护范围之内的,而syscall table本身也是在__DATA_CONST:__const区域,它也是KPP的保护对象,无法篡改。

0x04 Reference

  1. *OS Internals III
  2. https://github.com/coolstar/electra
  3. https://github.com/kpwn/yalu102/
  4. Not relative: http://yumistar.ga/blog/iOS-11.html
  5. Not relative: https://bazad.github.io/2017/09/live-kernel-introspection-ios/#generic-kernel-function-calls-on-ios-and-macos
  6. Not relative: https://blog.binary.house/2018/10/sneak-peek-under-hood-of-electras.html