如果你看完書中的所有例子蠢琳,你很可能已經(jīng)做完你的實驗和在已經(jīng)越獄的iPhone上的研究啊终。因為和許多人一樣,幾乎所有的iPhone安全研究都在已經(jīng)越獄的設(shè)備上實施傲须。然而蓝牲,對包括安全社區(qū)和iPhone安全研究者在內(nèi)的大部分人來說,越獄的內(nèi)部工作原理是完全不知道的泰讽。許多人把越獄當(dāng)黑匣子看待例衍;當(dāng)他們在越獄工具選項里點擊jailbreak按鈕,認(rèn)為工作起來像魔術(shù)一樣已卸。這是由于對于他們所進行的越獄操作并不需要知道越獄的內(nèi)部工作原理佛玄,如用戶層漏洞。
但如果想知道越獄過程的內(nèi)部工作原理累澡,這章將是你許多問題的答案梦抢。
對不同越獄類型的簡短介紹后,我們用紅雪(redsn0w)越獄做例子愧哟,向你一步步介紹設(shè)備所發(fā)生的越獄過程奥吩。這章也向你介紹內(nèi)核應(yīng)用補丁的內(nèi)部工作原理,你將知道對應(yīng)不同選項哪些補丁是實際需要的蕊梧。
為何要越獄霞赫?
人們對他們的ios設(shè)備越獄有許多原因,有的是為了開發(fā)軟件需要一個開放的平臺肥矢,有的喜歡對他們的設(shè)備的全部控制的感覺端衰,有的需要越獄去安裝解鎖運營商的軟件(如ultrasn0w),有的越獄為了安裝私人的iPhone應(yīng)用橄抹。
另一方面靴迫,安全研究者進行自己的iOS設(shè)備的越獄通常有其他原因。事實上由于正常的iPhone被緊緊的鎖定楼誓,不允許運行未簽名的代碼玉锌,對于評估系統(tǒng)安全,挖掘安全漏洞疟羹,這是一個大障礙主守。
甚至即使擁有一個蘋果的iOS開發(fā)者賬號,由于沙盒(sandbox)和其他限制榄融,代碼在iPhone上運行也是有限制的参淫。例如,進程不允許執(zhí)行其他進程和復(fù)制愧杯。另外涎才。沙盒制止了研究者修改其他應(yīng)用程序的文件,也不可能對MobileSafari瀏覽器掛接調(diào)試器進行調(diào)試。
雖然可以在一個正常的iPhone應(yīng)用里檢測到運行進程的名稱耍铜,但用戶無法制止可疑進程的運行或分析他們在做什么邑闺。回想下蘋果公司把在每臺iPhone上存儲GPS軌跡文件歸結(jié)于軟件bug的事情棕兼,如果沒有越獄陡舅,這個“定位門”問題永遠(yuǎn)不會被發(fā)現(xiàn)。
最重要的伴挚,如果沒有公開越獄的工具靶衍,這本書的大部分研究將沒有可能。你將驚奇的發(fā)現(xiàn)大部分iPhone的安全研究人員把整個越獄工作留給 iPhone Dev Team或Chronic Dev Team去做茎芋,而他們只是越獄工具的使用者颅眶。但每個新一代的iOS的硬件和軟件版本出來,越獄變得越來越困難败徊。所以有更多的安全社區(qū)的人來幫助越獄團隊是很重要的趾徽。我們希望這章的其它部分能吸引你來參加未來越獄的發(fā)展允瞧。
越獄類型
雖然多年來人們能對他們的各種iOS版本的iPhone進行越獄箱蝠,這些越獄都有不同的特性诀紊。主要是因為越獄的質(zhì)量在很大部分依賴于發(fā)現(xiàn)的安全漏洞,這些漏洞被用來解除設(shè)備的強制約束沪哺。一旦一個越獄的漏洞被知曉沈自,蘋果公司自然會盡快在下一版本的iOS中進行修補。所以幾乎每個新版本的iOS都需要一套新的漏洞來進行越獄辜妓。 有時漏洞是駐留在硬件層面的枯途,蘋果公司不能進行簡單的軟件升級來修補它,這需要一套新的硬件籍滴,需要發(fā)布下一版本的iPhone或iPad酪夷,將花費蘋果公司更長的時間來修補。
越獄的保持(Jailbreak Persistence)
依賴越獄使用的漏洞孽惰,越獄的效果可能長期的晚岭,也可能在設(shè)備關(guān)機再開啟后消失。為了描述兩種不同的越獄勋功,越獄社區(qū)把這兩種方式叫做 完美越獄(tethered jailbreak)和非完美越獄(untethered jailbreak)坦报。
非完美越獄(Tethered Jailbreaks)
非完美越獄是設(shè)備重啟后就消失的越獄。越獄后的設(shè)備每次重啟后需要某種方式的重新越獄狂鞋。通常意味著每次關(guān)機再重新開機時需要重新連接到電腦上片择。由于這個過程中需要USB線纜連接,這就是tethered的意思骚揍。這個詞tethered也用于不需要USB連接字管,但需要訪問特定網(wǎng)站或執(zhí)行特定應(yīng)用程序的重新越獄,
如果漏洞是某些提權(quán)代碼,一個非完美越獄能只由單個漏洞組成嘲叔。一個例子是limera1n的bootrom漏洞脐供,被目前的大部分iOS4和iOS5越獄使用。另一個例子是iOS的USB內(nèi)核驅(qū)動程序的漏洞借跪。然而,目前沒有類似的公開漏洞酌壕。
如果沒有類似的漏洞可用掏愁,進入設(shè)備的初始入口可以通過一個應(yīng)用程序的漏洞來獲得很少的權(quán)限,如MobileSafari瀏覽器卵牍。然而果港,單獨的這樣一個漏洞不能認(rèn)為是越獄,因為沒有附加的內(nèi)核漏洞糊昙,不能禁止所有的安全特性辛掠。 所以一個非完美越獄由一個提權(quán)代碼漏洞組成,或一個非提權(quán)代碼漏洞結(jié)合其他權(quán)限提升漏洞释牺。
完美越獄(Untethered Jailbreaks)
完美越獄是利用一個設(shè)備重啟后不會消失的持久漏洞來完成的萝衩,完美(untethered)因為設(shè)備每次重新啟動后不需要重新越獄,所以它是更好的越獄方式没咙。
由于完美越獄需要啟動環(huán)節(jié)的非常特殊地方的漏洞猩谊,自然更難完成。過去由于在設(shè)備硬件里發(fā)現(xiàn)了非常強有力的漏洞祭刚,允許在設(shè)備的啟動環(huán)節(jié)的早期進行破解牌捷,使完美越獄可能實現(xiàn)。 但這些漏洞現(xiàn)在已經(jīng)消失了涡驮,而同樣品質(zhì)的漏洞沒有出現(xiàn)暗甥。
由于以上原因,完美越獄通常由某種非完美越獄結(jié)合附加的允許在設(shè)備上保持的漏洞組成捉捅。利用開始的非完美越獄來在設(shè)備的根目錄文件系統(tǒng)上安裝附加漏洞撤防。由于首先專有未簽名代碼必須執(zhí)行,其次權(quán)限要提升以便能對內(nèi)核打補丁锯梁,所以至少需要2個附加的漏洞即碗。
接下來的部分將介紹越獄的全貌,當(dāng)你讀完陌凳,將會很清晰的了解設(shè)備越獄的完整詳細(xì)的過程剥懒。
漏洞類型(Exploit Type)
漏洞的存在位置影響你對設(shè)備的存取級別。一些允許低級別的硬件存取合敦。另一些受限于沙盒內(nèi)的許可權(quán)限初橘。
Bootrom級別
從越獄者的角度看,Bootrom級別的漏洞是最有力的。bootrom在iPhone的硬件內(nèi)部保檐,它的漏洞不能通過軟件更新推送來修復(fù)耕蝉。相反,只能在下一代的硬件版本里修復(fù)夜只。在存在limera1n漏洞的情況下垒在,蘋果沒有發(fā)布iPad1或iPhone4的新產(chǎn)品,直到A5處理器的設(shè)備扔亥,iPad2和iPhone4S發(fā)布前场躯,這個漏洞長期存在并為人所知。
Bootrom級別的漏洞不能修復(fù)旅挤,并且允許對整個啟動環(huán)節(jié)的每個部分進行替換或打補短吖亍(包括內(nèi)核的啟動參數(shù)),是最有力的漏洞粘茄。由于漏洞在啟動環(huán)節(jié)發(fā)生的很早签舞,而且漏洞Payload擁有對硬件的全部讀取權(quán)限。 如它可以利用AES硬件引擎的GID密碼來解密IMG3文件柒瓣,而IMG3文件允許解密新的iOS更新儒搭。
iBoot級別
當(dāng)iBoot里的漏洞達(dá)到能提供的特性時,幾乎和bootrom里的漏洞一樣有力芙贫。這些漏洞效果下降是由于iBoot沒有固化入硬件师妙,能通過簡單的軟件升級來修復(fù)。
除了這點屹培,iBoot漏洞在啟動環(huán)節(jié)任然很早默穴,能提供給內(nèi)核啟動參數(shù),對內(nèi)核打補丁褪秀,或?qū)τ布苯舆M行GID密碼的AES操作蓄诽。
Userland級別
用戶層面級別的越獄是完全基于用戶層面進程的漏洞的,像JBME3(http://jailbreakme.com)媒吗。這些進程如果是系統(tǒng)進程仑氛,就擁有超級用戶root權(quán)限,如果是用戶應(yīng)用程序闸英,就擁有稍低級別的如mobile用戶的權(quán)限锯岖。不管哪種情況,越獄設(shè)備至少需要2個漏洞甫何。第一個漏洞用來完成專有代碼執(zhí)行出吹,第二個漏洞用來使內(nèi)核的安全措施失效,進行權(quán)限提升辙喂。
在以前的iOS版本里捶牢,只要破解的進程以root超級用戶權(quán)限運行鸠珠,代碼簽名功能就會失效。現(xiàn)在秋麸,內(nèi)核內(nèi)存崩潰或執(zhí)行內(nèi)核代碼需要禁止強制代碼簽名渐排。
和bootrom、iBoot級別漏洞相比灸蟆,用戶層面的漏洞更弱一些驯耻。因為即使內(nèi)核代碼執(zhí)行已經(jīng)可能了,如GID密碼的AES引擎的硬件特性依然不能讀取炒考。所以蘋果公司對用戶層面的漏洞更容易修補吓歇;并由于遠(yuǎn)程用戶層面的漏洞能用于iPhone惡意軟件的注入,所以蘋果公司對這些漏洞經(jīng)常很快進行修補票腰。
理解越獄過程(Understanding the Jailbreaking Process)
這個章節(jié)觀察了紅雪(redsn0w)越獄工具的內(nèi)部工作原理。紅雪是由 iPhone Dev Team團隊開發(fā)的女气,可以在他們的網(wǎng)站(http://blog.iphone-dev.org/)上下載杏慰。由于它支持大部分的iOS版本,容易使用炼鞠,被視為最穩(wěn)定的越獄缘滥,而且同時支持Windows和OS X操作系統(tǒng),是目前對A5以前的設(shè)備進行越獄的最流行的工具谒主。
使用紅雪朝扼,越獄只是點擊幾個按鈕,把你的iPhone設(shè)置為設(shè)備固件升級(DFU)狀態(tài)霎肯。新手使用它來越獄iPhone都是很容易的擎颖。圖10.1顯示了紅雪的啟動屏幕截屏畫面:
當(dāng)你點擊Jailbreak越獄按鈕后,紅雪指導(dǎo)設(shè)置你的iPhone為DFU模式观游,根據(jù)你連接上的設(shè)備,提供你可選擇的不同的越獄特性懂缕。你簡單選擇你的選項(如多任務(wù)手勢)允跑,點擊Next繼續(xù)按鈕,等待紅雪完成它的工作搪柑。
從用戶角度看這是非常簡單的過程聋丝,但是這這些操作后面發(fā)生了很多事情,并且除了越獄社區(qū)的少數(shù)人工碾,沒人真的知道發(fā)生了什么弱睦。當(dāng)你讀完下面章節(jié)后,你將成為了解紅雪內(nèi)部工作的少數(shù)人之一渊额。
經(jīng)作者的允許每篷,下面章節(jié)的所有信息都來自一個反編譯版本的紅雪越獄瓣戚。由于A5處理器的iPad2或iPhone 4S設(shè)備沒有一個公開知曉的bootrom漏洞,這些設(shè)備的所有越獄必須是用戶層面級別的焦读。 這表示bootrom破解和啟動ramdisk的頭兩個步驟必須由MobileSafari漏洞和一個內(nèi)核漏洞替代子库,其余的越獄過程工作是一樣的。
破解Bootrom(Exploiting the Bootrom)
紅雪的越獄開始時利用the limera1n 的DFU bootrom漏洞來使在高權(quán)限級別執(zhí)行代碼成為可能矗晃。這個漏洞是一個前A5處理器設(shè)備的bootrom中USB DFU堆棧中的基于堆的緩沖區(qū)溢出漏洞仑嗅。我們這里不討論漏洞的細(xì)節(jié)。如果感興趣张症,你可以在諸如THEiPHONEWiKi(http://theiphonewiki.com/wiki/index.php?title=Limera1n_Exploit)的一些地方找到這個漏洞的說明和源代碼仓技。
對越獄來說,你唯一需要知道的是這個漏洞用來給bootrom里的簽名驗證代碼打補丁修改俗他,允許你啟動專門的ramdisk脖捻,給Low-Level-Bootloader (LLB)、 iBoot和內(nèi)核的版本打補丁兆衅。 Chronic Dev Team團隊已在GitHub(https://github.com/Chronic-Dev/syringe)上釋放了同樣執(zhí)行效果的源代碼地沮。由于紅雪沒有公開源代碼,如果你想重頭編寫自己的越獄工具羡亩,這些代碼是一個很好的起點摩疑。
啟動Ramdisk(Booting the Ramdisk)
紅雪利用 limera1n 漏洞啟動一個打補丁修改過的內(nèi)核和一個預(yù)先定制的ramdisk。內(nèi)核被打了一些越獄補丁以便允許執(zhí)行未簽名的代碼畏铆。然而雷袋,它并沒包括在已完美越獄的系統(tǒng)中發(fā)現(xiàn)所有內(nèi)核補丁。依據(jù)用戶在越獄時設(shè)置的開關(guān)選項辞居,ramdisk在每次運行時都在根目錄創(chuàng)建不同的文件楷怒,形成定制的ramdisk。這些文件的存在在晚些時候會被ramdisk上的越獄執(zhí)行過程檢測到瓦灶,以此決定紅雪的哪種特性被激活率寡。例如noUntetherHacks文件的存在會使紅雪跳過完美越獄漏洞的安裝。
ramdisk啟動時倚搬,內(nèi)核會運行 ramdisk的/sbin/launchd的二進制文件冶共,它包括一個初始化越獄的小型stub程序。這個程序首先在系統(tǒng)里裝載root根文件系統(tǒng)和數(shù)據(jù)分區(qū)每界,為修改需要捅僵,以上裝載好的文件系統(tǒng)和數(shù)據(jù)分區(qū)是可讀寫。最終眨层,一個越獄的執(zhí)行程序會接管并執(zhí)行所有接下來的步驟庙楚。
越獄文件系統(tǒng)(Jailbreaking the Filesystem)
iPhone的文件系統(tǒng)缺省分成2個分區(qū),第一個分區(qū)是root根文件系統(tǒng)趴樱,存放iOS的操作系統(tǒng)文件和如MobileMail馒闷,MobileSafari的標(biāo)準(zhǔn)應(yīng)用程序集酪捡。早期的iOS版本里,root根文件系統(tǒng)的大小接近分區(qū)的容量大小纳账,分區(qū)沒有多少剩余空間逛薇。雖然root文件系統(tǒng)是假設(shè)為不可修改的,分區(qū)也缺省裝載為只讀的疏虫,但如今root根文件系統(tǒng)接近1GB大小永罚,分區(qū)有200MB左右空間剩余。設(shè)備的其余存儲空間分配給第二個分區(qū)卧秘,即數(shù)據(jù)分區(qū)呢袱,它裝載在/private/var目錄下,可以讀寫翅敌。在根目錄的 /etc/fstab文件里有以下配置:
/dev/disk0s1 / hfs ro 0 1
/dev/disk0s2 /private/var hfs rw,nosuid,nodev 0 2
你可以看到羞福,數(shù)據(jù)分區(qū)的裝載配置文件有 nodev 和nosuid標(biāo)志。為了防止文件系統(tǒng)層面的攻擊蚯涮,nodev標(biāo)志是確保設(shè)備節(jié)點在可寫的數(shù)據(jù)分區(qū)里的存在將會被忽略治专。nosuid標(biāo)志是告知內(nèi)核在數(shù)據(jù)分區(qū)里執(zhí)行時忽略suid位。suid位表示執(zhí)行時需要以超級用戶root身份執(zhí)行恋昼,或與當(dāng)前用戶不同的一個用戶來執(zhí)行。這些標(biāo)志都是iOS內(nèi)部用來防止權(quán)限提升漏洞的防御措施赶促。
不管是bootrom級別液肌,還是用戶層面級別的漏洞,這個缺省的配置是所有越獄面臨的難題鸥滨。因為他們通常需要對root根文件系統(tǒng)進行修改嗦哆,使程序在設(shè)備重啟后還能存在,或能增加服務(wù)和守護進程婿滓。所以每次越獄獲得超級用戶root的權(quán)限后的第一個動作就是重新裝載root根文件系統(tǒng)老速,使之可讀可寫。為了使設(shè)備重啟后修改也生效凸主,下一個步驟就是用下面類似的配置替換系統(tǒng)的/etc/fstab文件:
/dev/disk0s1 / hfs rw 0 1
/dev/disk0s2 /private/var hfs rw 0 2
這個新的文件系統(tǒng)的配置文件將裝載root根目錄文件為可讀可寫橘券,并從第二個分區(qū)的裝載配置中移去nosuid和nodev標(biāo)志。
安裝完美越獄破解(Installing the Untethering Exploit)
每次當(dāng)一個新版本的iOS出現(xiàn)卿吐,原先的已知漏洞就被修復(fù)了旁舰。 所以在一個有限的時間窗口里,紅雪在老設(shè)備上能越獄新的固件嗡官,但不能安裝完美越獄漏洞箭窜。
一旦得到了一個新的完美越獄漏洞,紅雪的作者就會修改程序來安裝新的漏洞衍腥。 由于每個漏洞都是不同的磺樱,所以都需要不同的安裝步驟纳猫。
雖然實際的完美越獄漏洞安裝是不同的,但都是在root根文件系統(tǒng)里重命名和移動一些文件竹捉,并拷貝一些文件到它上面芜辕。當(dāng)你反編譯當(dāng)前的紅雪軟件版本,你會發(fā)現(xiàn)它從4.2.1到5.0.1的大部分iOS版本上都支持安裝完美越獄漏洞活孩,發(fā)現(xiàn)每個完美越獄漏洞需要那些文件物遇。
安裝 AFC2服務(wù)(Installing the AFC2 Service)
蘋果文件連接 (AFC)是一個運行在每臺iPhone上的文件傳送服務(wù),它允許你通過USB連線存取iPhone的/var/mobile/Media的目錄里的文件憾儒。AFC服務(wù)由lockdownd守護進程提供询兴,被命名為com.apple.afc 。但lockdownd守護進程只提供存取服務(wù)起趾,實際由afcd守護進程實現(xiàn)诗舰。在MAC上通過MobileDevice.framework,在Windows PC上通過 iTunesMobileDevice.dll來使用训裆。
afcd還提供lockdownd的第二個服務(wù)眶根,它注冊為com.apple.crashreportcopymobile。它用來從設(shè)備向電腦復(fù)制CrashReporter報告边琉,并只限制于/var/mobile/Library/Logs/CrashReporter目錄和子目錄的讀寫存取 属百。
由于這些服務(wù)運行于mobile用戶的許可權(quán)限下,被鎖定于特定目錄下变姨,他們對于越獄的作用是受限的族扰。所以紅雪和其他越獄工具向lockdownd注冊了一個額外的服務(wù),叫做com.apple.afc2定欧。這個服務(wù)利用afcd守護進程提供對整個文件系統(tǒng)的root超級用戶權(quán)限的讀寫存取渔呵,這是一個大部分用戶都不知道的相當(dāng)危險的越獄特性。這意味著一臺沒有密碼保護或在未鎖定狀態(tài)的越獄過的iPhone砍鸠,只要連接上一個USB充電站或其他人的電腦扩氢,就給了另一方在沒有用戶交互下的整個文件系統(tǒng)的讀取存取權(quán)限。他們可以竊取你的所有數(shù)據(jù)或安裝系統(tǒng)后門爷辱。
com.apple.afc2服務(wù)通過更改在/System/Library/Lockdown/Services.plist文件里的lockdownd配置來安裝录豺。這是一個正常的.plist 文件,可以通過 .plist文件的標(biāo)準(zhǔn)工具或API來修改饭弓。紅雪通過在文件里增加以下內(nèi)容來安裝新的服務(wù):
com.apple.afc2
AllowUnactivatedService
Label
com.apple.afc2
ProgramArguments
/usr/libexec/afcd
–lockdown
-d
/
由于文件系統(tǒng)越獄和新的AFC2服務(wù)可以通過簡單配置文件的更改來完成巩检,并不需要執(zhí)行未簽名的二進制代碼。所以他們在重啟后就可以工作示启,即使一個設(shè)備還沒有發(fā)現(xiàn)完美越獄漏洞兢哭。
安裝基本程序庫(Installing Base Utilities)
蘋果沒有在iPhone上提供UNIX外殼程序,所以它的根目錄下的/bin和/usr/bin目錄基本是空的夫嗓,沒有你所期待的可執(zhí)行的二進制文件迟螺。實際上冲秽,最新的iOS5.0.1只在這兩個目錄下預(yù)先安裝提供了以下5個可執(zhí)行的二進制文件:
/bin/launchctl
/usr/bin/awd_ice3
/usr/bin/DumpBasebandCrash
/usr/bin/powerlog
/usr/bin/simulatecrash
因為這樣,類似紅雪的越獄工具通常在這兩個目錄下安裝一套基本程序庫來實現(xiàn)基本功能矩父,使越獄的文件安裝更簡單锉桑。下面的工具清單是從紅雪的ramdisk里的越獄二進制文件里展開的,顯示了紅雪安裝的基本程序庫清單窍株。這些工具也用于越獄二進制文件自身民轴,例如壓縮tar文檔或更改.plist文件內(nèi)容。
/bin/mv
/bin/cp
/bin/tar
/bin/gzip
/bin/gunzip
/usr/sbin/nvram
/usr/bin/codesign_allocate
/usr/bin/ldid
/usr/bin/plutil
除了這些文件球订,一些附加庫和文件也被安裝用于越獄過程而不是用于UNIX外殼用戶后裸。所以我們沒有把他們列出來。一個有趣的事是當(dāng)前的iOS固件已經(jīng)有一個/usr/sbin/nvram二進制文件冒滩,但被紅雪重新覆蓋微驶。
應(yīng)用程序隱藏(Application Stashing)
當(dāng)從蘋果的應(yīng)用程序商店安裝應(yīng)用時,它們被安裝在/var/mobile/Applications目錄里开睡,該目錄駐留在iPhone的大容量的數(shù)據(jù)分區(qū)里因苹。可以安裝的應(yīng)用程序的數(shù)量依賴于數(shù)據(jù)分區(qū)的空閑空間篇恒》鲩埽空閑空間通常有上GB 容量,所以對安裝應(yīng)用程序數(shù)量來講不是真正的限制.
Cydia是越獄者制做的相當(dāng)于蘋果AppStore的應(yīng)用程序商店胁艰,通過Cydia下載的越獄應(yīng)用的安裝地點是不同的款筑。像Cydia自身和其他內(nèi)置的二進制文件安裝在root根目錄的/Application目錄下。前面提到蝗茁,root根文件系統(tǒng)的容量取決于固件的版本醋虏、容量和設(shè)備類型寻咒。通常在1GB和1.5GB之間哮翘,有大約200MB的空閑,這點容量對安裝應(yīng)用程序來說是不多的毛秘。
另外饭寺,墻紙和鈴聲也存放在根目錄的 /Library/Wallpaper 和 /Library/Ringtones目錄下,所以從Cydia安裝的每個墻紙和鈴聲也也會占用掉有限的應(yīng)用程序空間叫挟。
為解決這個問題艰匙,各種越獄都實現(xiàn)了應(yīng)用程序隱藏技術(shù)。它是在iPhone的數(shù)據(jù)分區(qū)創(chuàng)建了/var/stash的新目錄抹恳,并把一些正常情況下位于root根文件系統(tǒng)下的應(yīng)用程序移到/var/stash目錄下员凝,原來的目錄替換為鏈接到新目錄的符號鏈接。
以下清單是通過程序隱藏轉(zhuǎn)移到/var/stash下的目錄:
/Applications
/Library/Ringtones
/Library/Wallpaper
/usr/include
/usr/lib/pam
/usr/libexec
/usr/share
然而奋献,不是所有的越獄工具和所有版本的越獄工具都進行應(yīng)用程序隱藏健霹。因為這樣旺上,Cydia創(chuàng)建時在第一次調(diào)用時會進行檢測,這是Cydia里的重新組織文件系統(tǒng)(“Reorganizing Filesystem”)的耗時較長的步驟糖埋。
安裝程序包 (Bundle Installation)
越獄安裝過程的下一步是安裝程序包宣吱。根據(jù)使用的工具,它可以是一個高級用戶自己定制的程序包瞳别,或越獄后缺省附帶的Cydia程序包征候。例如,紅雪接收的程序包是簡單的tar文檔祟敛,可以選擇是否由gzip壓縮疤坝。 它們可以通過前面安裝的基本程序庫解壓,所以越獄不需要文檔解壓代碼垒棋。
程序庫的安裝是通過對存放在ramdisk上的程序包逐個解壓縮來進行的卒煞,解壓縮過程中,解壓縮程序(tar)保留了UNIX的許可權(quán)限叼架,以便允許你把suid的超級用戶位的設(shè)置一起打包設(shè)置畔裕。Cydia需要這個設(shè)置,因為沒有root超級用戶權(quán)限乖订,它不能安裝新的應(yīng)用程序扮饶。對于蘋果的欺騙是很有趣的,值得說明下乍构,因為圖形界面程序在他們的主目錄上不能有suid位設(shè)置甜无,所以Cydia通過運行一個叫做MobileCydia的shell腳本,來給主目錄設(shè)置suid位哥遮。
然而岂丘,應(yīng)用程序包解壓縮到/Application目錄后,安裝過程并未完成眠饮,所有的已安裝的應(yīng)用程序需要注冊到一個特殊的系統(tǒng)層面的安裝緩存里奥帘,它存儲在/var/mobile/Library/Caches/com.apple.mobile.installation.plist文件里。這個文件時一個正常的.plist文件仪召,格式如下:
LastDevDirStat
…
Metadata
…
System
com.apple.xxx
…
User
someuserapp
…
緩存包括一個時間戳寨蹋,一些元數(shù)據(jù),冠以所有系統(tǒng)和用戶程序的信息扔茅。系統(tǒng)程序都在/Application目錄里已旧,從蘋果的AppStore下載的用戶程序放在/var/mobile/Applications里。 所有的程序包都要注冊系統(tǒng)緩存條目召娜。紅雪會讀取應(yīng)用程序的Info.plist 文件运褪,利用里面的信息來創(chuàng)建新的緩沖條目。首先,讀取CFBundleIdentifier值并用來作為緩沖的一個新值秸讹,然后Info.plist文件里的系統(tǒng)值詞典里增加了一個應(yīng)用程序類型( ApplicationType)的新的值胁后。
安裝后過程(Post-Installation Process)
全部安裝完成后,紅雪調(diào)用sync()系統(tǒng)調(diào)用嗦枢,確保全部東西寫入磁盤攀芯。然后,root根文件系統(tǒng)被重新裝載為只讀狀態(tài)文虏,確保所有可寫緩沖區(qū)同步到磁盤上侣诺。裝載到 /var目錄的數(shù)據(jù)分區(qū)被卸載。在裝載操作失敗的情況下氧秘,重復(fù)這個過程直到它成功或直到超出重試次數(shù)年鸳。
越獄最后調(diào)用reboot()系統(tǒng)調(diào)用來重啟系統(tǒng),結(jié)束越獄過程丸相。如果是非完美越獄搔确,設(shè)備重啟為未越獄狀態(tài),除非安裝的程序包修改了重啟需要的文件灭忠。紅雪需要非完美重啟來使設(shè)備進入越獄狀態(tài)膳算。
如果設(shè)備已經(jīng)完美越獄,設(shè)備重啟會進入越獄狀態(tài)弛作。重啟過程中已安裝的完美漏洞會修改一些應(yīng)用涕蜂,利用其它內(nèi)核漏洞來在內(nèi)核里執(zhí)行代碼。在接下來的章節(jié)你將學(xué)習(xí)這些內(nèi)核payload映琳。
執(zhí)行內(nèi)核Payloads并修改內(nèi)核(Executing Kernel Payloads and Patches)
這章節(jié)將對前面關(guān)于內(nèi)核漏洞章節(jié)里沒有討論的內(nèi)核級別的Payload進行討論机隙。這是因為執(zhí)行內(nèi)核payload是越獄過程中用來真正打破監(jiān)獄封鎖的,是越獄最重要的部分萨西。因此我們認(rèn)為最好放在這一章節(jié)專門描述有鹿。
雖然每個內(nèi)核漏洞和每個payload是不同的,但能把越獄所用的內(nèi)核級的payload分為為4個部分:
(1)修復(fù)內(nèi)核狀態(tài)Kernel State Reparation
(2)權(quán)限提升Privilege Escalation
(3)修改內(nèi)核Kernel patching
(4)清理并返回Clean return
接下來的章節(jié)對他們進行詳細(xì)描述
修復(fù)內(nèi)核狀態(tài)(Kernel State Reparation)
雖然存在不同類型的內(nèi)核漏洞谎脯,但在內(nèi)核里執(zhí)行特定代碼通常是一些內(nèi)核級的函數(shù)指針被覆蓋的結(jié)果葱跋。按照漏洞的類型,被覆蓋的函數(shù)指針可以是內(nèi)核內(nèi)存里唯一崩潰的地方穿肄,但通常不是這樣年局。像堆載和堆緩沖區(qū)溢出這樣的類型的漏洞通常引起大面積的崩潰區(qū)域际看。尤其是由于攻擊堆的元數(shù)據(jù)結(jié)構(gòu)引起的堆緩沖區(qū)溢出咸产,在執(zhí)行漏洞代碼后內(nèi)核堆可能變成不穩(wěn)定的狀態(tài),結(jié)果就是或遲或早的內(nèi)核錯誤仲闽。
所以在每個內(nèi)核漏洞執(zhí)行后脑溢,修正它引起的內(nèi)存問題或崩潰的狀態(tài)是很重要的。剛開始把覆蓋的函數(shù)指針恢復(fù)成崩潰前的值,然而屑彻,通常這還不夠验庙。對于堆漏洞示血,由于被攻擊堆的元數(shù)據(jù)需要修復(fù)喇肋,內(nèi)核修復(fù)是可能是一個很復(fù)雜的任務(wù)顽铸。依據(jù)內(nèi)核堆的信息使用的方法期揪,它可能需要掃描內(nèi)核內(nèi)存拢切,查找需要釋放的被泄露的堆內(nèi)存塊梢莽,來確保內(nèi)核運行不越界魏滚。
對于堆棧數(shù)據(jù)崩潰扫倡,內(nèi)核堆棧是否需要修補取決于漏洞的情況熟空。 一個系統(tǒng)調(diào)用可能有處理例外的內(nèi)核線程藤巢,它的堆棧緩沖區(qū)溢出不需要修補,因為不會引起內(nèi)核錯誤息罗。
權(quán)限提升(Privilege Escalation)
由于iPhone上的所有應(yīng)用程序的都以權(quán)限較少的用戶(如mobile,_wireless,_mdsnresponder,_securityd)角色運行掂咒,一個內(nèi)核漏洞的payload執(zhí)行后,通常要把應(yīng)用程序的運行進程的權(quán)限提升到root超級用戶權(quán)限迈喉。 如果少了這一步驟绍刮,有些操作是不可能完成的的,像重新裝載root根文件系統(tǒng)到可寫狀態(tài)挨摸,或修改屬于root超級用戶的文件录淡。所有這些在越獄的初始安裝時都時需要的。只用于完美越獄的重啟后執(zhí)行的內(nèi)核漏洞不需要這一步驟油坝,因為通常已經(jīng)已root超級用戶角色運行嫉戚。
在內(nèi)核內(nèi)部,提升當(dāng)前運行進程的權(quán)限是很容易的澈圈。只需要修改進程的proc_t結(jié)構(gòu)的信用值彬檀。這個結(jié)構(gòu)在XNU源代碼的/bsd/sys/proc_internal.h文件的proc結(jié)構(gòu)里定義。依據(jù)不同的內(nèi)核漏洞payload開始運行方法的不同瞬女,取得當(dāng)前進程的proc_t結(jié)構(gòu)的指針的方法是不同的窍帝。在以前公開的許多iOS內(nèi)核漏洞里,用于覆蓋系統(tǒng)調(diào)用表里的系統(tǒng)調(diào)用程序的地址的辦法是不同的诽偷。內(nèi)核漏洞的payload由調(diào)用被覆蓋的系統(tǒng)調(diào)用來觸發(fā)坤学。在這種情況下,它獲得的proc_t結(jié)構(gòu)是微不足道的报慕,因為它是系統(tǒng)調(diào)用程序的第一參數(shù)深浮。
得到proc_t結(jié)構(gòu)的地址的更通用的方法是調(diào)用current_proc()內(nèi)核函數(shù),它能取回這個結(jié)構(gòu)的的地址眠冈。這個函數(shù)是一個內(nèi)核輸出的符號飞苇,很容易找到。由于剛開始的內(nèi)核漏洞能檢測使用的內(nèi)核版本,并且內(nèi)核里沒有地址隨機化布卡,所以它可以把函數(shù)的地址硬編碼到內(nèi)核漏洞里雨让。
取到proc_t結(jié)構(gòu)的地址的第三個方法是使用通過sysctl接口泄露的內(nèi)核地址信息。這項技術(shù)是由noir在破解OpenBSD內(nèi)核的過程中首先發(fā)表的(詳見www.phrack.org/issues.html?issue=60&id=06)忿等,并被nemo用于XNU內(nèi)核(詳見www.phrack.org/issues.html?issue=64&id=11)栖忠。這個泄露的信息允許用戶態(tài)進程通過一個簡單的sysctl系統(tǒng)調(diào)用取到proc結(jié)構(gòu)的內(nèi)核地址。
在取到進程proc_t結(jié)構(gòu)的地址后贸街,結(jié)構(gòu)里的p_ucred成員用來修改連接的ucred結(jié)構(gòu)娃闲。 這個元素可以通過proc_ucred()函數(shù)讀取,或直接讀取匾浪。下面的反匯編代碼表明在當(dāng)前iOS版本里結(jié)構(gòu)里p_ucred域的偏移量是0×84.
_proc_ucred:
LDR.WR0, [R0,#0x84]
BXLR
在/bsd/sys/ucred.h文件里有ucred結(jié)構(gòu)的定義皇帮。結(jié)構(gòu)里還包含擁有這個結(jié)構(gòu)的進程的用戶ID和組ID。
struct ucred {
TAILQ_ENTRY(ucred)cr_link;
u_longcr_ref;
struct posix_cred {
uid_tcr_uid;
uid_tcr_ruid;
uid_tcr_svuid;
shortcr_ngroups;
gid_tcr_groups[NGROUPS];
gid_tcr_rgid;
gid_tcr_svgid;
uid_tcr_gmuid;
int cr_flags;
} cr_posix;
struct label*cr_label;
struct au_session cr_audit;
};
為了提升擁有這個結(jié)構(gòu)的進程的權(quán)限蛋辈,結(jié)構(gòu)偏移量0x0c處的cr_uid域被設(shè)置為0属拾。如你預(yù)料的,偏移量是0x0c冷溶,而不是0×08渐白,是因為一個TAILQ_ENTRY條目是8byte的。當(dāng)然逞频,其他元素也能被修改纯衍。然而一旦uid值等于0,用戶態(tài)的進程就能利用系統(tǒng)調(diào)用更改它的許可權(quán)限苗胀。
修改內(nèi)核(Kernel Patching)
內(nèi)核級payload最重要的部分是對內(nèi)核代碼和數(shù)據(jù)進行內(nèi)核級別的修改襟诸,使安全功能失效,讓未簽名的代碼可以執(zhí)行基协,設(shè)備也就被越獄了歌亲。這幾年,不同的越獄團隊開發(fā)了他們自己的修改補丁澜驮,所以大部分越獄都有不同的內(nèi)核修改補丁陷揪,有不同的功能特性。最流行的內(nèi)核修改補丁是由comex開發(fā)的杂穷,可以在他的github里的datautils0程序庫得到(https://github.com/comex/datautils0)悍缠。它不僅被comex用于comex自己的越獄網(wǎng)站(http://jailbreakme.com),也被許多其他iOS內(nèi)核內(nèi)部研究的人做參考耐量。然而飞蚓,這些GitHub程序庫的特定的補丁,不可能適用將來的內(nèi)核版本拴鸵;因為comex已經(jīng)加入蘋果公司玷坠,很可能在從事和以前相反的工作,防止將來的iPhone被越獄劲藐。
然而八堡,接下來的章節(jié)向你介紹這些補丁和它們背后的原理,你可以用它們來開發(fā)你自己的內(nèi)核修改補丁聘芜,運用于未來的iOS版本兄渺。
security.mac.proc_enforce變量
security.mac.proc_enforce是個系統(tǒng)調(diào)用變量,它控制著是否在進程操作中使能MAC策略汰现。變量禁止時挂谍,各種進程策略檢查和限制就被關(guān)掉了。例如瞎饲,對fork(), setpriority(), kill() 和 wait() 系統(tǒng)調(diào)用的限制口叙。 除此以外,這個變量還控制著代碼簽名blob的數(shù)字簽名是否合法嗅战。變量禁止時妄田,代碼簽名blob的數(shù)字簽名是非法的二進制代碼也可以被執(zhí)行。
在iOS的4.3以前的版本里驮捍,這個變量對以root超級用戶方式運行的完美越獄漏洞來說是個捷徑疟呐。漏洞可以通過sysctl()系統(tǒng)調(diào)用禁止這個變量,來允許他們在內(nèi)核漏洞里執(zhí)行二進制代碼东且。像現(xiàn)在需求的用對象返回編程來編寫整個內(nèi)核漏洞沒有必要了启具。為了防止這個攻擊,蘋果公司在iOS4.3里已經(jīng)把security.mac.proc_enforce系統(tǒng)調(diào)用變量改為只讀了珊泳。
對于內(nèi)核payload鲁冯,因為能分配0值給這個變量,禁用該變量不是一個大問題色查。唯一需要做的工作是決定變量在內(nèi)存中的地址晓褪。一個可能的解決辦法是掃描內(nèi)核里的_sysctl_set段,這里定義了sysctl變量和變量的地址综慎。由于變量在內(nèi)核數(shù)據(jù)段內(nèi)涣仿,它是一個永久靜態(tài)地址。
內(nèi)核的cs_enforcement_disable變量
/osfmk/vm/vm_fault.c文件的頁錯誤處理程序的源代碼里有一個cs_enforcement_disable變量示惊,它控制著頁錯誤處理程序的代碼簽名是否起作用好港。該變量在iOS內(nèi)核里缺省的初始化為0,使之起作用米罚。如果反之钧汹,賦予非零值i,將不起作用录择。
查看代碼拔莱,你會發(fā)現(xiàn)這個變量只在vm_fault_enter()函數(shù)里用了2次碗降。下面的代碼是使用這個變量的第一次,對于發(fā)生了什么塘秦,代碼注解得很詳細(xì):
if(!cs_enforcement_disable && map_is_switched &&
map_is_switch_protected && page_immutable(m, prot) &&
(prot & VM_PROT_WRITE))
{
return KERN_CODESIGN_ERROR;
}
你在代碼里可以看到讼渊,如果設(shè)置了cs_enforcement_disable標(biāo)志,其他條件檢查就會被忽略尊剔。代碼接下來的檢查一頁內(nèi)存是否未簽名但想執(zhí)行的條件也會成立:
if (m->cs_tainted ||
(( !cs_enforcement_disable && !cs_bypass ) &&
(
(!m->cs_validated && (prot & VM_PROT_EXECUTE))||
(page_immutable(m, prot) && ((prot & VM_PROT_WRITE) || m->wpmapped))
))
)
{
在這兩種情況下爪幻,設(shè)置cs_enforcement_disable變量就能使保護失效⌒胛螅考慮到變量初始化為0并沒有被改寫挨稿,我們很慶幸編譯器沒有對它進行優(yōu)化。這個變量在二進制內(nèi)核里被定位后京痢,能被越獄修改奶甘。在iOS5里,comex沒有修改變量祭椰,而是選擇修改檢查的代碼甩十。即使在將來的iOS版本里該變量不再使用,直接修改代碼這個方法也仍然可行吭产。
datautils0里的內(nèi)核修改補丁通過搜索如下的字符串來定位檢查代碼:
df f8 88 33 1d ee 90 0fa2 6a1b 68 00 2b
它的反匯編代碼是:
80045730LDR.WR3, =dword_802DE330
80045734MRCp15, 0, R0,c13,c0, 4
80045738LDRR2, [R4,#0x28]
8004573ALDRR3, [R3]
8004573CCMPR3, #0
可以看到cs_enforcement_disable變量位于0x802DE330地址侣监,它的值被裝入R3寄存器,再和0做比較臣淤。最簡單的辦法是修改為在R3寄存器里裝入1橄霉。變量在vm_fault_enter()的使用也很容易修改,因為編譯器生成的代碼不重新裝載變量邑蒋,而是使用寄存器的緩存副本姓蜂。
AMFI模塊的cs_enforcement_disable變量
第四章討論過的蘋果手機文件完整性 Apple Mobile File Integrity (AMFI) 內(nèi)核模塊,用來檢查一些參數(shù)的存在性医吊。其中一個是cs_enforcement_disable钱慢。如果設(shè)置了這個參數(shù),它會影響AMFI_vnode_check_exec()函數(shù)的處理策略卿堂。在策略檢查的反編譯代碼里可以看到束莫,通過設(shè)置進程簽名代碼標(biāo)志里的CS_HARD和CS_KILL標(biāo)志,它停止了AMFI內(nèi)核模塊草描。
int AMFI_vnode_check_exec(kauth_cred_t cred, struct vnode *vp, struct label
*label, struct label *execlabel, struct componentname *cnp, u_int *csflags)
{
if ( !cs_enforcement_disable )
{
if ( !csflags )
Assert(
“/SourceCache/AppleMobileFileIntegrity/AppleMobileFileIntegrity-
79/AppleMobileFileIntegrity.cpp”,
872,
“csflags”);
*csflags |= CS_HARD|CS_KILL;
}
return 0;
}
如果CS_HARD和CS_KILL標(biāo)志沒有設(shè)置览绿,代碼簽名也能被有效的禁止。然而穗慕,不清楚當(dāng)前的越獄有無修改這個變量饿敲,因為execve() 和 posix_spawn()系統(tǒng)調(diào)用里使用的mac_vnode_check_exec()的策略檢查已經(jīng)被proc_enforce補丁禁用了,可以在如下代碼里看到:
int mac_vnode_check_exec(vfs_context_t ctx, struct vnode *vp,
struct image_params *imgp)
{
kauth_cred_t cred;
int error;
if (!mac_vnode_enforce || !mac_proc_enforce)
return (0);
cred = vfs_context_ucred(ctx);
MAC_CHECK(vnode_check_exec, cred, vp, vp->v_label,
(imgp != NULL) ? imgp->ip_execlabelp : NULL,
(imgp != NULL) ? &imgp->ip_ndp->ni_cnd : NULL,
(imgp != NULL) ? &imgp->ip_csflags : NULL);
return (error);
}
如果像大部分公開的越獄所做的逛绵,把proc_enforce設(shè)為0怀各,AMFI策略檢查根本不會執(zhí)行倔韭,而是成功返回。只有在一些我們知道的未公開的越獄里proc_enforce標(biāo)志沒有更改瓢对,在這種情況下寿酌,補丁是有效的。
PE_i_can_has_debugger函數(shù)
iOS內(nèi)核有一個PE_i_can_has_debugger()函數(shù)沥曹,內(nèi)核和一些內(nèi)核擴展里都用它來決定是否允許調(diào)試份名。例如碟联,如果這個函數(shù)返回值是真妓美,那么KDP內(nèi)核調(diào)試器不能使用。XNU的源代碼里沒有這個函數(shù)鲤孵,因此我們只能通過反編譯代碼查看:
int PE_i_can_has_debugger(int *pFlag)
{
int v1; // r1@3
if ( pFlag )
{
if ( debug_enable )
v1 = debug_boot_arg;
else
v1 = 0;
*pFlag = v1;
}
return debug_enable;
}
在iOS4.3以前的越獄版本里壶栋,這個函數(shù)被修改為永遠(yuǎn)返回為真。我們試著使用KDP內(nèi)核調(diào)試器普监,但不能工作贵试。由于只是返回真值并沒有完全仿真這個原始函數(shù)的行為,在一些iOS內(nèi)核擴展里設(shè)置調(diào)試啟動參數(shù)會引起內(nèi)核錯誤凯正。所以當(dāng)前的大部分越獄不再修改這個函數(shù)代碼毙玻,而是修改內(nèi)核里的debug_enable 變量。為了確定這個變量的地址廊散,必須分析PE_i_can_has_debugger()函數(shù)的代碼桑滩。因為這個變量位于一個未初始化的數(shù)據(jù)段里,修改只能在運行時進行允睹。為了查找啟動時初始化這個變量的代碼运准,需要搜索debug-enabled字符串,可以直接找到把值復(fù)制到變量的代碼缭受。
vm_map_enter函數(shù)
當(dāng)內(nèi)存映射到進程的地址空間時胁澳,內(nèi)核函數(shù)vm_map_enter()被用于分配一段虛擬地址映射。例如米者,可以用mmap()系統(tǒng)調(diào)用來觸發(fā)這個函數(shù)韭畸。這個函數(shù)對越獄有吸引力,因為它能使映射的內(nèi)存不能同時可寫和可執(zhí)行蔓搞。下面的代碼表明了這點陆盘。在/osfmk/vm/vm_map.c文件里可以查看這個函數(shù)的完整代碼,可以看到败明,如果設(shè)置了VM_PROT_WRITE 標(biāo)志隘马,VM_PROT_EXECUTE標(biāo)志就被清除。
kern_return_t vm_map_enter(
vm_map_tmap,
vm_map_offset_t*address,
vm_map_size_tsize,
vm_map_offset_tmask,
intflags,
vm_object_tobject,
vm_object_offset_toffset,
boolean_tneeds_copy,
vm_prot_tcur_protection,
vm_prot_tmax_protection,
vm_inherit_tinheritance)
{
…
if (cur_protection & VM_PROT_WRITE){
if ((cur_protection & VM_PROT_EXECUTE) && !(flags &
VM_FLAGS_MAP_JIT)){
printf(“EMBEDDED: %s curprot cannot be write+execute.
turning off execute\n”, _PRETTY_FUNCTION_);
cur_protection &= ~VM_PROT_EXECUTE;
}
}
像你在第四章里看到的一樣妻顶,這個規(guī)則有個叫做JIT(just-in-time)映射的例外酸员。這是一個特殊類型的內(nèi)存區(qū)域蜒车,允許同時可寫和可執(zhí)行,MobileSafari手機瀏覽器里的JIT javaScript編譯器需要這樣做幔嗦。一個應(yīng)用程序只有當(dāng)它有動態(tài)代碼簽名酿愧,才能使用一次這種例外。
迄今為止邀泉,只有MobileSafari手機瀏覽器才能這樣嬉挡。其他所有應(yīng)用程序都沒有可以修改自身的代碼、動態(tài)代碼生成器或JIT編譯器汇恤,不具有第四章討論過的 Charlie Miller發(fā)現(xiàn)的動態(tài)代碼簽名漏洞庞钢。為了完全越獄,需要取消這個限制因谎;因為它不允許應(yīng)用程序的運行時修改基括,而這是流行的MobileSubstrate公用程序庫所需要的。另外财岔,越獄過的iPhone里的一些模擬器需要自我修改的代碼风皿。
為了找到修改這個檢查的最好方法,需要查看iOS的二進制內(nèi)核匠璧。雖然沒有vm_map_enter() 函數(shù)的符號標(biāo)志桐款,但通過查找包含vm_map_enter的字符串,很容易找到這個函數(shù)夷恍。通過查看檢查功能的ARM的匯編代碼魔眨,可以發(fā)現(xiàn)有多個不同的取消檢查的方法,并且只需要修改一個字節(jié)裁厅。例如冰沙, AND.W R0, R1, #6 可以改為 AND.W R0, R1, #8,或BIC.W R0, R0, #4 可以改為 BIC.W R0, R0, #0:
800497C6LDRR1, [R7,#cur_protection]
800497C8AND.WR0, R4, #0×80000
800497CCSTRR0, [SP,#0xB8+var_54]
800497CESTRR1, [SP,#0xB8+var_78]
800497D0AND.WR0, R1, #6
800497D4CMPR0, #6
800497D6ITT EQ
800497D8LDREQR0, [SP,#0xB8+var_54]
800497DACMPEQR0, #0
800497DCBNEloc_800497F0
800497DELDR.WR1, =aKern_return_
800497E2MOVSR0, #0
800497E4BLsub_8001D608
800497E8LDRR0, [R7,#cur_protection]
800497EABIC.WR0, R0, #4
800497EESTRR0, [SP,#0xB8+var_78]
對于用iPhone越獄來進行安全研究和shell訪問的的人來說执虹,這個修改是不需要的拓挥。對這個限制進行修改實際上適得其反,因為手機的表現(xiàn)更像iPhone的默認(rèn)行為袋励。
vm_map_protect函數(shù)
vm_map_protect() 是內(nèi)核函數(shù)侥啤,它在映射內(nèi)存的保護改變時被調(diào)用。例如茬故,你可以用mprotect()系統(tǒng)調(diào)用來觸發(fā)它盖灸。和vm_map_enter()函數(shù)類似,它不能把內(nèi)存保護改為同時可寫可執(zhí)行磺芭。下面的代碼表明了這點赁炎。如果要看更多的細(xì)節(jié),在/osfmk/vm/vm_map.c文件里可以查看這個函數(shù)的完整代碼钾腺,可以看到徙垫,如果設(shè)置了VM_PROT_WRITE 標(biāo)志姻报,VM_PROT_EXECUTE標(biāo)志又會被清除荣瑟。
kern_return_t vm_map_protect(
register vm_map_tmap,
register vm_map_offset_tstart,
register vm_map_offset_tend,
register vm_prot_tnew_prot,
register boolean_tset_max)
{
. . .
#if CONFIG_EMBEDDED
if (new_prot & VM_PROT_WRITE) {
if ((new_prot & VM_PROT_EXECUTE) && !(current->used_for_jit)) {
printf(?EMBEDDED: %s can’t have both write and exec at the
same time\n”, _FUNCTION_);
new_prot &= ~VM_PROT_EXECUTE;
}
}
#endif
你又能發(fā)現(xiàn)一個用于JIT范圍的內(nèi)存例外仙辟,這只能由動態(tài)代碼簽名權(quán)限的應(yīng)用程序創(chuàng)建粟焊。沒有其他應(yīng)用程序能利用mprotect() 函數(shù)來使內(nèi)存同時可寫可執(zhí)行香追。所以標(biāo)準(zhǔn)的越獄修改了這個檢查顿苇,使應(yīng)用程序允許前面分配的內(nèi)存可寫可執(zhí)行漩氨。
為了修改這個函數(shù)首先需要找到它可都,雖然沒有指向這個函數(shù)的內(nèi)核符號指針,但在函數(shù)里有vm_map_protec字符串的引用鹦付,使它容易發(fā)現(xiàn)。再次查看你看到的ARM的匯編代碼腌巾,兩個可選擇的單字節(jié)修改可以用來清除這個安全檢查礁击。 AND.W R1,R6, #6 可以改為 AND.W R1, R6, #8; 或 BIC.W R6, R6, #4 可以改為BIC.W R6, R6, #0:
8004A950AND.WR1, R6, #6
8004A954CMPR1, #6
8004A956IT EQ
8004A958TSTEQ.WR0, #0×40000000
8004A95CBNEloc_8004A96A
8004A95EBIC.WR6, R6, #4
因為這個修改,越獄減弱了iOS設(shè)備的內(nèi)存保護缩搅。我們建議當(dāng)用戶想運行需要修改自身代碼的應(yīng)用程序時才進行這個補丁修改硼瓣。這些修改的問題是禁止了非執(zhí)行內(nèi)存的限制慢宗,以致對iPhone應(yīng)用程序的遠(yuǎn)程攻擊不需要實現(xiàn)百分百的ROP操作贱田。相反缅茉,這些攻擊或惡意程序只需要一個利用 mprotect()函數(shù)來注入執(zhí)行代碼的簡短的ROP stub。
AMFI二進制信任緩沖區(qū)(AMFI Binary Trust Cache)
AMFI內(nèi)核模塊負(fù)責(zé)檢查簽名代碼blob的數(shù)字簽名的合法性男摧。它注冊了一些MAC的策略處理句柄蔬墩,如vnode_check_signature鉤子,它在每次內(nèi)核增加一個新的簽名代碼blob時都會被調(diào)用耗拓;AMFI處理程序?qū)碜蕴O果的證書驗證簽名拇颅。然而,如果基于bootrom或 iBoot的越獄設(shè)置了啟動參數(shù)amfi_get_out_of_my_way 或 amfi_allow_any_signature乔询,驗證將會被跳過樟插。如果簽名代碼的blob的SHA1散列可以在一個內(nèi)置的大于2200個已知散列里找到的話,驗證也會被跳過。這些散列就是AMFI二進制信任緩沖區(qū)黄锤。這個信任緩沖區(qū)的查找是在一個單獨函數(shù)里實現(xiàn)的搪缨,comex對它進行了修改,使它總是返回為成功鸵熟。這使得AMFI相信每個簽名都在緩沖區(qū)里副编,是可信任的;這有效的禁止了簽名代碼blob的數(shù)字簽名流强。
可以通過在AMFI的MAC策略表里搜索AMFI的叫做vnode_check_signature 的MAC策略處理程序齿桃,通過搜索第一個內(nèi)部函數(shù)調(diào)用來找到這個函數(shù)的地址。另一個辦法是在內(nèi)核里搜索如下字節(jié)匹配模式:f0 b5 03 af 2d e9 00 05 04 46 .. ..14 f8 01 0b4ff0 130c
這些代碼接下來被一個返回為真的函數(shù)覆蓋后煮盼,會幫助跳過數(shù)字簽名驗證短纵。但對內(nèi)核修改的進一步研究會發(fā)現(xiàn)這根本不需要。因為查看在/security/mac_vfs.c里定義的 mac_vnode_check_signature代碼僵控,可以發(fā)現(xiàn)AMFi處理程序已經(jīng)被前面的proc_enforce修改完全禁止了香到。
int mac_vnode_check_signature(struct vnode *vp, unsigned char *sha1, void *
signature, size_t size)
{
int error;
if (!mac_vnode_enforce || !mac_proc_enforce)
return (0);
MAC_CHECK(vnode_check_signature, vp, vp->v_label, sha1, signature, size);
return (error);
}
如果the mac_proc_enforce標(biāo)志被禁止,AMFI的vnode_check_signature檢查將不會被調(diào)用报破。所有的MAC策略處理程序都會使用AMFI二進制信任緩沖區(qū)悠就。
0號進程任務(wù)陷阱(Task_for_pid 0)
雖然這個補丁修改對大部分越獄者都是沒有必要的,我們把它記錄下來是因為它涉及一個mach陷阱充易,下面我們會向你介紹一種在iOS二進制內(nèi)核里尋找mach陷阱表(mach_trap_table)的策略梗脾。
task_for_pid()是一個mach陷阱,會返回另一個進程的任務(wù)端口盹靴,以它的進程ID命名炸茧。這局限于用戶ID相同的進程,除非請求任務(wù)端口的進程是特權(quán)的稿静。在早期的Mac OS X版本中梭冠,通過請求0號進程的任務(wù)端口可以得到內(nèi)核進程的任務(wù)端口。在Mac OS X的rootkit里使用了這項技術(shù)改备,因為它允許用戶空間的進程去讀寫專有的內(nèi)核空間控漠。
這可能是task_for_pid()不再允許訪問0號進程的任務(wù)端口的原因,可以在XNU源代碼的/bsd/vm/vm_unix.c文件里的的看到如下的代碼:
kern_return_t task_for_pid(struct task_for_pid_args *args)
{
mach_port_name_ttarget_tport = args->target_tport;
intpid = args->pid;
user_addr_ttask_addr = args->t;
proc_tp = PROC_NULL;
task_tt1 = TASK_NULL;
mach_port_name_ttret = MACH_PORT_NULL;
ipc_port_ttfpport;
void * sright;
int error = 0;
AUDIT_MACH_SYSCALL_ENTER(AUE_TASKFORPID);
AUDIT_ARG(pid, pid);
AUDIT_ARG(mach_port1, target_tport);
if (pid == 0) {
(void ) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
return(KERN_FAILURE);
}
可以看到悬钳,對于0號進程有一個詳細(xì)的檢查盐捷,如果是0號進程會直接返回一個錯誤代碼。Comex修改了這個檢查默勾,把if語句里的條件跳轉(zhuǎn)改為無條件跳轉(zhuǎn)碉渡。修改的地址是通過對西面字節(jié)的模式匹配發(fā)現(xiàn)的:91 e8 01 04 d1 f8 08 80 00 21 02 91 ba f1 000f01 91
發(fā)現(xiàn)修改地方的另一個辦法是在mach的陷阱表里搜索task_for_pid()函數(shù)的地址。然而定義在/osfmk/kern/syscall_sw.c里的mach陷阱表的符號表并未輸出灾测,需要額外的辦法去發(fā)現(xiàn)它爆价。當(dāng)你查看表的定義時會看到如下類似的東西:
mach_trap_t mach_trap_table[MACH_TRAP_TABLE_COUNT] = {
MACH_TRAP(kern_invalid, 0, NULL, NULL),
MACH_TRAP(kern_invalid, 0, NULL, NULL),
MACH_TRAP(kern_invalid, 0, NULL, NULL),
. . .
MACH_TRAP(mach_reply_port, 0, NULL, NULL),
MACH_TRAP(thread_self_trap, 0, NULL, NULL),
MACH_TRAP(task_self_trap, 0, NULL, NULL),
. . .
MACH_TRAP(task_for_pid, 3, munge_www, munge_ddd),
可以看到垦巴,這張表的前面是一些非法內(nèi)核陷阱,這可以用來檢測內(nèi)存里的mach陷阱表的地址铭段。在公開的XNU的源代碼里定義的表骤宣,可以看到前面26個mach陷阱是非法的。然而查看iOS內(nèi)核序愚,卻發(fā)現(xiàn)只有前面10個mach陷阱是非法的憔披。
不幸的是,kern_invalid()函數(shù)沒有輸出爸吮,無法用來查找第一個mach陷阱芬膝。但這個問題可以解決,因為在下面的代碼可以看到它引用了一個很有揭示作用的字符串形娇。
kern_return_t kern_invalid(_unused struct kern_invalid_args *args)
{
if (kern_invalid_debug) Debugger(“kern_invalid mach trap”);
return(KERN_INVALID_ARGUMENT);
}
由于這個引用的字符串在整個代碼里只使用了一次锰霜,對這個字符串的唯一的交叉引用是在kern_invalid()函數(shù)里。通過這個地址的幫助桐早,在搜索四字節(jié)“0”和緊隨的這個函數(shù)地址的重復(fù)匹配模式后癣缅,可以找到mach陷阱表。但在當(dāng)前的iOS內(nèi)核里哄酝,查找mach陷阱表并不需要kern_invalid()函數(shù)的地址友存,四字節(jié)“0”的重復(fù)匹配模式的搜索后的指針已經(jīng)足夠發(fā)現(xiàn)mach陷阱表了。
修改沙盒 (Sandbox Patches)
Comex的內(nèi)核修改補丁的最后一步就是改變沙盒的行為陶衅。沒有這個修改補丁屡立,越獄過的iPhone不能運行類似MobileSafari 和 MobileMail的應(yīng)用程序。因為越獄后/Applications 目錄已經(jīng)移到/var/stash/Applications目錄了搀军,這違反了沙盒機制膨俐。 奇怪的是目前我們只知道這兩個應(yīng)用程序受影響。即使沒有修改沙盒奕巍,其他所有的內(nèi)置應(yīng)用程序看起來都能完美運行吟策。
這個修改補丁包括兩塊:第一塊是用鉤子(hook)覆蓋sb_evaluate()函數(shù)的開始部分;第二塊是在內(nèi)核里的未用區(qū)域?qū)懭胄麓a的止。這個函數(shù)的更多信息,可以回顧第5章着撩。這個修改補丁改變了沙盒仿真的修為诅福,去存取處理不同的特定的目錄。
在描述新的仿真功能前拖叙,由于沒有符號表可用氓润,我們要找到在內(nèi)核代碼里定位sb_evaluate()函數(shù)的方法。一個可能性是在沙盒內(nèi)核擴展里搜索mac策略處理程序表薯鳍。一些mac策略處理程序會用到sb_evaluate()函數(shù)咖气。當(dāng)前的iOS內(nèi)核里很容易搜索到錯誤操作碼的字符。因為只能在你的函數(shù)里使用它,一旦找到它的數(shù)據(jù)引用崩溪,你要找到它所用的函數(shù)的開始的地方浅役。
定位到sb_evaluate()函數(shù)的地址后,可以給它安裝一個鉤子函數(shù)伶唯,讓它跳轉(zhuǎn)到一個內(nèi)核未使用的區(qū)域觉既,在那里你可以放置其余代碼。我們在第9章里已經(jīng)討論過如何找到未用的區(qū)域乳幸。在comex的GitHub程序庫里可以找到datautils0程序的源代碼瞪讼,它模擬了鉤子的功能,我們現(xiàn)在要仔細(xì)研究它粹断。代碼的總體想法是對/private/var/mobile和private/var/mobile/Library/Preferences里的文件避免進行沙盒檢查符欠。代碼開始時檢查提供的vnode是否為0,如果為0瓶埋,不調(diào)用鉤子函數(shù)背亥,只是跳過檢查,執(zhí)行原來的處理程序悬赏。
start:
push {r0-r4, lr}
sub sp, #0×44
ldr r4, [r3, #0x14]
cmp r4, #0
beq actually_eval
接下來的代碼調(diào)用vn_getpath()函數(shù)狡汉,得到提供的vnode的路徑。如果返回錯誤闽颇,ENOSPC錯誤被忽略盾戴,其他錯誤則返回執(zhí)行原來的處理程序。
ldr r3, vn_getpath
mov r1, sp
movs r0, #0×40
add r2, sp, #0×40
str r0, [r2]
mov r0, r4
blx r3
cmp r0, #28
beq enospc
cmp r0, #0
bne actually_eval
如果沒有錯誤返回或者沒有獲得路徑全名的足夠空間兵多,返回的路徑名稱會和/private/var/mobile字符串作比較尖啡,如果不匹配,允許訪問:
enospc:
# that error’s okay…
mov r0, sp
adr r1, var_mobile ; # “/private/var/mobile”
movs r2, #19 ;# len(var_mobile)
ldr r3, memcmp
blx r3
cmp r0, #0
bne allow
如果路徑名稱匹配剩膘,會再和/private/var/mobile/Library/Preferences/com.apple相匹配衅斩,如果匹配成功,會調(diào)用原來的sb_evaluate()函數(shù)怠褐。
mov r0, sp
adr r1, pref_com_apple
; # “/private/var/mobile/Library/Preferences/com.apple”
movs r2, #49 ;# len(preferences_com_apple)
ldr r3, memcmp
blx r3
cmp r0, #0
beq actually_eval
下一步檢查路徑名稱是否在/private/var/mobile/Library/Preferences 里畏梆,如果是,允許訪問奈懒;否則調(diào)用原來的處理程序:
mov r0, sp
adr r1, preferences ;# “/private/var/mobile/Library/Preferences”
movs r2, #39 ;# len(preferences)
ldr r3, memcmp
blx r3
cmp r0, #0
bne actually_eval
代碼記下允許訪問的信息奠涌,返回提供的數(shù)據(jù)結(jié)構(gòu),第5章里有更詳細(xì)的描寫:
allow:
# it’s not in /var/mobile but we have a path, let it through
add sp, #0×44
pop {r0}
movs r1, #0
str r1, [r0]
movs r1, #0×18
strb r1, [r0, #4]
pop {r1-r4, pc}
代碼的其他部分只是跳過檢查磷杏,返回原來的函數(shù)溜畅。因為這只是標(biāo)準(zhǔn)的API攔截技術(shù),這里不進行討論极祸。
清空緩存(Clearing the Caches)
由于整個內(nèi)核鏡像是在一個可讀慈格、可寫怠晴、可執(zhí)行的內(nèi)存里,前面的內(nèi)核補丁修改都是直接了當(dāng)進行的浴捆。然而內(nèi)核級別的payload可以對原始代碼打補丁蒜田,不需要修改內(nèi)存的許可權(quán)限。
唯一混亂的地方是修改內(nèi)核時CPU指令和數(shù)據(jù)緩存需要清空汤功,否則越獄修改的結(jié)果不會立即激活物邑。
為了達(dá)到這個目的,漏洞payload應(yīng)該在每次修改內(nèi)核代碼或數(shù)據(jù)時立即調(diào)用iOS內(nèi)核的兩個輸出函數(shù)滔金。為了清空指令緩存色解,需要調(diào)用invalidate_icache()函數(shù),這個函數(shù)需要三個參數(shù)餐茵,第一個參數(shù)是要清空的無效的內(nèi)存區(qū)域地址科阎,第二個參數(shù)是內(nèi)存區(qū)域的長度,第三個參數(shù)應(yīng)該是0忿族。
清空數(shù)據(jù)緩存的函數(shù)是flush_dcache()函數(shù)锣笨,也需要同樣的三個調(diào)用參數(shù)。
清理并返回(Clean Return)
提升權(quán)限道批,修改安全特性错英,脫離內(nèi)核的掌控后,唯一要做的是讓內(nèi)核空間保持在清潔的狀態(tài)隆豹,防止內(nèi)核不穩(wěn)定或立即崩潰椭岩。通常只需要把普遍意義上的CPU寄存器的值恢復(fù)到調(diào)用內(nèi)核payload前的值,并返回保存的程序指針璃赡。萬一內(nèi)核堆棧被溢出了判哥,由于真實的堆棧的值被溢出的緩沖區(qū)覆蓋,導(dǎo)致不可能恢復(fù)碉考。這種情況下塌计,可以返回一個未被破壞的以前的堆棧幀。
另一個退出內(nèi)核的辦法是調(diào)用內(nèi)核的thread_exception_return()函數(shù)侯谁。由于這個函數(shù)在內(nèi)核里沒有符號表锌仅,需要通過模式匹配掃描和交叉引用掃描找到這個函數(shù)。當(dāng)內(nèi)核堆棧幀不可能回退時需要執(zhí)行完當(dāng)前內(nèi)核線程的例外情況良蒸,需要調(diào)用這個函數(shù)來恢復(fù)內(nèi)核技扼。因此,可以用它來離開漏洞payload后的內(nèi)核嫩痰。但是,內(nèi)核應(yīng)該盡可能通過返回正確的堆棧幀的來離開窍箍,否者串纺,離開后內(nèi)核不能保證還在穩(wěn)定狀態(tài)丽旅。
小結(jié)Summary
越獄被大多數(shù)人認(rèn)為是個黑盒子,這一章我們對它進行了深入研究纺棺。介紹了為安全研究使用越獄后的iPhone而不是原始iPhone的原因榄笙,討論了不同類型的越獄的優(yōu)缺點。
我們分析了紅雪越獄工具的內(nèi)部工作原理祷蝌,介紹了越獄過程的每一個步驟茅撞。從可用性和安全性的角度說明了越獄后的iPhone和未越獄的iPhone的不同點。
我們還說明了越獄所使用的內(nèi)核修改補丁巨朦,討論了每一個補丁的的原由米丘、如何發(fā)現(xiàn)修改地址、修改的方法糊啡。有了這些知識拄查,你也可以不依靠越獄社區(qū),自己把這些修改補丁移植到將來的iOS版本棚蓄。