原文链接:https://xerub.github.io/ios/kpp/2017/04/13/tick-tock.html
与iOS9一起推出的内核完整性保护又称为“KPP”,这对于arm64越狱带来了新的问题。 在修补内核代码(通常在较旧的越狱中)之后,一般要不了多久,设备就会panic。 很明显,有些东西会检查内核代码。 这个东西在内核之外,不断地管理和监视着内核。
到目前为止,我仍然感到惊讶的是,没人对KPP写点什么。 至少到现在我都没看到。 所以,我将尝试解释虚拟管理程序如何工作。 具体的实施细节可能会在稍后的时间提供,只要我有时间。现在,不浪费时间了我们开始吧。
KPP位于一个Mach-O可执行文件,附加在压缩的内核块之后,在kernelcache img4内。 iBoot加载KPP的镜像,将其加载到0x4100000000,并在EL3中运行。
_start(monitor_boot_args *mba)
这结构体有如下几项
KPP调用_start(NULL)
在0x4100000000来覆盖自己的Mach-O
头,并安装了两个异常处理程序sync_handler和irq_handler
。 回想一下AArch64异常表:
ExceptionVector具有两个处理程序的位置
接下来,它解析内核及其kexts(来自__PRELINK_INFO
)
最后,如果被启用 它始终设置下面的寄存器
内核在EL1中开始执行
monitor_call()
将升级到EL3到管理程序的sync_handler
sync_handler
:
当出现问题时,FAIL(代码)设置一个全局变量,并通过以下方式向内核发出信号:
代码含义
然后往下调用SError返回到内核的ExceptionTable中:
否则,如果一切是正常的,就在monitor_call()之后,在内核中执行恢复操作。
这是设置阶段,为了让内核设置一次写入内存位置所需的。 接下来,进入中心阶段
同时在用户空间运行代码,当FPU指令被执行后,CPACR_EL1.FPEN==1
会产生一个内核陷阱。
在内核中,fleh_synchronous()
fleh_irq()
fleh_fiq()
和 fleh_serror()
所有都会这样结束
exception_return_dispatch() => check_user_asts() => MSR CPACR_EL1, X0
一旦来自于EL3内核陷阱,CPACR_EL1就会执行。当CPTR_EL3.TCPAC==1
时,执行权就转交到EL3 sync_handler
sync_handler:
如果所有的检查都通过的话,管理程序就会禁用FPU陷阱(允许FPU最终执行)使得IRQ执行到EL3(确保再次命中),在CPACR_EL1命中后恢复内核然后等待。
内核和用户空间愉快的运行着。当下一次IRQ触发时,就由EL3 IRQ的管理程序接管。
irq_handler:
也就是说:重置IRQs到EL1,重新启动FPU陷阱,重新启动CPACR_EL1访问的陷阱,这些是最后的4步,然后会一直重复。
总结:KPP总是确保FPU陷阱且不会被禁用。当FPU命中,内核就会尝试禁用陷阱但同时也会由KPP接管。然后KPP运行检查,释放FPU,运行IRQs本身。只要任何IRQ触发,就会使FPU进入内核陷阱并结束IRQs
这是保持虚拟管理程序跳动的引擎。 如果你修改触发器,即CPACR_EL1访问,则FPU无法执行。 但是,有一个catch。 我们可以“窃取”CPACR_EL1单独访问:
struct monitor_boot_args {
uint64_t version;
uint64_t virtBase;
uint64_t physBase;
uint64_t memSize;
struct kernel_boot_args *kernArgs;
uint64_t kernEntry;
uint64_t kernPhysBase;
uint64_t kernPhysSlide;
uint64_t kernVirtSlide;
};
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)