Android-so加載流程剖析

前言:由于逆向需要知識的全面性,這次我們來剖析一下so的加載流程惠奸;從java->c梅誓;廢話不多說,開始佛南。

一梗掰、JAVA層(這里我的target是28為例)

1、調(diào)用方式:System.loadLibrary();

System.loadLibrary("xxxx");

2嗅回、點進去

image.png
//類加載器 和 so名字
  Runtime.getRuntime().loadLibrary0(classLoader,libName);

這里發(fā)現(xiàn)哈及穗,他是在runtime的時候才會獲取,要理解Runtime绵载,運行時埂陆。

3苛白、runtime層代碼:

代碼不多我直接全部貼上了,注意一下里面帶有中文注釋的地方焚虱,為個人理解部分和重點部分丸氛。

//同步方法。加載肯定是有先后順序著摔,類似隊列形式
 synchronized void loadLibrary0(ClassLoader loader, String libname) {
        if (libname.indexOf((int)File.separatorChar) != -1) {
            throw new UnsatisfiedLinkError(
    "Directory separator should not appear in library name: " + libname);
        }
        String libraryName = libname;
        if (loader != null) {
          //尋找這個文件是不是存在。 不存在的話返回null定续,直接拋異常
            String filename = loader.findLibrary(libraryName);
            if (filename == null) {
                // It's not necessarily true that the ClassLoader used
                // System.mapLibraryName, but the default setup does, and it's
                // misleading to say we didn't find "libMyLibrary.so" when we
                // actually searched for "liblibMyLibrary.so.so".
                throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
                                               System.mapLibraryName(libraryName) + "\"");
            }
            //文件存在谍咆,就交給下一層處理,這里如果返回的內(nèi)容不是null就說明加載失敗了私股,且含有錯誤信息摹察。
          //所以這里是重點!3ā9┖俊!  下一步我們就看這里
            String error = nativeLoad(filename, loader);
            if (error != null) {
                throw new UnsatisfiedLinkError(error);
            }
            return;
        }

        String filename = System.mapLibraryName(libraryName);
        List<String> candidates = new ArrayList<String>();
        String lastError = null;
        for (String directory : getLibPaths()) {
            String candidate = directory + filename;
            candidates.add(candidate);

            if (IoUtils.canOpenReadOnly(candidate)) {
                String error = nativeLoad(candidate, loader);
                if (error == null) {
                    return; // We successfully loaded the library. Job done.
                }
                lastError = error;
            }
        }

        if (lastError != null) {
            throw new UnsatisfiedLinkError(lastError);
        }
        throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
    }

4峭状、nativeLoad();

這里就直接native層了克滴,
private static native String nativeLoad(String filename, ClassLoader loader);

二、Native層(這里我使用的是:http://androidxref.com/

1优床、sdk28對應(yīng)的是 android9.0劝赔,所以這里要選擇一樣的版本,因為版本之間可能會有差異胆敞。

image.png

2着帽、源碼中,so層也會對應(yīng)有一個Runtime移层,注意關(guān)鍵詞

image.png

3仍翰、溯源1

這里注意下,動態(tài)加載观话。


image.png

4予借、溯源2

因為是native層,我們選這個


image.png

其實有人可能已經(jīng)發(fā)現(xiàn)了匪燕,這個.h不是頭文件嗎檐束?為什么要看頭文件呢? 這里特別提醒一下畜疾,我們要看非頭文件囊榜,因為頭文件是一種約束存在。
所以我們選擇:OpenjdkJvm.cc

5尼变、溯源3

image.png

6利凑、溯源4

這個方法比較長浆劲,這里分幾塊來看。(純個人理解哀澈,有誤歡迎指出)

6.1 -溯源4.1

我們的目的就是把這個so文件加載到內(nèi)存中牌借,那么肯定要圍繞這個文件做事情。還是老方法割按,捕捉關(guān)鍵字膨报。


image.png
6.2 -溯源4.2

看看下面圍繞這個 library做了什么事情。


image.png

這里又圍繞著他們得到了一個handle

6.3 -溯源4.3
image.png

這里我有個小疑問适荣,就是當(dāng)sym==nullptr 的時候他直接返回success现柠,這里是因為首次加載的時候,JNI_OnLoad 函數(shù)是首次執(zhí)行弛矛,所以他首次加載够吩。如果加載過了,他就要找到加載過他的classloader丈氓,并且拿到相關(guān)信息驗證周循,信息無誤之后才返回success。

7万俗、溯源5

這里要說的湾笛,在6部分,大致流程梳理完了闰歪。需要回頭來看一個比較重要的函數(shù)迄本,就是在 6.2里面提到的handle,handle是通過調(diào)用了一個 OpenNativeLibrary课竣,接下來在7部分嘉赎,來著重分析這個模塊的流程。
搜索他于樟,只有一個公条。


image.png
7.1 -溯源5.1
image.png

這里,只簡單看一下兩部分迂曲,一部分是classloader為空的靶橱,就是說首次加載,否則需要通過之前加載過的classLoader拿到相關(guān)信息返回路捧。
我們還是著重分析1关霸,dlopen() 函數(shù)

7.2 -溯源5.2
image.png

這里我們選擇的是bionic目錄下的 dlopen,是因為在 bionic目錄下都屬于android的內(nèi)核源碼杰扫,是比較關(guān)鍵的地方队寇。

7.3 -溯源5.3
image.png

又跳到__loader_dlopen()


image.png

繼續(xù)追,注意關(guān)鍵函數(shù)章姓,do_dlopen()


image.png
7.4 -溯源5.4

這里要注意特征佳遣,四個參數(shù)识埋。


image.png

繼續(xù)


image.png

劃重點,這里有個結(jié)構(gòu)體零渐,soinfo窒舟,這樣看沒有感覺,如果換成java的駝峰表示就一目了然了:soInfo诵盼,顧名思義惠豺,so的信息。
中間代碼都是判斷一些信息是不是null的環(huán)節(jié)风宁,這里代碼就不貼了耕腾,我們直接來看一下結(jié)尾返回的什么,然后追溯返回的東西的來歷杀糯。


image.png

相同點部分,標(biāo)記出來苍苞。
劃重點->
1固翰、 si是 find_library 返回的結(jié)構(gòu)體,也就是這個 library的一系列信息羹呵。
2骂际、handle = si->to_handle(); 將si的句柄返回。
什么是句柄? 它實際上是作為一個索引在一個表中查找對應(yīng)的內(nèi)核對象的實際地址冈欢。你可以理解為一個對象在內(nèi)存中的位置歉铝。 這句話出自:https://blog.csdn.net/qq_31511955/article/details/90763661
3、si->call_constructors(); 本人英語不好凑耻,翻譯一下:調(diào)用構(gòu)造函數(shù)太示。

image.png

8、溯源6

在上面的一系列函數(shù)中香浩,這一條調(diào)用鏈似乎是完成了类缤。這里先來小小的總結(jié)一下。
1邻吭、調(diào)用java層loadLirbrary
2餐弱、然后交給so層調(diào)用 nativeLoadLibrary
3、然后給vm(虛擬機)調(diào)用加載
4囱晴、然后我們需要根據(jù)路徑打開這個library膏蚓,并且返回這個library的句柄。

只要下層返回的信息無誤畸写,上面一層函數(shù)都會正常執(zhí)行驮瞧。so加載到內(nèi)存之后的地址不會變,所以只要圍繞著他的地址做操作就可以了枯芬。
這里還要深究一下si->call_constructors()剧董, 看看他的構(gòu)造函數(shù)里做了什么幢尚,這一步也比較關(guān)鍵,這樣一來整個流程就貫穿下來了翅楼。

9尉剩、溯源7

si->call_constructors()


image.png

1、代碼結(jié)合注釋內(nèi)容翻譯結(jié)果毅臊,這一段的含義是說:全局不允許頻繁調(diào)用這個構(gòu)造方法理茎,也就是這個so只能被初始化一次,且它在內(nèi)存中的地址是不會變的管嬉。 類似于java中的單例皂林。
2、如果這個so沒有被加載過蚯撩,那就調(diào)用DT_INIT 和 DT_INIT_ARRAY础倍, 類似于初始化方法。具體操作要看開發(fā)者是怎么寫的胎挎。 可以類似理解為:Application 的 attachBaseContext() 方法沟启,只有程序第一次進入的時候才會走。

10犹菇、溯源總結(jié)

整個流程走完之后德迹,腦瓜里清晰不少,最后用自己的理解來總結(jié)出一張大致流程圖奉上揭芍,有誤歡迎指出胳搞。


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市称杨,隨后出現(xiàn)的幾起案子肌毅,更是在濱河造成了極大的恐慌,老刑警劉巖姑原,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芽腾,死亡現(xiàn)場離奇詭異,居然都是意外死亡页衙,警方通過查閱死者的電腦和手機摊滔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來店乐,“玉大人艰躺,你說我怎么就攤上這事≌0耍” “怎么了腺兴?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長廉侧。 經(jīng)常有香客問我页响,道長篓足,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任闰蚕,我火速辦了婚禮栈拖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘没陡。我一直安慰自己涩哟,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布盼玄。 她就那樣靜靜地躺著贴彼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埃儿。 梳的紋絲不亂的頭發(fā)上器仗,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音童番,去河邊找鬼精钮。 笑死,一個胖子當(dāng)著我的面吹牛妓盲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播专普,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼悯衬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了檀夹?” 一聲冷哼從身側(cè)響起筋粗,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎炸渡,沒想到半個月后娜亿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蚌堵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年买决,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吼畏。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡督赤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泻蚊,到底是詐尸還是另有隱情躲舌,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布性雄,位于F島的核電站没卸,受9級特大地震影響羹奉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜约计,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一诀拭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧病蛉,春花似錦炫加、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至魄健,卻和暖如春赋铝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沽瘦。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工革骨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人析恋。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓良哲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親助隧。 傳聞我的和親對象是個殘疾皇子筑凫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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