Tick(FPU)Tock(IRQ) 与iOS9一起推出的内核完整性保护又称为KPP,这对于arm64越狱带来了新的问题。 有效地观察到,在修补内核代码(通常在较旧的越狱中)之后,设备会一段时间后会静默地恐慌。很明显,有些东西会检查内核代码。 这个东西在内核之外,很快就显现出一种在工作中的管理程序。 到目前为止,我仍然感到惊讶的是,没有人对KPP进行了一个写作至少没有人知道。所以,我将尝试解释hypervision如何工作。具体的实施细节可能会在稍后的时间提供,只要我有时间。现在,不用多说,我们走 第1部分(设置) KPP位于一个MachO可执行文件,紧随压缩内核块之后,在kernelcacheimg4内。iBoot刻录出KPP图像,将其加载到0x4100000000,并在EL3中运行 EL3 start(monitorbootargsmba) 这结构体有如下几项 structmonitorbootargs{ uint64 uint64tvirtB uint64tphysB uint64tmemS structkernelbootargskernA uint64tkernE uint64tkernPhysB uint64tkernPhysS uint64tkernVirtS }; KPP使用调用start(NULL)的蹦床来覆盖自己的MachO头,0x4100000000,并安装了两个异常处理程序synchandler和irqhandler。回想一下AArch64异常表: ExceptionVector具有两个处理程序的位置 接下来,它解析内核及其kexts(来自PRELINKINFO) saveTEXT,DATAsegmentstomaplist saveTEXT,DATA::constzonestohashlist 最后,如果启用whichit(以及其他)以下寄存器 CPACREL10x100000;CPACREL1。FPEN1,causesinstructionsinEL0thatusetheFloatingPointexecutiontobetrapped CPTREL30x80000000;CPTREL3。TCPAC1,accessestoCPACREL1willtrapfromEL2andEL1toEL3 SCREL30x631;SCREL3。IRQ0,WhenexecutingatanyExceptionlevel,physicalIRQinterruptsareNOTtakentoEL3 SCREL3。SMD0,SMCinstructionsareENABLEDatEL1andabove SCREL3。SIF1,SecurestateinstructionfetchesfromNonsecurememoryareNOTpermitted EL1 内核在EL1中开始执行 start()startfirstcpu()arminit(): cpumachineidleinit()monitorcall(0x800) machinestartup()kernelbootstrap()kernelbootstrapthread()monitorcall(0x801) startcpu()arminitcpu()cpumachineidleinit()monitorcall(0x800) monitorcall()将升级到EL3到管理程序的synchandler EL3 synchandler: if(ESREL30x5E000011){ESREL3。EC0x17ESREL3。IL1ESREL3。ISS0x11akaSMC0x11akamonitorcall()insidethekernel switch(arg0){ case0x800:calledbycpumachineidleinit() savekernelentrypoint case0x801:calledbykernelbootstrapthread() if(enabled){ if(locked){ FAIL(4); } dolockdown: hashallregionsfromhashlist initializesomevars saveSCTLREL1,TCREL1,TTBR1EL1,VBAREL1 。。。 SCREL3。SMD1; locked1; } returnOK; case0x802:wtfisthisshit? FAIL(5); } } (tobecontinued) 当出现问题时,FAIL(代码)设置一个全局变量,并通过以下方式向内核发出信号: ESREL10xBF575400codeESREL1。EC0x2F,ESREL1。ISV1,ESREL1。IS0x575400code 代码含义 帧违规 坏系统调用 未锁定 已锁定 软件请求 TTEPTE无效 违反绘图 违反系统注册 然后,执行再转移到SError回到内核的ExceptionTable中: SErrorflehserror()slehserror()kernelintegrityerrorhandler()panic() 否则,如果一切都会好的,就在monitorcall()之后,执行在内核中恢复。 这是设置阶段,为了让内核设置一次写入内存位置所需的。接下来,进入心跳阶段 第二部分(theticking) 同时在用户空间运行代码,当FPU指令被执行后,CPACREL1。FPEN1会产生一个内核陷阱。 EL1 在内核中,flehsynchronous()flehirq()flehfiq()和flehserror()所有都会这样结束exceptionreturndispatch()checkuserasts()MSRCPACREL1,X0一旦来自于EL3内核陷阱,CPACREL1就会执行。当CPTREL3。TCPAC1时,执行权就转交到EL3synchandler EL3 Thistime,itmeansbusiness。 synchandler: (continued) elseif(ESREL30x62340400){ESREL3。EC0x18ESREL3。IL1ESREL3。ISS0x340400akatrappedbyMSRCPACREL1,X0 if(violated){ FAIL(1); } if(!locked){ FAIL(3); } if(!(numberofhitswatchtowerthrottle)){ if(!(flipflop1)){ if(hashisready){ blake2bfinal(hash,digest); if(memcmp(curdigest,digest,32)){ FAIL(1); } curgetnextregion(); if(!cur){ curgetfirstregion(); } blake2binit(hash); hashisready0; }else{ chunkmin(curdataleft,128); blake2bupdate(hash,curdataptr,chunk); if(!curdataleft){ hashisready1; } } }else{ walkandcheckTTEPTE verifymaplist checksystemregistersSCTLREL1,TCREL1,TTBR1EL1,VBAREL1 。。。 } } ELREL34;skipinsn CPTREL30;CPTREL3。TCPAC0,accessestoCPACREL1willnottrapfromEL2andEL1toEL3 CPACREL10x300000;CPACREL1。FPEN3,doesnotcauseanyFPUinstructiontobetrapped SCREL30x6B3;SCREL3。IRQ1,WhenexecutingatanyExceptionlevel,physicalIRQinterruptsaretakentoEL3 SCREL3。SMD1,SMCinstructionsareUNDEFINEDatEL1andabove SCREL3。SIF1,SecurestateinstructionfetchesfromNonsecurememoryareNOTpermitted returnOK; } EL3。SIF0,SecurestateinstructionfetchesfromNonsecurememoryarepermitted 也就是说:重置IRQs到EL1,使其重新能够FPU陷阱,能够处理CPACREL1访问的陷阱,最后的4步然后一直重复。 总结 KPP确保FPU陷阱且不会被禁用。当FPU命中,内核就会尝试禁用陷阱但同时也会由KPP接管。KPP然后运行检查,释放FPU,运行IRQs本身。只要任何IRQ触发,就会使FPU进入内核陷阱并结束IRQs 这是保持管理程序跳动的引擎。如果你修改触发器,即CPACREL1访问,则FPU无法执行。但是,有一个catch。我们可以窃取CPACREL1访问单独的蹦床: 取消patch 触发CPACREL1,管理程序然后运行恢复执行权 再次patch profit 这种绕过方式在qwertyoruiop的yalu102中使用过。 本文由看雪论坛iOS安全小组OSGksmokee原创转载请注明来自看雪社区