日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

进击的Android Hook 注入术《三》

發(fā)布時(shí)間:2025/3/15 Android 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进击的Android Hook 注入术《三》 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄(?)[-]

  • 繼續(xù)
  • Component Injection
  • 原理
  • 示例二
  • comdemohost
  • comdemoinject
  • 繞過ClassLoader雙親委托
  • 輸出
  • 最后
  • 繼續(xù)

    在《二》詳細(xì)介紹了通過ptrace實(shí)現(xiàn)注入的技術(shù)方案,在這個(gè)章節(jié)里,我再介紹一種Android上特有的注入技術(shù),我命其名為——Component Injection。顧名思義,這種方式是跟Android的組件相關(guān)的,詳細(xì)見下面敘述。

    Component Injection

    原理

    在android的開發(fā)者文檔里,對(duì)android:process的描述是這樣的:
    android:process
    The name of a process where all components of the application should run. Each component can override this default by setting its own?process?attribute.By default, Android creates a process for an application when the first of its components needs to run. All components then run in that process. The name of the default process matches the package name set by the?<manifest>?element.
    By setting this attribute to a process name that's shared with another application, you can arrange for components of both applications to run in the same process — but only if the two applications also share a user ID and be signed with the same certificate.
    If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed. If the process name begins with a lowercase character, a global process of that name is created. A global process can be shared with other applications, reducing resource usage.

    從描述上可以發(fā)現(xiàn),當(dāng)兩個(gè)應(yīng)用,它們簽名同樣且具備相同的shareduserID,它們之間只有一個(gè)組件的android:process是相同的,那么這兩個(gè)組件之間的互動(dòng)可以發(fā)生在同一個(gè)進(jìn)程里。這里所說的同一個(gè)進(jìn)程,其實(shí)就是進(jìn)程注入的效果的了。

    示例二

    示例二同樣包含兩部分代碼,分別是com.demo.host和com.demo.inject,它們的代碼都非常簡(jiǎn)單,如下所示:

    com.demo.host

    先看看host的manifest.xml的配置 [html] view plain copy
  • <manifest?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????package="com.demo.host"??
  • ????android:sharedUserId="com.demo"??
  • ????android:versionCode="1"??
  • ????android:versionName="1.0"?>??
  • ??
  • ????<application??
  • ????????android:name=".DemoApplication"??
  • ????????android:allowBackup="true"??
  • ????????android:icon="@drawable/ic_launcher"??
  • ????????android:label="@string/app_name"??
  • ????????android:process="com.demo"??
  • ????????android:theme="@style/AppTheme"?>??
  • ????????<activity?android:name=".MainActivity"?>??
  • ????????????<intent-filter>??
  • ????????????????<action?android:name="android.intent.action.MAIN"?/>??
  • ??
  • ????????????????<category?android:name="android.intent.category.LAUNCHER"?/>??
  • ????????????</intent-filter>??
  • ????????</activity>??
  • ????</application>??
  • ??
  • ????<uses-sdk??
  • ????????android:minSdkVersion="8"??
  • ????????android:targetSdkVersion="9"?/>??
  • ??
  • </manifest>??
  • 關(guān)鍵代碼 [java] view plain copy
  • package?com.demo.host;??
  • ??
  • import?android.app.Activity;??
  • import?android.content.ContentResolver;??
  • import?android.net.Uri;??
  • import?android.os.Bundle;??
  • import?android.util.Log;??
  • ??
  • /**?
  • ?*??
  • ?*?@author?boyliang?
  • ?*??
  • ?*/??
  • public?final?class?MainActivity?extends?Activity?{??
  • ????private?static?int?sA?=?1;??
  • ??
  • ????public?static?void?setA(int?a)?{??
  • ????????sA?=?a;??
  • ????}??
  • ??
  • ????public?static?int?getA()?{??
  • ????????return?sA;??
  • ????}??
  • ??
  • ????@Override??
  • ????protected?void?onCreate(Bundle?savedInstanceState)?{??
  • ????????super.onCreate(savedInstanceState);??
  • ??
  • ????????ContentResolver?resolver?=?getContentResolver();??
  • ????????Uri?uri?=?Uri.parse("content://demo_contentprovider");??
  • ????????resolver.query(uri,?null,?null,?null,?null);??
  • ??
  • ????????new?Thread()?{??
  • ??
  • ????????????public?void?run()?{??
  • ????????????????while?(true)?{??
  • ????????????????????Log.i("TTT",?""?+?getA());??
  • ????????????????????setA(getA()?+?1);??
  • ??
  • ????????????????????try?{??
  • ????????????????????????Thread.sleep(1000);??
  • ????????????????????}?catch?(InterruptedException?e)?{??
  • ????????????????????????e.printStackTrace();??
  • ????????????????????}??
  • ????????????????}??
  • ????????????};??
  • ??
  • ????????}.start();??
  • ????}??
  • }??
  • host一啟動(dòng),就馬上調(diào)用ContentResolver的query,這個(gè)正是Inject里的ContentProvider組件。

    com.demo.inject

    manifest.xml [html] view plain copy
  • <manifest?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????package="com.demo.inject"??
  • ????android:sharedUserId="com.demo"??
  • ????android:versionCode="1"??
  • ????android:versionName="1.0"?>??
  • ??
  • ????<application??
  • ????????android:allowBackup="true"??
  • ????????android:icon="@drawable/ic_launcher"??
  • ????????android:label="@string/app_name"??
  • ????????android:process="com.demo"??
  • ????????android:theme="@style/AppTheme"?>??
  • ??????????
  • ????????<provider??
  • ????????????android:name=".DemoContentProvider"??
  • ????????????android:authorities="demo_contentprovider"??
  • ????????????android:exported="false"?/>??
  • ??????????
  • ????</application>??
  • ??????
  • ????<uses-sdk??
  • ????????android:minSdkVersion="8"??
  • ????????android:targetSdkVersion="9"?/>??
  • ??
  • </manifest>??
  • 關(guān)鍵代碼 [java] view plain copy
  • <span?style="white-space:pre">????</span>@Override??
  • ????public?Cursor?query(Uri?arg0,?String[]?arg1,?String?arg2,?String[]?arg3,?String?arg4)?{??
  • ??
  • ????????final?Timer?timer?=?new?Timer("demo");??
  • ????????timer.schedule(new?TimerTask()?{??
  • ??
  • ????????????@Override??
  • ????????????public?void?run()?{??
  • ????????????????try?{??
  • ????????????????????Log.i("TTT",?">>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy!!!!<<<<<<<<<<<<<<\n");??
  • ????????????????????//Class<?>?MainActivity_class?=?Class.forName("com.demo.host.MainActivity");??
  • ????????????????????Context?context?=?ContexHunter.getContext();??
  • ????????????????????ClassLoader?classloader?=?context.getClass().getClassLoader();??
  • ????????????????????Class<?>?MainActivity_class?=?classloader.loadClass("com.demo.host.MainActivity");??
  • ????????????????????Method?setA_method?=?MainActivity_class.getDeclaredMethod("setA",?int.class);??
  • ????????????????????setA_method.invoke(null,?998);??
  • ????????????????}?catch?(Exception?e)?{??
  • ????????????????????e.printStackTrace();??
  • ????????????????}??
  • ??
  • ????????????????timer.cancel();??
  • ????????????}??
  • ??
  • ????????},?5000);??
  • ??????????
  • ????????return?null;??
  • ????}??
  • inject中,當(dāng)query被調(diào)用后,會(huì)等待5s,然后通過反射調(diào)用host的MainActivity.setA方法,修改打印的數(shù)值。

    繞過ClassLoader雙親委托

    細(xì)心的朋友會(huì)發(fā)現(xiàn),inject的代碼中,獲取MainActivity的Class,并不是直接通過Class.forName("com.demo.host.MainActivity")獲取到,而是先獲取到全局Context(即Application對(duì)象),然后再調(diào)用其ClassLoader來間接獲取得的,為什么要這樣呢?我我們知道,Java中每個(gè)class都是通過雙親委托機(jī)制加載的,這方面的內(nèi)容可以參考http://blog.csdn.net/xyang81/article/details/7292380,下面我畫出示意圖:


    當(dāng)我們嘗試在DemoContentProvider通過Class.forNmae尋找MainActivity時(shí),必然會(huì)拋ClassNotFoundException。唯一可行的方案是找到host的PathClassLoader,然后通過這個(gè)ClassLoader尋找MainActivity。我們需要尋找的變量需要滿足如下條件:
    • 這個(gè)變量必須由host產(chǎn)生的;
    • 這個(gè)變量必須是全局的,而且其引用會(huì)保存在BootClassLoader(也就是Android SDK中的某個(gè)引用);
    • 可以通過反射機(jī)制讀取到;
    很自然的,想到了host的Application對(duì)象。通過閱讀源碼,發(fā)現(xiàn)可以通過下面的方式讀取到Application對(duì)象:
    • 如果是System_Process,可以通過如下方式獲取
    [java] view plain copy
  • Context?context?=?ActivityThread.mSystemContext??
    • 如果是非System_Process(即普通的Android進(jìn)程),可以通過如下方式獲取
    [java] view plain copy
  • Context?context?=?((ApplicationThread)RuntimeInit.getApplicationObject()).app_obj.this$0??
  • 輸出

    理解了上述的原理之后,我們?cè)倏纯词纠妮敵? [plain] view plain copy
  • I/TTT?????(??633):?com.demo.inject?starts.??
  • I/TTT?????(??633):?com.demo.host?starts??
  • I/TTT?????(??633):?1??
  • I/TTT?????(??633):?2??
  • I/TTT?????(??633):?3??
  • I/TTT?????(??633):?4??
  • I/TTT?????(??633):?5??
  • I/TTT?????(??633):?>>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy!!!!<<<<<<<<<<<<<<??
  • I/TTT?????(??633):?998??
  • I/TTT?????(??633):?999??
  • I/TTT?????(??633):?1000??
  • I/TTT?????(??633):?1001??
  • I/TTT?????(??633):?1002??
  • I/TTT?????(??633):?1003??
  • 從前二行就可以看出,這兩個(gè)組件都是運(yùn)行在同一個(gè)進(jìn)程的。從第5秒開始,打印的數(shù)據(jù)開始發(fā)生變化,證明我們的注入邏輯生效了。 文中的示例代碼,大家可以到https://github.com/boyliang/Component_Injection下載

    最后

    ComponentInjection的好處是不需要ROOT權(quán)限,但其使用限制也非常多。但如果跟MaskterKey漏洞結(jié)合起來用,那效果還是相當(dāng)驚艷的。我們知道,Zygote進(jìn)程會(huì)接收來自system_process的命令,其中比較關(guān)鍵的信息有uid, gid, gids, classpath, runtime-init等等,這些信息是決定了Zygote子進(jìn)程的加載容器以及所從屬的uid。
    通過MasterKey漏洞我們可以偽造系統(tǒng)的Setting包,Setting與system_process的配置正好符合我所說的ComponentInjection條件,因此利用這種方式,可以注入到system_process進(jìn)程,進(jìn)而控制傳遞給Zygote的參數(shù)。其中classpath和runtime-init是加載容器的配置,classpath是指向一個(gè)dex文件的路徑,runtime-init是其main函數(shù)所在的類名,通過指定每個(gè)App的加載容器,就可以很巧妙的控制了所有普通用戶的進(jìn)程的環(huán)境。
    LBE 曾經(jīng)就是利用這種技術(shù)實(shí)現(xiàn)主動(dòng)防御的,更詳細(xì)的介紹可訪問http://safe.baidu.com/2013-10/lbe-root.html,不過這個(gè)文章分析得并不到位,最關(guān)鍵的環(huán)節(jié)即ComponentInjection并沒有提及,結(jié)合的我分享,算是做一個(gè)完美的補(bǔ)充吧。
    這一章節(jié)里,介紹了一種Android特有的注入技術(shù),通過一些小技巧繞過了Java的雙父委托機(jī)制。而且找到了可以輕松找到Application對(duì)象的方法,這個(gè)對(duì)象在Android開發(fā)中可以是至關(guān)重要的。在接下來的《四》里,我會(huì)詳細(xì)介紹如何利用JNI獲取JNIEnv指針,再通過JNI找到DexCloassLoader加載DEX文件。



    原文地址:http://blog.csdn.net/l173864930/article/details/38459449

    總結(jié)

    以上是生活随笔為你收集整理的进击的Android Hook 注入术《三》的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。