Linux共享庫(kù)庫(kù)函數(shù)掛鉤主流兩種方法。一是替換函數(shù)對(duì)應(yīng)的GOT/PLT條目,GOT/PLT原理類(lèi)似Windows的IAT;二是inline掛鉤,即替換函數(shù)序言的幾個(gè)字節(jié)(x86是5或7字節(jié))為jmp/call,若發(fā)現(xiàn)稍遠(yuǎn)處有jmp或call(前提在入口基本塊內(nèi),若不在入口基本塊內(nèi)要修改分支控制條件,這有點(diǎn)復(fù)雜也無(wú)必要),則其目標(biāo)地址可被替換,這樣就不用替換序言的幾字節(jié)了。Windows的IAT掛鉤檢測(cè)很方便,因?yàn)閐ll的baseaddr及size可通過(guò)API VirtualQueryEx(https://learn.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualqueryex)或toolhelp庫(kù)的Module32First/Module32Next(https://learn.microsoft.com/zh-cn/windows/win32/api/tlhelp32/nf-tlhelp32-module32first)接口來(lái)獲取。同理linux也可以拿到有兩種方法,一種是讀/proc/pid/maps(這里pid為實(shí)際目標(biāo)進(jìn)程號(hào))獲取so庫(kù)代碼段的baseaddr和size,另一種用dl_iterate_phdr(https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html)拿到代碼段(pt_load類(lèi)型+可執(zhí)行標(biāo)志)的baseaddr及size。只要模塊(代碼段)的baseaddr及size確定了,檢測(cè)方法同IAT,即看替換函數(shù)地址是否不在代碼段空間內(nèi),若不在或地址不是原函數(shù)則認(rèn)為被掛鉤了,否則需進(jìn)一步用針對(duì)inline掛鉤法的檢測(cè)處理,見(jiàn)下文描述。另外dladdr(https://man7.org/linux/man-pages/man3/dladdr.3.html)判斷一個(gè)地址是否跟一個(gè)so庫(kù)及符號(hào)相關(guān),因此也可用于檢測(cè)掛鉤。如果是inline掛鉤法,那么分析函數(shù)入口基本塊內(nèi)(不管替換序言幾字節(jié)還是已有jmp/call目標(biāo)地址,都在入口基本塊)jmp/call的目標(biāo)地址(最好用成熟的反匯編引擎分析,比如llvm的mc庫(kù)反匯編功能,或https://salsa.debian.org/debian/distorm3),看是否超出so庫(kù)的代碼段空間