衆所周知一個 iOS App 的程序入口是main.m
, 但系統是怎麼找到main.m
的估計不少人就有疑問了,本文將詳細解釋這個問題.html
dyld(the dynamic link editor), 動態連接器,是專門用來加載動態庫以及主程序的庫. 當kernel
作好程序的啓動準備工做以後,系統的執行由內核態轉換爲用戶態,由 dyld 首先開始工做,iOS 中用到的全部系統framework都是動態庫,好比最經常使用的UIKit.framework
,Foundation.framework
, 而這些動態庫是手機內全部App共享的,因此須要在咱們 App運行前加載進來. dyld 主要的工做有:git
在 demo 里加[NSObject init]的符號斷點來看下: github
能夠看到入口函數事在dyid_start
方法裏的
dyldbootstrap::start
方法,接下來去源碼裏看看. 在 dyld 源碼裏找到
dyldStartup.s
找到了
__dyld_start
,這裏只截取了arm架構的部分.
經過註釋能夠看到有調用
dyldbootstrap::start
,那順着調用再往下看. 在
dyldInitialization.cpp
中找到了
start
slideOfMainExecutable
拿到隨機地址的偏移量rebaseDyld
重定位dyld::_main
,將返回值傳遞給__dyld_start
的調用main.m
函數.dyld::_main
是dyld中的關鍵方法,代碼也很是多,它的實現能夠分爲如下幾步: (關鍵部分有註釋)checkSharedRegionDisable
是檢查共享緩存是否禁用,裏面能夠看到一行註釋,iOS 必須開啓共享緩存才能運行.
static void checkSharedRegionDisable(const dyld3::MachOLoaded* mainExecutableMH, uintptr_t mainExecutableSlide) {
// iOS cannot run without shared region
}
複製代碼
接下來調的mapSharedCache()
就是加載共享緩存的邏輯,就不深刻了.bootstrap
ImageLoader
.先看下
instantiateFromLoadedImage
的調用棧:
其中
ImageLoader
是一個抽象類,它的兩個子類
ImageLoaderMachOCompressed
、
ImageLoaderMachOClassic
負責把 Mach-O 實例化爲 Image.但要用哪一個子類來進行實例化是經過
sniffLoadCommands
來判斷Mach-O 文件的 LINKEDIT 是classic或者compressed.
DYLD_INSERT_LIBRARIES
環境變量,而後調用
loadInsertedDylib
加載.
ImageLoader::link
函數,主要是作了加載動態庫、rebase、binding 等操做,代碼比較多,我就不貼了,在附件的源碼上有我寫的詳細註釋.
context.notifySingle(dyld_image_state_dependents_initialized, this, &timingInfo);
複製代碼
再往下找到sNotifyObjCInit
,再去找它的賦值找到registerObjCNotifiers
,從函數註釋來看是用objc runtime
來調的,這塊以後再看.在查閱一些資料以後得知,這裏的sNotifyObjCInit
就是調用 objc 中的 load_images,它調用全部的 load 方法,在調用完 load 方法之後調用了緩存
bool hasInitializers = this->doInitialization(context);
複製代碼
doInitialization
又調用了doModInitFunctions
, 也就是constuctor
方法,關於這個方法能夠參看連接.安全
getEntryFromLC_MAIN
,就是從``Load Command
中讀取
LC_MAIN
入口,若是沒有,就讀取
LC_UNIXTHREAD
,而後跳到入口處執行,就回到了咱們熟悉的
main.m`.
1.dyld 源碼: opensource.apple.com/tarballs/dy…
2.本文分析所用版本: dyld-635.2
3.帶註釋 dyld源碼地址: Github
bash
1.iOS 應用逆向與安全
2.www.dllhook.com/post/238.ht…
3.blog.sunnyxx.com/2014/08/30/…
架構