最近經(jīng)常用到PLT hook,接下來幾篇文章胀滚,給大家介紹一下PLT hook的原理趟济、使用、案例咽笼、以及一些注意事項顷编。
今天是第一篇,先來介紹一下PLT Hook的基本原理剑刑。
ELF文件格式
ELF:Executable and Linkable Format
動態(tài)鏈接庫就是ELF格式的文件媳纬,要搞清楚PLT Hook的原理,首先要了解ELF文件格式施掏。
ELF分為連接視圖和執(zhí)行視圖钮惠。
- 連接視圖:ELF未被加載到內(nèi)存執(zhí)行前,以section為單位的數(shù)據(jù)組織形式
- 執(zhí)行視圖:ELF被加載到內(nèi)存后七芭,以segment為單位的數(shù)據(jù)組織形式
PLT Hook是運行中修改內(nèi)存中的數(shù)據(jù)素挽,所以我們主要關(guān)心的是執(zhí)行視圖。
linker依據(jù)ELF文件執(zhí)行視圖中的信息狸驳,用mmap將ELF加載到內(nèi)存中预明,執(zhí)行relocation將外部引用的絕對地址填入GOT表和DATA中。
PLT Hook的執(zhí)行時機耙箍,是在linker將ELF加載到內(nèi)存之后撰糠。Hook的原理,是解析內(nèi)存中的ELF數(shù)據(jù)辩昆,修改relocation結(jié)果阅酪。
裝載、動態(tài)鏈接卤材、重定位
1. 裝載
使用System.loadLibrary的方式遮斥,加載目標(biāo)共享庫,內(nèi)部其實也是調(diào)用linker中的dlopen扇丛、dlsym术吗、dlclose函數(shù)對目標(biāo)共享庫進行裝載。
2. 動態(tài)鏈接
動態(tài)鏈接的基本思想是把程序按照模塊拆分成各個相對獨立部分帆精,在程序運行時才將它們鏈接在一起较屿。當(dāng)共享庫被裝載的時候隧魄,動態(tài)鏈接器linkder會將共享庫裝載到進程的地址空間,并且將程序中的符號綁定到動態(tài)鏈接庫中隘蝎,進行重定位工作购啄。
3. 重定位
共享庫需要重定位的主要原因是導(dǎo)入符號的存在。動態(tài)鏈接下嘱么,一旦依賴于其他共享對象狮含,就會有導(dǎo)入符號。這些導(dǎo)入符號在編譯的時候是未知的曼振,只有在運行的時候才確定几迄,所以需要就這些導(dǎo)入符號的引入進行修正,即進行重定位冰评。
PLT Hook的原理映胁,就是改變導(dǎo)入符號重定位的結(jié)果。
linker
linkder在加載ELF時的最主要工作是relocation甲雅,這個過程的目的是為當(dāng)前ELF的每個“導(dǎo)入符號”找到對應(yīng)的外部符號(函數(shù)或數(shù)據(jù))的絕對地址解孙。
這些地址會寫在以下幾個地方:
- .got.plt: GOT表,保存外部函數(shù)的絕對地址
- .data, .data.rel.ro:保存外部數(shù)據(jù)(包含函數(shù)指針)的絕對地址
要完成 relocation 過程抛人,需要依賴于 ELF 中的以下信息:
- .rel.plt弛姜,.rela.plt:用于關(guān)聯(lián) .dynsym 和 .got.plt。這就是我們經(jīng)常會聽到的 “PLT 表”函匕。
- .rel.dyn娱据,.rela.dyn,.rel.dyn.aps2盅惜,.rela.dyn.aps2:用于關(guān)聯(lián) .dynsym 和 .data中剩,.data.rel.ro。
relocation完成后的函數(shù)調(diào)用關(guān)系如下:
PLT和GOT表
- PLT表:程序鏈接表(Procdure Link Table)抒寂,外部調(diào)用的跳板结啼,.plt
- GOT表:全局偏移表 (Global Offset Table),記錄外部調(diào)用的入口地址屈芜,.got
由上面的分析可知郊愧,當(dāng)我們調(diào)用某個函數(shù)的時候,并不是直接調(diào)用函數(shù)的地址井佑,而是經(jīng)過PLT表属铁,跳轉(zhuǎn)到GOT表,獲取目標(biāo)函數(shù)的全局偏移躬翁。這個時候就可以通過基址+偏移的方式焦蘑。定位到真正的函數(shù)地址。
PLT Hook基本原理
PLT Hook就是改變了原來的relocation后的地址盒发。主要流程:
- 通過符號名例嘱,在hash table中找到對應(yīng)的符號信息
- 再找到對應(yīng)的PLT信息
- 最后找到GOT表中的絕對地址的值
- 修改這個絕對地址的值狡逢,為我們的“代理函數(shù)”的地址