Mach-o格式、進(jìn)程以及線程內(nèi)幕(二)

Mach-O二進(jìn)制格式

????UNIX基本上標(biāo)準(zhǔn)化了一個(gè)通用的可移植的二進(jìn)制格式,這個(gè)格式成為Executable and Library Format(簡(jiǎn)稱ELF)投剥。這個(gè)格式具有良好的文檔,而且還有一整套binutils工具用于維護(hù)和調(diào)試這個(gè)格式的文件担孔,甚至同樣的CPU架構(gòu)上的不同UNIX之間還允許二進(jìn)制級(jí)別的可移植性(例如Linux和Solaris--這是真的江锨,x86版本的Solaris可以原生地執(zhí)行某些Linux二進(jìn)制文件)。然而OS X卻維護(hù)了一個(gè)自己獨(dú)有的二進(jìn)制格式:Mach-Object(簡(jiǎn)寫為Mach-O)糕篇,這是另一個(gè)源于NextSTEP的遺產(chǎn)啄育。
????Mach-O和蘋果的一些文檔對(duì)Mach-O的格式進(jìn)行了解釋。Mach-O格式具有一個(gè)固定的文件頭拌消。這個(gè)文件頭的詳細(xì)信息在<mach-o/loader.h>頭文件中挑豌,如圖4-3所示。
????文件頭一開(kāi)始是魔數(shù)值,加載器可以通過(guò)這個(gè)魔數(shù)值快速判斷這個(gè)二機(jī)制文件用于32位(MH_MAGIC, #define為0xFEEDFACE)還是64位(MH_MAGIC_64, #define為0xFEEDFACF)氓英。在魔數(shù)值之后跟著的是cpu類型以及子類型字段侯勉,這兩個(gè)字段和通用二進(jìn)制文件中的相同字段作用是一樣的---------用于確保二進(jìn)制文件適合并且可以在當(dāng)前架構(gòu)下運(yùn)行。除此之外铝阐,32位架構(gòu)和64位架構(gòu)的文件頭結(jié)構(gòu)就沒(méi)有實(shí)質(zhì)差別了:除了64位的頭文件還包含一個(gè)額外的預(yù)留字段之外址貌,這個(gè)字段目前沒(méi)有使用。


image.png

????由于這樣的同一種二進(jìn)制格式用于多種目標(biāo)文件類型(可執(zhí)行文件徘键,庫(kù)文件练对,核心轉(zhuǎn)儲(chǔ)文件以及內(nèi)核擴(kuò)展文件等),那么下一個(gè)int類型的字段filetype就用于表示目標(biāo)文件的類型,這個(gè)字段的可取值以宏的形式定義在<mach-o/loader.h>頭文件中啊鸭。在我們使用的系統(tǒng)中常見(jiàn)的值如表4-3所示锹淌。


image.png

????文件頭中還包含了重要的標(biāo)志,這些標(biāo)志也定義在<mach-o/loader.h>文件中赠制,如圖:
image.png

從上圖中可以看出赂摆,有兩個(gè)標(biāo)志和“執(zhí)行” 相關(guān):MH_ALLOW_STACK_EXECUTION和MH_NO_HEAP_EXECTION.這兩個(gè)標(biāo)志都用于防止某些數(shù)據(jù)的執(zhí)行,通常稱為NX(Non-eXecutable,可參閱內(nèi)存頁(yè)面中的一個(gè)同名標(biāo)志位)钟些。通過(guò)將數(shù)據(jù)所在的內(nèi)存頁(yè)面標(biāo)記為不可執(zhí)行烟号,(一般情況下)可以防止黑客進(jìn)行代碼注入,因?yàn)楹诳筒荒芊奖愕貓?zhí)行數(shù)據(jù)段中的代碼政恍。如果試圖執(zhí)行數(shù)據(jù)段中的代碼汪拥,則會(huì)引發(fā)一個(gè)硬件異常,進(jìn)程會(huì)終止---------讓進(jìn)程崩潰篙耗,從而避免執(zhí)行注入的代碼迫筑。

????由于代碼注入的常見(jiàn)方法是使用棧變量(即自動(dòng)變量),因此默認(rèn)情況下棧都標(biāo)記為不可執(zhí)行宗弯,而這個(gè)標(biāo)志可以用于覆蓋這種行為(非常危險(xiǎn))脯燃。堆則默認(rèn)可執(zhí)行。盡管完全可能蒙保,但是通過(guò)堆注入代碼相對(duì)困難一些辕棚。

????這兩個(gè)設(shè)置可以在系統(tǒng)級(jí)別進(jìn)行:通過(guò)sysctl(8)修改vm.allow_stack_exec和vm.allow_heap_exec變量。在發(fā)生沖突時(shí)邓厕,以更寬松的設(shè)置為準(zhǔn)(即false優(yōu)先于true)逝嚎。在iOS中,沒(méi)有暴露sysctl接口详恼,堆和棧都默認(rèn)不可執(zhí)行补君。
????Mach-O文件頭的主要功能在于加載命令(load command)。加載命令緊跟在文件頭之后昧互,文件頭中的兩個(gè)字段--------ncmds和sizeofincmds---------用于解析加載命令赚哗。之后會(huì)詳細(xì)討論她紫。


image.png

otool工具善于分析加載命令和文本段,但是不合適分析數(shù)據(jù)段和其他區(qū)域屿储。本書的支持網(wǎng)站上有一個(gè)名為jtool的工具贿讹,這個(gè)工具的目的是增強(qiáng)otool的功能。這個(gè)工具可以處理iOS 5.1和Mountain Lion之前(含)的所有類型的二進(jìn)制文件够掠。這個(gè)工具將nm和strings民褂、segedit、size和otool的功能整合在一個(gè)二進(jìn)制文件中疯潭,不僅特別適合腳本化操作赊堪,還支持一些新的特性。

????Mach-O文件頭中包含了非常詳細(xì)的指令竖哩,這些指令在被調(diào)用時(shí)清晰地指導(dǎo)了如何設(shè)置并加載二進(jìn)制數(shù)據(jù)哭廉。這些指令,或稱為“加載命令”相叁,緊跟在基本的mach_header之后遵绰,每一條指令都采用“類型-長(zhǎng)度-值”的格式:32位的cmd值(表示類型),32位的cmdsize值(32位二進(jìn)制位4的倍數(shù)增淹,64位二進(jìn)制為8的倍數(shù))椿访,以及命令本身(由cmdsize指定的任意長(zhǎng)度)。有一些命令是由內(nèi)核加載器(定義在bsd/kern/mach_loader.c文件中)直接使用的虑润,其他命令是由動(dòng)態(tài)鏈接器處理的成玫。
????加載命令總共有30多條。如圖列出了內(nèi)核使用的那些命令(之后在討論鏈接編輯器時(shí)會(huì)討論剩下的命令):


image.png

加載過(guò)程在內(nèi)核的部分負(fù)責(zé)新進(jìn)程的基本設(shè)置--------分配虛擬內(nèi)存拳喻,創(chuàng)建主線程哭当,以及處理任何可能的代碼簽名/加密的工作。然而對(duì)于動(dòng)態(tài)鏈接的可執(zhí)行文件(大部分可執(zhí)行文件都是動(dòng)態(tài)鏈接的)來(lái)說(shuō)冗澈,真正的庫(kù)加載和符號(hào)解析的工作都是通過(guò)LC_LOAD_DYLINKER命令指定的動(dòng)態(tài)鏈接器在用戶態(tài)完成的钦勘。控制權(quán)會(huì)轉(zhuǎn)交給鏈接器渗柿,鏈接器進(jìn)而接著處理頭文件中的其他加載命令(本章稍后會(huì)討論庫(kù)的加載)个盆。
????下面詳細(xì)討論這些加載命令脖岛。
????LC_SEGMENT 以及進(jìn)程虛擬內(nèi)存設(shè)置
????LC_SEGMENT(或LC_SEGMENT_64)命令是最主要的加載命令朵栖,這條命令指導(dǎo)內(nèi)核如何設(shè)置新運(yùn)行的進(jìn)程的內(nèi)存空間。這些“段”直接從Mach-O二進(jìn)制文件加載到內(nèi)存中柴梆。
????每一條LC_SEGMETN[_64]命令都提供了段布局的所有必要細(xì)節(jié)信息陨溅,如圖


image.png

image.png

????有了LC_SEGMENT命令,設(shè)置進(jìn)程虛擬內(nèi)存的過(guò)程就變成遵循LC_SEGMENT命令的簡(jiǎn)單操作绍在。對(duì)于每一個(gè)段门扇,將文件中相應(yīng)的內(nèi)容加載到內(nèi)存中:從偏移量為fileoff處加載filesize字節(jié)到虛擬內(nèi)存地址vmaddr處的vmsize字節(jié)雹有。每一個(gè)段的頁(yè)面根據(jù)iniprot進(jìn)行初始化,initprot指定了如何通過(guò)讀/寫/執(zhí)行位初始化頁(yè)面的保護(hù)級(jí)別臼寄。段的保護(hù)設(shè)置可以動(dòng)態(tài)改變霸奕,但是不能超過(guò)maxprot中指定的值(在iOS中,+x和+w是互斥的)吉拳。
????_PAGEZERO段(空指針陷阱)质帅、_TEXT段(程序代碼)、_DATA段(程序數(shù)據(jù))和_LINKEDIT(鏈接器使用的符號(hào)和其他表)段提供了LC_SEGMENT命令留攒。段有時(shí)候也可以進(jìn)一步分解為區(qū)(section)煤惩。如圖列出了一些常見(jiàn)的區(qū):
image.png

????段也可以設(shè)置一些<mach/loader.h>頭文件中定義的標(biāo)志。蘋果使用的一個(gè)標(biāo)志是SG_PROTECTED_VERSION_1(0x08)炼邀,表示這個(gè)段的頁(yè)面是“受保護(hù)的”魄揉,即加密的。蘋果通過(guò)這個(gè)種技術(shù)加密一些二進(jìn)制文件拭宁,例如Finder洛退。如圖所示:


image.png

????為了支持這種代碼加密,XNU內(nèi)核包含了一個(gè)特殊的自定義(外部)虛擬內(nèi)存管理器红淡,其名稱為“Apple protect”
????在創(chuàng)建Mach-O對(duì)象時(shí)不狮,可以通過(guò)-segcreate開(kāi)關(guān)讓Xcode的ld創(chuàng)建段。Xcode還包含一個(gè)名為segedit的特殊工具在旱,可以用于提取或替換Mach-O文件中的段摇零。這個(gè)工具可以用于提取內(nèi)嵌的文本信息,例如內(nèi)核的PRELINK_INFO區(qū)桶蝎,此外驻仅,本書的伴隨工具jtool也提供了這個(gè)功能。jtool還提供了另一個(gè)Xcode工具size的功能登渣,能夠打印出每一個(gè)段的大小和地址噪服。
????LC_UNIXTHREAD
????當(dāng)所有的庫(kù)都完成加載之后,dyld的工作也完成了胜茧,之后由LC_UNIXTHREAD命令負(fù)責(zé)啟動(dòng)二進(jìn)制程序的主線程(因此主線程總是在可執(zhí)行文件中粘优,而不會(huì)在其他二進(jìn)制文件中,例如庫(kù)文件)呻顽。根據(jù)架構(gòu)的不同雹顺,這條命令列出所有初始化寄存器的狀態(tài),不同架構(gòu)的寄存器狀態(tài)不同廊遍,這些不同的架構(gòu)包括i386_THREAD_STATE嬉愧、x86 _THREAD_STATE64以及iOS中的ARM_THREAD_STATE。在任何一種架構(gòu)中喉前,大部分寄存器應(yīng)該都會(huì)初始化為0没酣,其中指令指針(Intel的IP)或程序計(jì)數(shù)器(ARM的r15)是例外王财,這些寄存器保存了程序入口點(diǎn)的地址。

????在蘋果完成拋棄PPC平臺(tái)之前裕便,在Lion中绒净,還有一個(gè)PPC_THREAD_STATE。在某些包含了PPC代碼的胖二進(jìn)制文件中還能看到這個(gè)類型(例如在Snow Leopard中嘗試運(yùn)行otool -arch ppc -l/mach_kernel)偿衰。在這種情況下疯溺,寄存器srr0保存代碼的入口點(diǎn)。

????LC_THREAD
????和LC_UNIXTHREAD的功能類似哎垦,LC_THREAD用于核心轉(zhuǎn)儲(chǔ)文件囱嫩。Mach-O核心轉(zhuǎn)儲(chǔ)文件實(shí)際上是一個(gè)組LC_SEGMENT(或LC_SEGMENT_64)命令的集合,這些命令負(fù)責(zé)建立起進(jìn)程的內(nèi)存鏡像(只不過(guò)現(xiàn)在進(jìn)程已經(jīng)無(wú)效了)漏设,然后就是最后一條LC_THREAD命令墨闲。LC_THREAD命令也包含幾種不同的類型,每一種類型對(duì)應(yīng)不同的機(jī)器狀態(tài)(即線程郑口、浮點(diǎn)和異常)鸳碧。只要?jiǎng)?chuàng)建一個(gè)核心轉(zhuǎn)儲(chǔ)(這太簡(jiǎn)單了!)并通過(guò)otool -l查看這個(gè)核心轉(zhuǎn)儲(chǔ)文件就可以輕松找到這條命令了犬性。

????LC_MAIN
????從Mountain Lion開(kāi)始瞻离,一條新的加載命令LC_MAIN替代了LC_UNIXTHREAD命令。這條命令的作用是設(shè)置程序主線程的入口點(diǎn)地址和大小乒裆。這條命令比LC_UNIXTHREAD命令更實(shí)用一個(gè)些套利,

????LC_CODE_SIGNATURE
????Mach-O二進(jìn)制文件有一個(gè)重要特性就是可以進(jìn)行數(shù)字簽名。盡管在OS X中仍然沒(méi)怎么實(shí)用數(shù)字簽名鹤耍,不過(guò)由于代碼簽名和新改進(jìn)的沙盒機(jī)制綁定在一起肉迫,所以簽名的使用率也越來(lái)越高。在iOS中稿黄,代碼簽名是強(qiáng)制要求的喊衫,這也是蘋果盡可能對(duì)系統(tǒng)封鎖的另一種嘗試:在iOS中只有蘋果自己的簽名才會(huì)被認(rèn)可。在OS X中杆怕,codesign工具可以用于操縱和顯示代碼簽名族购。man手冊(cè)頁(yè),以及Apples code signing guide和Mac OS X Code Signing In Depth文檔都從系統(tǒng)管理的角度詳細(xì)解釋了代碼簽名機(jī)制陵珍。

????LC_CODE_SIGNATURE包含了Mach-O二進(jìn)制文件的代碼簽名寝杖,如果這個(gè)簽名和代碼本身不匹配(或者如果在iOS上這條命令不存在),那么內(nèi)核會(huì)立即給進(jìn)程發(fā)送一個(gè)SIGKILL信號(hào)將進(jìn)程殺掉撑教,沒(méi)有商量的余地朝墩,毫不留情醉拓。在ios4之前伟姐,還可以通過(guò)兩條sysctl命令覆蓋負(fù)責(zé)強(qiáng)制執(zhí)行(利用內(nèi)核的MAC,即Mandatory Access Control)的內(nèi)核變量收苏,從而實(shí)現(xiàn)禁用代碼簽名檢查:

sysctl -w security.mac.pro_enforce=0 // 禁用進(jìn)程的MAC
sysctl -w security.mac.vnode_enforce=0 //禁用VNode的MAC

????而在之后版本的iOS中,蘋果意識(shí)到只要能夠獲得root權(quán)限愤兵,越獄者就可以覆蓋內(nèi)核變量鹿霸。因此這些變量成了讀變量。untelthered越獄(即完美越獄)因?yàn)槔昧艘粋€(gè)內(nèi)核漏洞所以可以修改這個(gè)些變量秆乳。由于這些變量的默認(rèn)值都是啟用簽名檢查懦鼠,所以不完美越獄會(huì)導(dǎo)致非蘋果簽名的應(yīng)用程序崩潰-------除非i設(shè)備以完美越獄的方式引導(dǎo)。
????此外屹堰,通過(guò)Saurik的ldid這類工具可以在Mach-O中嵌入偽代碼簽名肛冶。這個(gè)工具可以替代OS X的codesign,允許生成自我簽署的偽簽名扯键。這在iOS中尤為重要睦袖,因?yàn)楹灻蜕澈心P偷膽?yīng)用程序“entitlement”綁定一起,而后者在iOS中是強(qiáng)制要求的荣刑。entitlement是聲明式的許可(以plist的形式保存)馅笙,必須內(nèi)嵌在Mach-O中并且通過(guò)簽名蓋章,從而允許執(zhí)行安全敏感的操作時(shí)具有運(yùn)行時(shí)權(quán)限厉亏。
????OS X和iOS都有一個(gè)特殊的系統(tǒng)調(diào)用csops用于代碼簽名的操作董习。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市爱只,隨后出現(xiàn)的幾起案子皿淋,更是在濱河造成了極大的恐慌,老刑警劉巖恬试,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沥匈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡忘渔,警方通過(guò)查閱死者的電腦和手機(jī)高帖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)畦粮,“玉大人散址,你說(shuō)我怎么就攤上這事⌒猓” “怎么了预麸?”我有些...
    開(kāi)封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)儒将。 經(jīng)常有香客問(wèn)我吏祸,道長(zhǎng),這世上最難降的妖魔是什么钩蚊? 我笑而不...
    開(kāi)封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任贡翘,我火速辦了婚禮蹈矮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸣驱。我一直安慰自己泛鸟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布踊东。 她就那樣靜靜地躺著北滥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闸翅。 梳的紋絲不亂的頭發(fā)上再芋,一...
    開(kāi)封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音坚冀,去河邊找鬼祝闻。 笑死,一個(gè)胖子當(dāng)著我的面吹牛遗菠,可吹牛的內(nèi)容都是我干的联喘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辙纬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼豁遭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起贺拣,我...
    開(kāi)封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蓖谢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后譬涡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體闪幽,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年涡匀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盯腌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡陨瘩,死狀恐怖腕够,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舌劳,我是刑警寧澤帚湘,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站甚淡,受9級(jí)特大地震影響大诸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一资柔、第九天 我趴在偏房一處隱蔽的房頂上張望焙贷。 院中可真熱鬧,春花似錦建邓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至外遇,卻和暖如春注簿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背跳仿。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工诡渴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人菲语。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓妄辩,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親山上。 傳聞我的和親對(duì)象是個(gè)殘疾皇子眼耀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容