本申請涉及通信技術領域,尤其涉及一種函數(shù)調(diào)用方法和裝置。
背景技術:
在不具有應用對應的源代碼的情況下,如果需要對應用進行二次開發(fā)或者進行性能測試,就需要想辦法調(diào)用該應用程序中的一些函數(shù),以對該函數(shù)進行修改或進行其他處理。
很多情況下,對應用進行二次開發(fā)或性能測試的用戶所感興趣的函數(shù)可能會在應用的動態(tài)鏈接庫中,如果感興趣的函數(shù)是動態(tài)鏈接庫中的導出函數(shù),那么通過操作系統(tǒng)的調(diào)用接口可以直接對感興趣的函數(shù)進行調(diào)用;如果感興趣函數(shù)是動態(tài)鏈接庫中的未導出的函數(shù),那么則無法通過操作系統(tǒng)的調(diào)用接口對開感興趣的函數(shù)進行調(diào)用,從而影響到了對應用的二次開發(fā)或者性能測試。因此,如何實現(xiàn)靈活、便捷調(diào)用動態(tài)鏈接庫中的未導出的函數(shù)是本領域技術人員迫切需要解決的技術問題。
技術實現(xiàn)要素:
有鑒于此,本申請?zhí)峁┝艘环N函數(shù)調(diào)用方法和裝置,在對應用程序進行性能測試或二次開發(fā)的過程中,可以降低調(diào)用未導出的函數(shù)的復雜度,提高調(diào)用未導出的函數(shù)的便捷性和靈活性。
為實現(xiàn)上述目的,一方面,本申請?zhí)峁┝艘环N函數(shù)調(diào)用方法,包括:
在應用中運行被注入的邏輯函數(shù),所述邏輯函數(shù)用于對所述應用進行測試或二次開發(fā);
在運行所述邏輯函數(shù)的過程中,如果需要對所述應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,運行注入到所述應用中且用于獲取函數(shù)偏移地址的偏移地址函數(shù),以分析出當前時刻所述目標函數(shù)相對于所述動態(tài)鏈接庫的目標偏移地址;
依據(jù)所述目標偏移地址,運行注入到所述應用中的指針生成函數(shù),以確定調(diào)用所述目標函數(shù)所需的函數(shù)指針。
另一方面,本申請還提供了一種函數(shù)調(diào)用裝置,包括:
第一函數(shù)運行單元,用于在應用中運行被注入的邏輯函數(shù),所述邏輯函數(shù)用于對所述應用進行測試或二次開發(fā);
第二函數(shù)運行單元,用于在運行所述邏輯函數(shù)的過程中,如果需要對所述應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,運行注入到所述應用中且用于獲取函數(shù)偏移地址的偏移地址函數(shù),以分析出當前時刻所述目標函數(shù)相對于所述動態(tài)鏈接庫的目標偏移地址;
指針生成單元,用于依據(jù)所述目標偏移地址,運行注入到所述應用中的指針生成函數(shù),以確定調(diào)用所述目標函數(shù)所需的函數(shù)指針。
經(jīng)由上述的技術方案可知,在申請實施例中,向待測試或二次開發(fā)的應用中注入用于對該應用進行測試或二次開發(fā)的邏輯函數(shù)的同時,還向應用中注入了用于獲取函數(shù)偏移地址的偏移地址函數(shù)以及生成函數(shù)指針的指針生成函數(shù),這樣,在應用運行該邏輯函數(shù)的過程中,如果需要對應用中的某個動態(tài)鏈接庫中未導出的某個函數(shù)進行調(diào)用時,可以通過運行該偏移地址函數(shù),實時動態(tài)的分析出當前時刻該函數(shù)相對于該動態(tài)鏈接庫的目標偏移地址,從而基于確定出的目標偏移地址以及注入到應用中的指針生成函數(shù),便可以得到調(diào)用該未導出的函數(shù)所需的函數(shù)指針,實現(xiàn)對未導出的函數(shù)的靈活調(diào)用。
而且,由于偏移地址函數(shù)具有普遍適用性,對于任意一款需要進行測試或二次開發(fā)的應用而言,在向應用中注入該偏移地址函數(shù)之后,在需要調(diào)用該應用的動態(tài)鏈接庫中的任意未導出的函數(shù)時,均可以通過運行該偏移地址函數(shù)分析出該未導出的函數(shù)相對于該動態(tài)鏈接庫的偏移地址,并結合指針生成函數(shù)得到調(diào)用未導出的函數(shù)所需的函數(shù)指針,這樣,二次開發(fā)或測試系統(tǒng)只需要維護一套偏移地址函數(shù)以及該指針生成函數(shù),便可以實現(xiàn)對任意應用中任意未導出的函數(shù)的調(diào)用,避免了針對不同應用的不同未導出的函數(shù)維護不同的調(diào)用代碼,減少了系統(tǒng)維護的數(shù)據(jù)量,也提高了調(diào)用未導出的函數(shù)的靈活性和便捷性。
附圖說明
為了更清楚地說明本申請實施例或現(xiàn)有技術中的技術方案,下面將對實施例或現(xiàn)有技術描述中所需要使用的附圖作簡單地介紹,顯而易見地,下面描述中的附圖僅僅是本申請的實施例,對于本領域普通技術人員來講,在不付出創(chuàng)造性勞動的前提下,還可以根據(jù)提供的附圖獲得其他的附圖。
圖1為本申請實施例公開的函數(shù)調(diào)用系統(tǒng)的一種組成結構示意圖;
圖2為本申請實施例公開的函數(shù)調(diào)用方法的一種流程示意圖;
圖3為本申請實施例公開的函數(shù)調(diào)用方法的又一種流程示意圖;
圖4為在一種應用場景下,本申請實施例公開的函數(shù)調(diào)用方法的又一種流程示意圖;
圖5為一種節(jié)區(qū)頭的十六進制內(nèi)容的示意圖;
圖6為本申請實施例公開的函數(shù)調(diào)用裝置的一種組成結構示意圖;
圖7為本申請實施例公開的一種終端的結構示意圖。
具體實施方式
本申請可能使用的技術名詞、簡寫或縮寫如下:
動態(tài)鏈接庫:是一種不可直接執(zhí)行的二進制代碼程序文件,在使用時需要被其他可執(zhí)行文件加載后才能執(zhí)行其中的二進制代碼,其中的代碼以導出函數(shù)的形式被其他可執(zhí)行程序解析;
導出函數(shù):在動態(tài)鏈接庫中可以被其他模塊調(diào)用的函數(shù),如,對于linux操作系統(tǒng)中動態(tài)鏈接庫內(nèi)的導出函數(shù)是指,在動態(tài)鏈接庫的SHT_DYNSYM節(jié)中被申明函數(shù)的名字,在該節(jié)中出現(xiàn)的符號會在被加載的時候會被鏈接器解析,可以直接使用操作系統(tǒng)的接口直接調(diào)用解析該導出函數(shù),從而可以很方便地進行調(diào)用;
未導出的函數(shù),也稱為內(nèi)部函數(shù),是動態(tài)鏈接庫中不屬于導出函數(shù)的一類函數(shù),該類函數(shù)不能使用操作系統(tǒng)提供的接口直接調(diào)用;
dlopen:linux的系統(tǒng)調(diào)用之一,其可以實現(xiàn)將一個動態(tài)鏈接庫加載到當前程序地址空間中來,加載之后可以直接執(zhí)行動態(tài)鏈接庫中的代碼;
dlsym:linux系統(tǒng)調(diào)用之一,其可以獲取給定的導出函數(shù)的函數(shù)名在某一個動態(tài)鏈接庫中的地址;
基址:動態(tài)鏈接庫被加載到可執(zhí)行的二進制程序之后,該動態(tài)鏈接庫在該進程空間中第一個字節(jié)所處的內(nèi)存地址。
偏移地址:相對基址的一個地址差值,是一個無符號整數(shù)。
進程map文件:在Unix系列操作系統(tǒng)中,指的是文件/proc/[pid]/maps,其中[pid]表示進程自身的進程id,該文件中記錄了該進程加載的所有可執(zhí)行代碼模塊,每一條記錄包括加載的起始地址、結束地址、加載方式(讀/寫/執(zhí)行)和包含可執(zhí)行代碼模塊的絕對路徑;
ELF文件:是UNIX系統(tǒng)實驗室作為應用程序二進制接口(Application Binary Interface,ABI)而開發(fā)和發(fā)布的,也是Linux的主要可執(zhí)行文件格式;
ELFIO:一個ELF格式解析庫;
Unity游戲:使用優(yōu)美締軟件公司開發(fā)的游戲引擎Unity開發(fā)的游戲。
本申請的發(fā)明人通過對應用進行二次開發(fā)或測試的過程進行研究發(fā)現(xiàn):在對應用進行二次開發(fā)或測試的過程中,如果希望對應用中動態(tài)鏈接庫中的未導出的函數(shù)(以下簡稱未導出函數(shù))進行調(diào)用,就需要獲取到該未導出函數(shù)的函數(shù)指針,該函數(shù)指針可以理解為未導出函數(shù)在應用的內(nèi)存空間中運行的地址。
其中,該函數(shù)指針可以根據(jù)動態(tài)鏈接庫在該內(nèi)存空間中運行的基址,以及該未導出函數(shù)相對于該動態(tài)鏈接庫的偏移地址(即,相對于動態(tài)鏈接庫的基址的偏移地址)得到。而在動態(tài)鏈接庫維持不變化的情況下,在應用中加載該動態(tài)鏈接庫之后,該未導出函數(shù)相對于該動態(tài)鏈接庫的偏移地址也保持不變,因此,可以針對需要調(diào)用的未導出函數(shù)生成一套用于調(diào)用該未導出函數(shù)的調(diào)用代碼,該調(diào)用代碼中預置了未導出函數(shù)相對于該動態(tài)鏈接庫的偏移地址,以及用于基于該偏移地址,生成未導出函數(shù)的函數(shù)指針的指針生成函數(shù)。在對應用進行測試或二次開發(fā)之前,可以將該調(diào)用代碼注入到該應用的進程中,這樣,在對應用進行測試或者二次開發(fā)的過程中,如果需要調(diào)用應用中的該未導出函數(shù),則可以通過運行該調(diào)用代碼,獲取該調(diào)用代碼中預置的偏移地址,依據(jù)該偏移地址,并運行調(diào)用代碼中的指針生成函數(shù)便可以得到該未導出函數(shù)的函數(shù)指針。
發(fā)明人進一步研究發(fā)現(xiàn):由于調(diào)用代碼中預置的偏移地址是固定不變的,這樣,一旦該未導出函數(shù)的動態(tài)鏈接庫發(fā)生更新,應用在加載該動態(tài)鏈接庫之后,該未導出函數(shù)相對于該動態(tài)鏈接庫的偏移地址也會發(fā)生改變,因此,調(diào)用代碼中預置的偏移地址與該未導出函數(shù)實際對應的偏移地址不同,這樣,基于該調(diào)用代碼中預置的偏移地址所得到的函數(shù)指針也是錯誤的,導致無法基于確定出的函數(shù)指針對該未導出函數(shù)進行調(diào)用??梢?,在動態(tài)鏈接庫發(fā)生更新之后,為了實現(xiàn)對該動態(tài)鏈接庫中的該未導出函數(shù)進行調(diào)用,就需要相應的修改該調(diào)用代碼中預置的偏移地址,增加了開發(fā)或測試人員的工作量。
而且,由于一套調(diào)用代碼中固定寫入的是某個未導出函數(shù)對應的偏移地址,因此,一套調(diào)用代碼僅僅適用于一款應用內(nèi)的一個動態(tài)鏈接庫內(nèi)的一個未導出函數(shù)的調(diào)用,這樣,如果需要二次開發(fā)或測試的應用數(shù)量較多,或者應用中需要調(diào)用的未導出函數(shù)的數(shù)據(jù)較多時,就需要分別針對不同的應用、不同的動態(tài)鏈接庫以及不同的未導出函數(shù)分別維護相應的調(diào)用代碼,使得二次開發(fā)或測試系統(tǒng)中需要維護多套調(diào)用代碼,數(shù)據(jù)維護量較大,不利于靈活、便捷的實現(xiàn)對未導出函數(shù)的調(diào)用。
同時,當需要調(diào)用應用中的未導出函數(shù)時,需要預先從維護的多套調(diào)用代碼中篩選出與該應用中該未導出函數(shù)的調(diào)用代碼,然后才可以注入該調(diào)用代碼;而且,當需要調(diào)用多個未導出函數(shù)時,則需要注入多套相應的調(diào)用代碼,導致了調(diào)用未導出函數(shù)的復雜度高。
為了能夠?qū)崿F(xiàn)對未導出函數(shù)的調(diào)用,并且能夠?qū)崿F(xiàn)靈活、便捷的調(diào)用未導出函數(shù),本申請實施例提供了一種函數(shù)調(diào)用方法和裝置,本實施例的方案具有普遍適用性,可以適用于對任意應用進行二次開發(fā)或者進行性能等其他測試過程中,對應用的任意一款動態(tài)鏈接庫中的任意未導出函數(shù)的調(diào)用。本申請實施例的方案可以應用到任意終端中,如計算機等,該終端中可以運行有待被二次開發(fā)或測試的應用,以及用于對該待被測試或二次開發(fā)的應用進行監(jiān)控的監(jiān)控應用。
下面將結合本申請實施例中的附圖,對本申請實施例中的技術方案進行清楚、完整地描述,顯然,所描述的實施例僅僅是本申請一部分實施例,而不是全部的實施例?;诒旧暾堉械膶嵤├?,本領域普通技術人員在沒有做出創(chuàng)造性勞動前提下所獲得的所有其他實施例,都屬于本申請保護的范圍。
圖1為本申請?zhí)峁┑暮瘮?shù)調(diào)用系統(tǒng)的一種組成結構示意圖,圖1所示的函數(shù)調(diào)用系統(tǒng)可以實施本申請實施例提供的函數(shù)調(diào)用方法,參照圖1,本申請?zhí)峁┑暮瘮?shù)調(diào)用系統(tǒng)可以包括:
運行于終端101中,待被測試或二次開發(fā)的至少一個待處理應用102;
運行于終端101中,用于對待處理應用102的測試或二次開發(fā)過程進行監(jiān)控的控制應用103。
其中,該控制應用103中維護邏輯函數(shù)、偏移地址函數(shù)以及指針生成函數(shù),其中,邏輯函數(shù)用于實現(xiàn)對待處理的應用102進行測試或二次開發(fā),在該邏輯函數(shù)中包含了用于執(zhí)行二次開發(fā)或測試的相關程序代碼;該偏移地址函數(shù)用于獲取未導出函數(shù)相對于該未導出函數(shù)所在的動態(tài)鏈接庫的偏移地址;該指針生成函數(shù)用于基于該偏移地址函數(shù)獲取到的偏移地址,確定該未導出函數(shù)對應的函數(shù)指針。
該控制應用103用于在需要對所述待處理的應用進行測試或二次開發(fā)之前,將所述邏輯函數(shù)、偏移地址函數(shù)以及該指針生成函數(shù)注入到該待處理的應用102中。
該待處理應用102,用于運行被注入的邏輯函數(shù);在運行該邏輯函數(shù)的過程中,如果需要對動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,運行注入的偏移地址函數(shù),以分析出當前時刻該目標函數(shù)相對于該動態(tài)鏈接庫的目標偏移地址;依據(jù)該目標偏移地址,運行注入的指針生成函數(shù),以確定調(diào)用目標函數(shù)所需的函數(shù)指針。
基于圖1所示的函數(shù)調(diào)用系統(tǒng),下面從待被測試或二次開發(fā)的待處理應用角度對本申請實施例的函數(shù)調(diào)用方法進行介紹。參見圖2,其示出了本申請一種函數(shù)調(diào)用方法一個實施例的流程示意圖,本實施例的方法可以包括:
201,在應用中運行被注入的邏輯函數(shù)。
需要說明的是,在本實施例中所提到的應用均指待進行測試或二次開發(fā)的待處理應用,實際上僅僅與監(jiān)控應用進行區(qū)分,本申請中將待進行測試或二次開發(fā)的應用稱為待處理應用。
其中,該邏輯函數(shù)用于對該應用進行測試或二次開發(fā)??梢岳斫獾氖牵捎诖粶y試或開發(fā)的應用與該監(jiān)控應用之間具有獨立的內(nèi)存空間,監(jiān)控應用無法訪問該被測試或開發(fā)的應用對應的內(nèi)存空間,因此,需要通過向待測試或二次開發(fā)的應用中注入邏輯函數(shù),在應用中注入該邏輯函數(shù)之后,該應用會加載該邏輯函數(shù)以運行該邏輯函數(shù),實現(xiàn)對該應用進行相應的測試或二次開發(fā)。
其中,本申請實施例中,注入的實現(xiàn)方式也可以有多種,終端所采用的操作系統(tǒng)不同時,注入技術也會有所差別,如,當終端為windows操作系統(tǒng)時,可以采用遠程線程注入技術實現(xiàn)邏輯函數(shù)以及偏移地址函數(shù)等函數(shù)的注入,當然,對應其他操作系統(tǒng)而言,還可以有其他注入技術,在此不加以限定。
202,在運行該邏輯函數(shù)的過程中,如果需要對該應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,運行注入到該應用中且用于獲取函數(shù)偏移地址的偏移地址函數(shù),以分析出當前時刻所述目標函數(shù)相對于該動態(tài)鏈接庫的目標偏移地址。
其中,目標函數(shù)相對于動態(tài)鏈接庫的偏移地址可以理解為在該應用加載該動態(tài)鏈接庫之后,目標函數(shù)在應用內(nèi)存空間中運行的地址相對于該動態(tài)鏈接庫的基址的偏移地址。
其中,為了便于區(qū)分,將本申請實施例中需要調(diào)用的未導出的函數(shù)稱為目標函數(shù),并將該目標函數(shù)相對于該動態(tài)鏈接庫的偏移地址稱為目標偏移地址。
與直接注入固化的某個未導出函數(shù)對應的偏移地址不同,本申請實施例中,向該應用中注入了用于獲取未導出的函數(shù)對應的偏移地址的偏移地址函數(shù),在確定了需要調(diào)用的目標函數(shù)之后,通過運行該偏移地址函數(shù)可以實時分析出當前時刻該目標函數(shù)相對于動態(tài)鏈接庫的偏移地址??梢?,只要是需要調(diào)用的未導出的目標函數(shù)是確定出的,通過該偏移地址函數(shù)均可以分析出當前該目標函數(shù)相對于該目標函數(shù)所在的動態(tài)鏈接庫的偏移地址。
可選的,為了使得偏移地址函數(shù)在運行過程中可以明確需要調(diào)用的目標函數(shù),在應用運行注入的該偏移地址函數(shù)之前,還可以確定該動態(tài)鏈接庫的標識以及目標函數(shù)的標識,也就是說,應用需要確定運行該邏輯函數(shù)過程中所需調(diào)用的未導出的目標函數(shù)的標識,以及該目標函數(shù)所在的動態(tài)鏈接庫的標識。其中,此處所提到的標識可以為名稱,也可以為其他能夠唯一標識動態(tài)鏈接庫或目標函數(shù)的序號或者標號等等信息。相應的,可以依據(jù)該動態(tài)鏈接庫的標識和目標函數(shù)的標識,運行注入到應用中的該偏移地址函數(shù)。如,將該動態(tài)鏈接庫的標識和目標函數(shù)的標識作為偏移地址函數(shù)的輸入?yún)?shù),以在偏移地址函數(shù)的過程中,基于該動態(tài)鏈接庫的標識和目標函數(shù)的標識,分析該目標函數(shù)相對于該動態(tài)鏈接庫的偏移地址。
可以理解的是,能夠?qū)崿F(xiàn)分析出當前該目標函數(shù)相對于該目標函數(shù)所在的動態(tài)鏈接庫的偏移地址的偏移地址函數(shù)可以有多種可能,在一種可能的情況下,運行該偏移地址函數(shù),具體可以觸發(fā)執(zhí)行以下操作:
解析該操作系統(tǒng)中的內(nèi)存映射文件,以從該內(nèi)存映射文件中記錄的已加載動態(tài)鏈接庫的路徑信息中,確定出與該動態(tài)鏈接庫的標識對應的動態(tài)鏈接庫全路徑;
依據(jù)該目標函數(shù)的標識,從該動態(tài)鏈接庫全路徑中提取出該目標函數(shù)所屬的目標文件對應的路徑;
基于該目標文件對應的路徑,訪問并解析該目標文件,以確定出該目標函數(shù)相對于該動態(tài)鏈接庫的目標偏移地址。
其中,操作系統(tǒng)的內(nèi)存映射文件中記錄了應用中當前加載的所有動態(tài)鏈接庫的路徑信息,如,內(nèi)存映射文件中可以記錄有動態(tài)鏈接庫中每個文件加載的起始地址、結束地址、加載方式(如,讀/寫)以及動態(tài)鏈接庫的絕對路徑等。
該動態(tài)鏈接庫全路徑中包含了該應用加載該動態(tài)鏈接庫之后,在動態(tài)鏈接庫中所有函數(shù)所在文件各自對應的路徑信息,通過函數(shù)所在文件對應的路徑可以從該應用的內(nèi)存空間中定位出該函數(shù)所在文件。
通過在偏移地址函數(shù)中包括以上操作的代碼,可以在運行偏移地址函數(shù)的過程中執(zhí)行以上幾步操作,并最終確定出該目標函數(shù)相對于動態(tài)鏈接庫的偏移地址。
203,依據(jù)該目標偏移地址,運行注入到應用中的指針生成函數(shù),以確定調(diào)用該目標函數(shù)所需的函數(shù)指針。
運行該指針生成函數(shù)的過程中,可以基于該目標偏移地址,生成該目標函數(shù)所需的函數(shù)指針。
可以理解的是,一種較為常見的生成未導出的目標函數(shù)的函數(shù)指針的方式可以為將該目標函數(shù)相對于該動態(tài)鏈接庫的目標偏移地址,與該動態(tài)鏈接庫的基址相加,得到的值就是該目標函數(shù)運行在該應用的內(nèi)存空間中的地址(該地址為函數(shù)的首條代碼對應的起始地址),而該目標函數(shù)在該內(nèi)存空間中的地址就是該目標函數(shù)的函數(shù)指針。因此,在一種可能的實現(xiàn)方式中,該指針生成函數(shù)可以包括用于獲取動態(tài)鏈接庫基址的基址函數(shù),以及用于確定函數(shù)指針的指針確定函數(shù)。相應的,運行該指針生成函數(shù)具體可以包括執(zhí)行以下操作:
運行該基址函數(shù),以獲取該動態(tài)鏈接庫的基址;
基于該目標偏移地址以及該動態(tài)鏈接庫的基址,運行該指針確定函數(shù),以確定該目標函數(shù)的函數(shù)指針。
其中,該基址函數(shù)包括用于獲取動態(tài)鏈接庫的基址的函數(shù)代碼。
可選的,可以依據(jù)該動態(tài)鏈接庫的標識,運行該基址函數(shù),以獲取到該動態(tài)鏈接庫的基址。
需要說明的是,運行該基址函數(shù)的操作可以是在確定出目標偏移地址之后執(zhí)行,也可以是在運行偏移地址函數(shù)的同時,運行該基址函數(shù);當然,也可以是在運行該偏移地址函數(shù)之前運行該基址函數(shù)。
可見,在本申請實施例中,在應用運行該邏輯函數(shù)的過程中,如果需要對應用中的某個動態(tài)鏈接庫中未導出的某個函數(shù)進行調(diào)用時,可以通過運行注入到應用中的該偏移地址函數(shù),實時動態(tài)的分析出當前時刻該未導出的函數(shù)相對于該動態(tài)鏈接庫的目標偏移地址,從而基于確定出的目標偏移地址以及注入到應用中的指針生成函數(shù),便可以得到調(diào)用該未導出的函數(shù)所需的函數(shù)指針,實現(xiàn)對該未導出的函數(shù)的靈活調(diào)用。
而且,由于偏移地址函數(shù)具有普遍適用性,對于任意一款需要進行測試或二次開發(fā)的應用而言,在向應用中注入該偏移地址函數(shù)之后,在需要調(diào)用該應用的動態(tài)鏈接庫中的任意未導出的函數(shù)時,均可以通過運行該偏移地址函數(shù)分析出該未導出的函數(shù)相對于該動態(tài)鏈接庫的偏移地址,并結合指針生成函數(shù)得到調(diào)用未導出的函數(shù)所需的函數(shù)指針,這樣,二次開發(fā)或測試系統(tǒng)只需要維護一套偏移地址函數(shù)以及該指針生成函數(shù),便可以實現(xiàn)對任意應用中任意未導出的函數(shù)的調(diào)用,避免了針對不同應用的不同未導出的函數(shù)維護不同的調(diào)用代碼,減少了系統(tǒng)維護的數(shù)據(jù)量,也提高了調(diào)用未導出的函數(shù)的靈活性和便捷性。
可以理解的是,在本申請實施例中,用于確定目標函數(shù)對應的函數(shù)指針所需的偏移地址函數(shù)以及指針生成函數(shù)可以分別注入到該應用中。
考慮到偏移地址函數(shù)以及指針生成函數(shù)需要相互配合才可以最終確定出該目標函數(shù)對應的函數(shù)指針,因此,為了便于實現(xiàn)函數(shù)注入,并有利于應用的調(diào)用,可以將用于確定未導出的函數(shù)所對應的函數(shù)指針所需的函數(shù)代碼均封裝到一個接口函數(shù)中,即該接口函數(shù)中可以封裝有偏移地址函數(shù)以及該指針生成函數(shù),這樣,應用需要確定目標函數(shù)對應的函數(shù)指針時,可以直接調(diào)用并運行該接口函數(shù),以運行該接口函數(shù)中封裝的各個函數(shù)所對應的函數(shù)代碼。相對應的,控制應用可以直接將該接口函數(shù)注入到該應用的進程中,如果應用調(diào)用該接口函數(shù),則會觸發(fā)運行該接口函數(shù)中封裝的偏移地址函數(shù)以及該接口函數(shù)中封裝的該指針生成函數(shù),這樣,在運行指針生成函數(shù)的過程中,基于運行偏移地址函數(shù)所得到的目標偏移地址,便可以最終得到目標函數(shù)對應的函數(shù)指針。
下面以通過接口函數(shù)封裝用于確定未導出的函數(shù)對應的函數(shù)指針的所有函數(shù)代碼為例進行介紹。結合圖1所述的函數(shù)調(diào)用系統(tǒng),對本申請實施例的函數(shù)調(diào)用方法進行介紹。參見圖3,其示出了本申請一種函數(shù)調(diào)用方法又一個實施例的流程交互示意圖,本實施例的方法可以包括:
301,監(jiān)控應用向待被測試或二次開發(fā)的待處理應用中注入邏輯函數(shù)和接口函數(shù)。
其中,該邏輯函數(shù)用于對該待處理應用進行測試或二次開發(fā)。該接口函數(shù)用于確定待處理應用的動態(tài)鏈接庫中未導出的函數(shù)的函數(shù)指針。
302,待處理應用運行該邏輯函數(shù)。
向待處理應用中注入該邏輯函數(shù)和接口函數(shù)之后,待處理應用可以加載并運行該邏輯函數(shù)和接口函數(shù)。
303,在待處理應用運行該邏輯函數(shù)的過程中,如果邏輯函數(shù)需要對該應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,確定該目標函數(shù)的名稱以及該動態(tài)鏈接庫的名稱。
其中,該目標函數(shù)的名稱也就是目標函數(shù)的函數(shù)名。該目標函數(shù)的名稱和動態(tài)鏈接庫的名稱可以預置在邏輯函數(shù)中,邏輯函數(shù)需要調(diào)用某個未導出的目標函數(shù)時,可以提供該目標函數(shù)的名稱以及動態(tài)鏈接庫的名稱。
可以理解的是,本實施例以目標函數(shù)和動態(tài)鏈接庫的標識為名稱為例進行介紹,但是當標識為其他情況,也同樣適用于本實施例。
304,待處理應用調(diào)用并運行該接口函數(shù),以執(zhí)行以下步驟305至311的操作。
305,待處理應用根據(jù)動態(tài)鏈接庫的名稱,加載該動態(tài)鏈接庫并獲取該動態(tài)鏈接庫的窗口句柄。
需要說明的是,加載該動態(tài)鏈接庫為可選操作,當待處理應用當前已經(jīng)加載了該動態(tài)鏈接庫的情況下,則無需再加載該動態(tài)鏈接庫。
其中,加載該動態(tài)鏈接庫并獲取動態(tài)鏈接庫的窗口句柄可以通過調(diào)用操作系統(tǒng)中用于打開動態(tài)鏈接庫并返回動態(tài)鏈接庫窗口句柄的庫函數(shù)來實現(xiàn)。當然,對于不同的操作系統(tǒng)而言,該庫函數(shù)會有所區(qū)別,如,當操作系統(tǒng)為linux系統(tǒng)時,可以通過dlopen這一函數(shù)來加載動態(tài)鏈接庫并返回動態(tài)鏈接庫的窗口句柄。
306,待處理應用基于該窗口句柄所對應的結構體指針,查詢該結構體指針所指向的結構體;
307,待處理應用從該結構體中解析出動態(tài)鏈接庫的基址。
如,仍以linux系統(tǒng)為例,Linux中,sysinfo是用來獲取系統(tǒng)相關信息的結構體,而dlopen函數(shù)所返回的窗口句柄是一個整數(shù),該窗口句柄的數(shù)值也就是soinifo結構體對應的結構體指針,基于該soinifo的指針可以查詢該soinifo結構體,在該soinifo結構體中存儲該動態(tài)鏈接庫的名字,該動態(tài)鏈接庫的基址等字段,從而可以通過該soinifo結構體中獲取到該動態(tài)鏈接庫的基址。
例如,soinifo結構體的部分定義可以如下:
其中,soinfo結構體中的name字段為動態(tài)鏈接庫的名字,而動態(tài)鏈接庫加載的基址存儲在base字段中。
需要說明的是,執(zhí)行以上步驟305至307所需的代碼相當于前面實施例提到了基址函數(shù)所對應的代碼,而步驟305至307的執(zhí)行過程相當于運行該基址函數(shù)所執(zhí)行的操作步驟。
308,待處理應用通過解析該操作系統(tǒng)中的內(nèi)存映射文件,從該內(nèi)存映射文件中記錄的已加載動態(tài)鏈接庫的路徑信息中,確定出與該動態(tài)鏈接庫的名稱對應的動態(tài)鏈接庫的全路徑。
可以理解的是,動態(tài)鏈接庫的全路徑中包含了該動態(tài)鏈接庫的名稱,因此,根據(jù)該動態(tài)鏈接庫的名稱,可以從該內(nèi)存映射文件中查詢出該動態(tài)鏈接庫所對應的全路徑。
仍以linux系統(tǒng)為例,內(nèi)存映射信息可以存儲在/proc/self/maps文件中,通過遍歷該map文件,可以得到加載的該動態(tài)鏈接庫在本地的全路徑。
309,待處理應用依據(jù)該目標函數(shù)的名稱,從動態(tài)鏈接庫全路徑中提取出該目標函數(shù)所屬的目標文件對應的路徑。
310,待處理應用基于該目標文件對應的路徑,訪問并解析該目標文件,以確定出該目標函數(shù)相對于該動態(tài)鏈接庫的目標偏移地址。
在確定出目標函數(shù)所屬的目標文件之后,可以對該目標文件進行解析,以確定該目標文件中存儲偏移地址的區(qū)域,從而定位出該目標函數(shù)相對于動態(tài)鏈接庫的目標偏移地址。
當然,當操作系統(tǒng)不同時,解析該目標文件獲取該目標函數(shù)相對于該目標偏移地址的具體過程也會有所差異。如,仍以linux系統(tǒng)為例,基于該linux系統(tǒng)的動態(tài)鏈接庫以及可執(zhí)行文件均為ELF文件,該ELF文件會有ELF頭,ELF頭中描繪了整個文件的組織結構。該EFL頭中還包括很多節(jié)(section),在確定出目標文件之后,可以獲取該目標文件對應的EFL頭中節(jié)的個數(shù),遍歷所有的節(jié),在定位到SHT_SYMTAB節(jié)之后遍歷所有的符號名稱,與該目標函數(shù)的名稱進行比較,如果定位該目標函數(shù),就將該目標函數(shù)的偏移地址提取出來。
可以理解的是,執(zhí)行以上步驟308至310所需的代碼相當于前面實施例提到了偏移地址函數(shù)所對應的代碼,而步驟308至310的執(zhí)行過程相當于運行該偏移地址函數(shù)所執(zhí)行的相關操作步驟。
需要說明的是,偏移地址函數(shù)與基址函數(shù)的運行前后順序并不限于圖3所示,因此,也可以是在執(zhí)行了步驟308至310之后,在執(zhí)行該步驟305至307,當然,也可以是在執(zhí)行該步驟305至307的同時,執(zhí)行該步驟308至310。
311,待處理應用依據(jù)該目標偏移地址和動態(tài)鏈接庫的基址,確定該目標函數(shù)的函數(shù)指針。
具體的,可以將動態(tài)鏈接庫的基址加上該目標偏移地址,得到該目標函數(shù)運行在應用的內(nèi)存空間中的地址,即得到該函數(shù)指針。
其中,該步驟311相當于運行前面提到的指針確定函數(shù)所執(zhí)行的操作。
312,待處理應用在運行邏輯函數(shù)的過程中,基于該目標函數(shù)的函數(shù)指針,調(diào)用該目標函數(shù)。
其中,該步驟312為可選步驟。
可見,由于本申請的接口函數(shù)具有普遍適用性,對于任意一款需要進行測試或二次開發(fā)的應用而言,在向應用中注入該接口函數(shù)之后,在需要調(diào)用該應用的動態(tài)鏈接庫中的任意未導出的函數(shù)時,依據(jù)該未導出的函數(shù)的名稱,通過調(diào)用并運行該接口函數(shù),便可以分析出該未導出的函數(shù)相對于該動態(tài)鏈接庫的偏移地址,并結合運行該接口函數(shù)所分析出的動態(tài)鏈接庫的基址,可以得到該未導出的函數(shù)所需的函數(shù)指針,這樣,二次開發(fā)或測試系統(tǒng)只需要維護一套接口函數(shù)以及需要調(diào)用的函數(shù)的函數(shù)名,便可以實現(xiàn)對任意應用中任意未導出的函數(shù)的調(diào)用,避免了針對不同應用的不同未導出的函數(shù)維護不同的調(diào)用代碼,減少了系統(tǒng)維護的數(shù)據(jù)量,也提高了調(diào)用未導出的函數(shù)的靈活性和便捷性。
可以理解的是,本申請實施例的方案適用于對任意操作系統(tǒng)下的動態(tài)鏈接庫中未導出函數(shù)的調(diào)用。
為了便于理解本申請實施例的方案的具體實現(xiàn)過程,下面以linux操作系統(tǒng)為例,對本申請實施例的函數(shù)調(diào)用方法進行介紹。結合圖1,參見圖4,其示出了本申請一種函數(shù)調(diào)用方法在一種應用場景下的流程交互示意圖,本實施例的方法可以包括:
401,監(jiān)控應用向待被測試或二次開發(fā)的待處理應用中注入邏輯函數(shù)和接口函數(shù)。
其中,該邏輯函數(shù)用于對該待處理應用進行測試或二次開發(fā)。該接口函數(shù)用于確定待處理應用的動態(tài)鏈接庫中未導出的函數(shù)的函數(shù)指針。
402,待處理應用運行該邏輯函數(shù)。
403,在待處理應用運行該邏輯函數(shù)的過程中,如果需要對該應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,確定該目標函數(shù)的名稱以及該動態(tài)鏈接庫的名稱。
可以理解的是,本實施例以目標函數(shù)和動態(tài)鏈接庫的標識為名稱為例進行介紹,但是當標識為其他情況,也同樣適用于本實施例。
404,待處理應用調(diào)用并運行該接口函數(shù),以執(zhí)行以下步驟405至415的操作。
405,待處理應用根據(jù)動態(tài)鏈接庫的名稱,利用dlopen函數(shù)加載該動態(tài)鏈接庫并獲取該動態(tài)鏈接庫的窗口句柄。
其中,dlopen為linux操作系統(tǒng)中的一種調(diào)用函數(shù)。
406,待處理應用基于該窗口句柄所對應的sysinfo結構體指針,查詢該sysinfo結構體指針所指向的sysinfo結構體。
407,待處理應用對該sysinfo結構體進行解析,從該sysinfo結構體的base字段中獲取動態(tài)鏈接庫的基址。
408,待處理應用通過解析該操作系統(tǒng)中的map文件,從該map文件中記錄的已加載動態(tài)鏈接庫的路徑信息中,確定出與該動態(tài)鏈接庫的名稱對應的動態(tài)鏈接庫全路徑。
409,待處理應用依據(jù)該目標函數(shù)的名稱,從動態(tài)鏈接庫全路徑中提取出該目標函數(shù)所屬的目標文件對應的路徑。
410,待處理應用基于該目標文件對應的路徑,訪問該目標文件的ELF頭。
411,待處理應用依據(jù)該目標函數(shù)的名稱,從該ELF頭確定包含該目標函數(shù)對應符號的節(jié)區(qū)符號表。
412,待處理應用依據(jù)該節(jié)區(qū)符號表中目標函數(shù)所對應的符號,從該EFL頭的節(jié)區(qū)頭部表中定位出.symtab節(jié)和.strtab節(jié)。
413,待處理應用遍歷該.symtab節(jié),查詢出該.symtab節(jié)中的sh_name在該.strtab節(jié)中的索引值為目標函數(shù)的符號項。
414,待處理應用依據(jù)查詢出的sh_name,在該.symtab節(jié)中查找該目標函數(shù)對應的目標偏移地址。
為了便于理解該步驟410至步驟414,下面結合具體實例進行介紹:
首先讀取ELF文件頭,在該ElF文件的結構體中,本方案僅關注三個字段:e_shoff,它的含義是節(jié)區(qū)頭部表在文件中的偏移;第二個是e_shentsize,它的含義是每個節(jié)區(qū)頭部的大??;第三個是e_shstrndx,它的含義是節(jié)符號表頭在節(jié)區(qū)頭部的索引號。假設e_shoff對應的值是0xbf4b88,e_shentsize對應的值是0x28,e_shstrndx對應的值是0x1a,由此計算出節(jié)符號表頭在文件中的偏移是0xbf4b88+0x28*0x1a=0xbf4f98。
其中,該偏移0xbf4f98處對應的是一個節(jié)區(qū)表頭的結構,在該節(jié)區(qū)表頭中,本方案所關鍵的同樣有三個字段:第一個是sh_name,它的含義是該節(jié)區(qū)的名字在節(jié)符號表中的偏移;第二個是sh_offset,它的含義是這個節(jié)區(qū)在文件中的偏移;第三個是sh_size,它的含義是這個節(jié)的大小。
查詢目標文件在該0xbf4f98處的節(jié)符號表頭的數(shù)據(jù),假設得到節(jié)符號表頭的名字sh_name索引號為0x11,在文件中的偏移sh_offset是0xbf4a6c,其大小sh_size為0x11b。
查詢目標文件在0xbf4a6c處的數(shù)據(jù),假設得到:偏移0x11處所對應的字符串為shstrtab,即節(jié)符號表本身的名字是shstrtab。至此,節(jié)符號表已經(jīng)找到。
基于該節(jié)符號表可以用來確定接下來找的節(jié)區(qū)的名字:從上面確定出的節(jié)表頭位置開始一個個遍歷節(jié)區(qū)頭,找到sh_type的屬性為SHT_SYMTAB的節(jié)區(qū)頭,假設經(jīng)過查找,發(fā)現(xiàn)有一個sh_type字段為2的節(jié)區(qū)頭,并假設該節(jié)區(qū)頭的十六進制內(nèi)容如圖5所示。
查看節(jié)符號表的數(shù)據(jù),在節(jié)符號表索引為1的位置表示的符號為”.symtab”,也就是說該節(jié)表示的頭就是symtab節(jié)。假設由symtab節(jié)頭可知,.symtab節(jié)的真實位置為文件偏移0xbf5010處,并查看0xbf5010處的數(shù)據(jù),其中,.symtab節(jié)的每一項數(shù)據(jù)都對應著一個符號結構,其中,字段sh_name為符號表中的索引,以遍歷節(jié)區(qū)頭表的方式查找到”.strtab”節(jié)的起始地址,假設該起始地址為0xdd0df0。
然后,遍歷.symtab節(jié),找到該節(jié)中符號名字為_Z13getNumCamerasv的項,假設該項的字符索引為0xb90f7,將該字符索引加上.strtab的0xdd0df0基址,得到0xe89ee7,假設查看目標文件0xe89ee7處的數(shù)據(jù)為_Z13getNumCamerasv,則該數(shù)據(jù)正是我們要找的符號。根據(jù).symtab節(jié)的每一項數(shù)據(jù)對應的符號結構,可以得到符號_Z13getNumCamerasv的偏移。
415,將目標偏移地址和動態(tài)鏈接庫的基址相加,得到該目標函數(shù)的函數(shù)指針。
416,待處理應用在運行邏輯函數(shù)的過程中,基于該目標函數(shù)的函數(shù)指針,調(diào)用該目標函數(shù)。
其中,該步驟416為可選步驟。
下面對本發(fā)明實施例提供的一種函數(shù)調(diào)用裝置進行介紹,下文描述的一種函數(shù)調(diào)用裝置可與上文描述的一種函數(shù)調(diào)用方法相互對應參照。
參見圖6,其示出了本申請一種函數(shù)調(diào)用裝置一個實施例的結構示意圖,本實施例的裝置可以包括:
第一函數(shù)運行單元601,用于在應用中運行被注入的邏輯函數(shù),所述邏輯函數(shù)用于對所述應用進行測試或二次開發(fā);
第二函數(shù)運行單元602,用于在運行所述邏輯函數(shù)的過程中,如果需要對所述應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,運行注入到所述應用中且用于獲取函數(shù)偏移地址的偏移地址函數(shù),以分析出當前時刻所述目標函數(shù)相對于所述動態(tài)鏈接庫的目標偏移地址;
指針生成單元603,用于依據(jù)所述目標偏移地址,運行注入到所述應用中的指針生成函數(shù),以確定調(diào)用所述目標函數(shù)所需的函數(shù)指針。
可選的,所述第二函數(shù)運行包括:
標識獲取單元,用于在運行所述邏輯函數(shù)的過程中,如果需要對所述應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,確定所述動態(tài)鏈接庫的標識以及所述目標函數(shù)的標識;
地址獲取單元,用于依據(jù)所述動態(tài)鏈接庫的標識和所述目標函數(shù)的標識,運行注入到所述應用中且用于獲取函數(shù)偏移地址的偏移地址函數(shù),以分析出所述以分析出當前時刻所述目標函數(shù)相對于所述動態(tài)鏈接庫的目標偏移地址。
可選的,所述地址獲取單元,包括:
全路徑解析單元,用于解析所述操作系統(tǒng)中的內(nèi)存映射文件,以從所述內(nèi)存映射文件中記錄的已加載動態(tài)鏈接庫的路徑信息中,確定出與所述動態(tài)鏈接庫的標識對應的動態(tài)鏈接庫全路徑;
文件路徑提取單元,用于依據(jù)所述目標函數(shù)的標識,從所述動態(tài)鏈接庫全路徑中提取出所述目標函數(shù)所屬的目標文件對應的路徑;
地址獲取子單元,用于基于所述目標文件對應的路徑,訪問并解析所述目標文件,以確定出所述目標函數(shù)相對于所述動態(tài)鏈接庫的目標偏移地址。
可選的,所述指針生成單元所運行的所述指針生成函數(shù)包括:用于獲取動態(tài)鏈接庫基址的基址函數(shù)以及用于確定函數(shù)指針的指針確定函數(shù);
所述指針生成單元,包括:
第三函數(shù)運行單元,用于運行所述基址函數(shù),以獲取所述動態(tài)鏈接庫的基址;
第四函數(shù)運行單元,用于基于所述目標偏移地址以及所述動態(tài)鏈接庫的基址,運行所述指針確定函數(shù),以確定所述目標函數(shù)的函數(shù)指針。
可選的,所述第一函數(shù)運行單元,具體為:用于在運行所述邏輯函數(shù)的過程中,如果需要對所述應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,調(diào)用注入到所述應用中的接口函數(shù),并運行所述接口函數(shù)中封裝的所述偏移地址函數(shù);
所述指針生成單元具體為,用于依據(jù)所述目標偏移地址,運行所述接口函數(shù)中封裝的指針生成函數(shù)。
本申請實施例還提供了一種終端,該終端可以實現(xiàn)上述所述的一種函數(shù)調(diào)用方法。
圖7示出了終端的硬件結構框圖,參照圖7,終端700可以包括:處理器701,通信接口702,存儲器703和通信總線704;
其中處理器701、通信接口702、存儲器703通過通信總線704完成相互間的通信;
可選的,通信接口702可以為通信模塊的接口,如GSM模塊的接口;
處理器701,用于執(zhí)行程序;
存儲器703,用于存放程序;
程序可以包括程序代碼,所述程序代碼包括計算機操作指令。
處理器701可能是一個中央處理器CPU,或者是特定集成電路ASIC(Application Specific Integrated Circuit),或者是被配置成實施本發(fā)明實施例的一個或多個集成電路。
存儲器703可能包含高速RAM存儲器,也可能還包括非易失性存儲器(non-volatile memory),例如至少一個磁盤存儲器。
其中,程序可具體用于:
在應用中運行被注入的邏輯函數(shù),所述邏輯函數(shù)用于對所述應用進行測試或二次開發(fā);
在運行所述邏輯函數(shù)的過程中,如果需要對所述應用的動態(tài)鏈接庫中未導出的目標函數(shù)進行調(diào)用時,運行注入到所述應用中且用于獲取函數(shù)偏移地址的偏移地址函數(shù),以分析出當前時刻所述目標函數(shù)相對于所述動態(tài)鏈接庫的目標偏移地址;
依據(jù)所述目標偏移地址,運行注入到所述應用中的指針生成函數(shù),以確定調(diào)用所述目標函數(shù)所需的函數(shù)指針。
需要說明的是,本說明書中的各個實施例均采用遞進的方式描述,每個實施例重點說明的都是與其他實施例的不同之處,各個實施例之間相同相似的部分互相參見即可。對于裝置類實施例而言,由于其與方法實施例基本相似,所以描述的比較簡單,相關之處參見方法實施例的部分說明即可。
最后,還需要說明的是,在本文中,諸如第一和第二等之類的關系術語僅僅用來將一個實體或者操作與另一個實體或操作區(qū)分開來,而不一定要求或者暗示這些實體或操作之間存在任何這種實際的關系或者順序。而且,術語“包括”、“包含”或者其任何其他變體意在涵蓋非排他性的包含,從而使得包括一系列要素的過程、方法、物品或者設備不僅包括那些要素,而且還包括沒有明確列出的其他要素,或者是還包括為這種過程、方法、物品或者設備所固有的要素。在沒有更多限制的情況下,由語句“包括一個……”限定的要素,并不排除在包括要素的過程、方法、物品或者設備中還存在另外的相同要素。
對所公開的實施例的上述說明,使本領域技術人員能夠?qū)崿F(xiàn)或使用本發(fā)明。對這些實施例的多種修改對本領域技術人員來說將是顯而易見的,本文中所定義的一般原理可以在不脫離本發(fā)明的精神或范圍的情況下,在其它實施例中實現(xiàn)。因此,本發(fā)明將不會被限制于本文所示的這些實施例,而是要符合與本文所公開的原理和新穎特點相一致的最寬的范圍。
以上僅是本發(fā)明的優(yōu)選實施方式,應當指出,對于本技術領域的普通技術人員來說,在不脫離本發(fā)明原理的前提下,還可以做出若干改進和潤飾,這些改進和潤飾也應視為本發(fā)明的保護范圍。