動態(tài)鏈接與靜態(tài)鏈接

  • 什么是靜態(tài)鏈接
  • 如何實現(xiàn)靜態(tài)鏈接
  • 靜態(tài)鏈接的優(yōu)點與缺點
  • 什么是動態(tài)鏈接
  • 如何實現(xiàn)動態(tài)鏈接
  • 動態(tài)鏈接的優(yōu)點與缺點
  • SO文件格式簡析
  • 根據(jù)SO文件格式進行靜態(tài)反編譯

靜態(tài)鏈接

一段代碼從文本編輯器上產(chǎn)生到最終能夠在機器上運行恳邀,經(jīng)歷了非常多的階段,概括而言蕾殴,至少包含了以下幾個階段:

  • 編譯: 編譯器通過詞法分析肥败,語法分析谭确,語義分析等,將一段代碼翻譯成匯編語言
  • 匯編:將匯編語言翻譯成機器指令
  • 鏈接:解決符號之間的重定位問題
  • 裝載:將可執(zhí)行文件加載到內(nèi)存

靜態(tài)鏈接就是在裝載之前,就完成所有的符號引用的一種鏈接方式于樟。靜態(tài)鏈接的處理過程分為2個步驟:

  1. 空間與地址的分配艘希。掃描所有的目標文件硼身,合并相似段硅急,收集當中所有的符號信息。
  2. 符號解析與重定位佳遂。調(diào)整代碼位置营袜。
鏈接前和鏈接后

如何可得,在完成靜態(tài)鏈接之后丑罪,可執(zhí)行文件中代碼段荚板、數(shù)據(jù)段等的虛擬地址已經(jīng)確定,即當此可執(zhí)行文件被載入到內(nèi)存后吩屹,代碼段的起始位置就在0000000000400400的位置跪另。

靜態(tài)鏈接的優(yōu)缺點

  • 優(yōu)點: 簡單
  • 缺點:
    • 浪費內(nèi)存空間。在多進程的操作系統(tǒng)下煤搜,同一時間免绿,內(nèi)存中可能存在多個相同的公共庫函數(shù)。
    • 程序的開發(fā)與發(fā)布流程受模塊制約擦盾。 只要有一個模塊更新嘲驾,那么就需要重新編譯打包整個代碼。

為了解決以上2個問題迹卢,就誕生了動態(tài)鏈接辽故。

動態(tài)鏈接

基本思想就是將對符號的重定位推遲到程序運行時才進行。

只要推遲到運行時進行符號的重定位腐碱,就能解決靜態(tài)鏈接的兩個缺點誊垢。

對于第一個缺點:在運行時重定位,如果在運行過程中調(diào)用了公共庫函數(shù)或者其他模塊的函數(shù)症见,系統(tǒng)只需要在內(nèi)存中維護一份公共庫代碼即可彤枢,只要將不同應用程序?qū)矌旌瘮?shù)的調(diào)用地址設置成相同即可。

對于第二個缺點:理論上只要將需要替換的模塊更新筒饰,無需將整個應用程序打包缴啡。

動態(tài)鏈接的實現(xiàn)

對于靜態(tài)鏈接來說,系統(tǒng)只需要加載一個文件(可執(zhí)行文件)到內(nèi)存即可瓷们,但是在動態(tài)鏈接下业栅,系統(tǒng)需要映射一個主程序和多個動態(tài)鏈接模塊,因此谬晕,相比于靜態(tài)鏈接碘裕,動態(tài)鏈接使得內(nèi)存的空間分布更加復雜。

不同模塊在內(nèi)存中的裝載位置一定要保證不一樣攒钳。

裝載時重定位

對于每一個模塊帮孔,對于代碼中符號的絕對引用,都需要加上一個基地址偏移量。(比如一個模塊中存在一個絕對地址的引用A文兢,它假定的是模塊可以被加載到0x1000的地方晤斩,但是系統(tǒng)在加載該位置已經(jīng)被其他模塊占用了,系統(tǒng)選擇將它加載到0x4000的地方姆坚,那么對絕對地址A的引用就需要被修改為A+0x3000澳泵,即修改代碼)。

但是它也有缺點兼呵,因為不同進程可能使用同一個模塊兔辅,但是對于不同進程,代碼段是不能共享的击喂,因此维苔,多個進程還是沒有辦法共享一個模塊。因為不能修改模塊當中的代碼懂昂,一旦一個進程將共享模塊的絕對地址修改了介时,其他進程此時調(diào)用就一定會報錯。

解決這個問題也有辦法忍法,在Windows中使用的就是裝載時重定位,但是在Linux下使用的是另外一種方式榕吼。

地址無關(guān)代碼

一個模塊的代碼部分是共享的饿序,但是數(shù)據(jù)部分是每個進程一個副本的。因此羹蚣,地址無關(guān)代碼的基本思想就是將代碼段中的絕對地址引用剝離出來放到數(shù)據(jù)段中原探,以保證代碼指令不變。在Android系統(tǒng)下進行SO文件的編譯顽素,默認就是產(chǎn)生地址無關(guān)代碼咽弦。

因此程序執(zhí)行的流程就變成了:當模塊A調(diào)用模塊B的某個方法的時候,會從模塊A的數(shù)據(jù)段部分找到模塊B中函數(shù)地址胁出,然后進行函數(shù)調(diào)用型型。

動態(tài)鏈接的優(yōu)點與缺點

優(yōu)點: 解決了靜態(tài)鏈接的缺陷,更適應現(xiàn)代的大規(guī)模的軟件開發(fā)

缺點:1. 結(jié)構(gòu)復雜 2.引入了安全問題全蝶,這也是我們能夠進行PLT HOOK的基礎

SO文件格式

ELF頭表

ELF頭表記錄了ELF文件的基本信息闹蒜,包括魔數(shù),目標文件類型(可執(zhí)行文件抑淫,共享庫文件或者目標文件)绷落,文件的目標體系結(jié)構(gòu),程序入口地址(共享庫文件為此值為0)始苇,然后是section表大小和數(shù)目砌烁,程序頭表的大小和數(shù)目,分別對應的是鏈接視圖和執(zhí)行視圖催式。

Section表

Section表記錄了每一個Section的基本信息函喉,名稱避归,類型,字節(jié)數(shù)函似,虛擬地址偏移和文件偏移槐脏。文件偏移指的是在ELF文件中,Section距離ELF文件起始位置的字節(jié)數(shù)撇寞,而虛擬地址偏移指的是當此section被加載到內(nèi)存中后顿天,該Section距離ELF起始位置的字節(jié)數(shù)。由于有些section只存在于文件中蔑担,而不會被系統(tǒng)加載到內(nèi)存中牌废,因此虛擬地址偏移可能為0.

程序頭表

程序頭表是裝載視圖下,系統(tǒng)進行segment解析的入口啤握,它給出了每一個segment的類型鸟缕,文件偏移,虛擬地址偏移和對齊等排抬。通過對程序頭表的遍歷懂从,我們可以得到ELF文件所有的segment。

重定位表

靜態(tài)鏈接下需要對符號的引用進行重定位蹲蒲,并且ELF文件中對符號的引用可能出現(xiàn)在代碼段番甩,也可能出現(xiàn)在數(shù)據(jù)段,因此重定位表分為了代碼段重定位表和數(shù)據(jù)段重定位表届搁,分別記錄引用的符號名和所在的偏移地址缘薛。因此,重定位表的格式就是記錄符號名和重定位地址的數(shù)組卡睦。

.dynamic段

.dynamic段是動態(tài)鏈接中最重要的段宴胧,它記錄了和動態(tài)鏈接有關(guān)的段的類型,地址或者數(shù)值表锻。指向了與動態(tài)鏈接相關(guān)的段

.got段

位于數(shù)據(jù)區(qū)恕齐,就是上文所述為了實現(xiàn)位置無關(guān)代碼將對絕對地址的引用抽離出來存放的集合

.plt段

在介紹.rel.plt段之前,對比靜態(tài)鏈接與動態(tài)鏈接我們需要知道.plt段的作用瞬逊。我們會發(fā)現(xiàn)檐迟,動態(tài)鏈接將所有的重定位操作延遲到加載時處理,那么就難以避免的會降低程序執(zhí)行的效率码耐,試想追迟,如果有1000個對外部模塊的函數(shù)引用,動態(tài)鏈接器就需要先解決這1000個函數(shù)引用骚腥,然后才開始執(zhí)行程序敦间。為此,鏈接器為了提升效率,采取了這樣一種策略:僅當函數(shù)被調(diào)用時廓块,才會喚醒動態(tài)鏈接器解決重定位問題厢绝。

.plt段就是為了實現(xiàn)這種策略增加的段。增加了.plt段之后带猴,代碼段中的地址就不再指向.got段而是指向了.plt段昔汉,再由.plt段指向.got段,具體過程如下:

.plt段是包含了若干數(shù)目的代碼片段組成的段拴清,代碼段中的地址指向?qū)瘮?shù)的.plt代碼段靶病,代碼片段的第一行代碼就是間接調(diào)用.got表中對應函數(shù)地址,但是此時口予,.got表中的地址指向的是.plt中代碼片段的第二行代碼娄周,而第二行以后的代碼作用就是調(diào)用動態(tài)鏈接器處理.got表中的地址。當再次調(diào)用此函數(shù)時沪停,.plt中代碼段第一行代碼就可以正確的跳入函數(shù)地址執(zhí)行相應的函數(shù)了煤辨。

但是,在Android平臺下木张,由于兼容性的限制众辨,并沒有采用這種"延遲加載"的特性,所以一開始加載舷礼,.got表中的地址就是真實的函數(shù)調(diào)用地址鹃彻。但是,Android下的ELF文件仍然保留了.plt表這種結(jié)構(gòu)且轨。

根據(jù)SO文件結(jié)構(gòu)進行靜態(tài)反編譯

靜態(tài)反編譯是指對未載入內(nèi)存控件的SO文件進行的反編譯浮声,在這種情況下虚婿,主要是針對SO文件的鏈接視圖進行關(guān)鍵參數(shù)上的修改旋奢,使得靜態(tài)反編譯工具不能夠正常的工作。

根據(jù)SO文件的格式然痊,在ELF頭表中會表明Section表的位置和Section表格的大小至朗。絕大部分靜態(tài)反編譯工具是依據(jù)SO文件的鏈接視圖還原出SO文件內(nèi)容的,那么在這種情況下剧浸,我們只需要修改ELF頭表中與SECTION表相關(guān)的2個參數(shù)锹引,就能使得工具反編譯SO文件失效。但是SO文件在系統(tǒng)載入內(nèi)存之后唆香,是使用的執(zhí)行視圖對SO文件進行解析嫌变,因此不會影響SO文件運行時。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躬它,一起剝皮案震驚了整個濱河市腾啥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖倘待,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疮跑,死亡現(xiàn)場離奇詭異,居然都是意外死亡凸舵,警方通過查閱死者的電腦和手機祖娘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啊奄,“玉大人渐苏,你說我怎么就攤上這事≡鋈龋” “怎么了整以?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長峻仇。 經(jīng)常有香客問我公黑,道長,這世上最難降的妖魔是什么摄咆? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任凡蚜,我火速辦了婚禮,結(jié)果婚禮上吭从,老公的妹妹穿的比我還像新娘朝蜘。我一直安慰自己,他們只是感情好涩金,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布谱醇。 她就那樣靜靜地躺著,像睡著了一般步做。 火紅的嫁衣襯著肌膚如雪副渴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天全度,我揣著相機與錄音煮剧,去河邊找鬼。 笑死将鸵,一個胖子當著我的面吹牛勉盅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顶掉,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼草娜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痒筒?” 一聲冷哼從身側(cè)響起宰闰,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤嗜暴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后议蟆,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闷沥,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年咐容,在試婚紗的時候發(fā)現(xiàn)自己被綠了舆逃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡戳粒,死狀恐怖路狮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蔚约,我是刑警寧澤奄妨,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站苹祟,受9級特大地震影響砸抛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜树枫,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一直焙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧砂轻,春花似錦奔誓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辆童,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工幌绍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留颁褂,地道東北人故响。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像颁独,于是被迫代替她去往敵國和親彩届。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

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