天天看點

Android逆向分析之Xposed的hook技術

Android逆向工程裡常用到的工具除了的dex2jar,jd-gui,  Apktool之外還有一個Xposed。

這個工具是一個在不修改APK的情況下,影響其運作過程的服務架構。可以根據自己的需求編寫子產品,讓子產品控制目标應用的運作。

因為本人也是新手,對于Xposed用法還有很多的不熟悉,是以隻對其hook技術進行簡單的介紹,并讓hook技術應用到以後的逆向分析工程中。

至于什麼是hook,不了解的話就先去百度一下,這裡基于菜鳥有限的經驗,我隻能說是一種函數攔截技術~

首先,下載下傳Xposed架構,我這裡就不提供下載下傳了,然後手機必須得先root,不然是無法安裝Xposed架構的,畢竟hook技術已經是個系統級的過程,是以你懂的~

Android逆向分析之Xposed的hook技術

這隻是一個架構而已,并沒有什麼功能,為了實作個人需求,我們還需要自己編寫子產品,讓這個架構去加載你的子產品。

舉個栗子,你要去知道手機某個應用包中的某個類中的某個方法中的某個參數,那麼你的子產品就要指明那個包,哪個類,哪個方法,當系統重新開機時加載目标應用包時,加載了你的子產品的Xposed架構會識别到,接下來,如果你指明的應用中的某一方法被系統執行了,那麼Xposed也會識别到,然後讓你的子產品去Hook(顧名思義,就是就是鈎子,陷阱的意思;也可以說是攔截)這個方法,并可以利用子產品的接口讓方法的參數和傳回結果暴露出來。

在本次的部落格中,隻是結合例子簡單的介紹Xposed的hook,實際上Xposed的功能貌似不止于此~

架構弄好了,接下來就可以根據需求編寫子產品了,不過,再此之前先明确一下需求,我們可以用一個簡單的登入系統APP進行測試。

先貼個簡單的代碼出來先:

public class LoginActivity extends Activity {

    private final String ACCOUNT="samuel";
    private final String PASSWORD="123456";
    private EditText etAccount, etPassword;
    private Button btnLogin;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        etAccount=(EditText)findViewById(R.id.et_account);

        etPassword=(EditText)findViewById(R.id.et_password);

        btnLogin=(Button)findViewById(R.id.btn_login);

        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isOK(etAccount.getText().toString(), etPassword.getText().toString())) {
                    Toast.makeText(LoginActivity.this, "登入成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(LoginActivity.this, "登入失敗", Toast.LENGTH_SHORT).show();
                }

            }
        });

    }

    private boolean isOK(String account, String password){
        return account.equals(ACCOUNT) && password.equals(PASSWORD);
    }
           

很簡單的一個登入頁面,其中的關鍵函數isOk(String, String)是用來驗證賬号密碼是否正确的,其中我已定死為賬号:samuel,密碼:123456,也就是說我必須輸入以上兩個字元串,才能完成驗證。

那麼,重點就來了,我們就可以利用Xposed的子產品hook到isOK(String, String)這個函數,并攔截到賬号和密碼,甚至可以修改賬号和密碼!!!

So,需求明确了,那麼我們就可以針對性編寫子產品了。

編寫子產品步驟:

1、先建立一個Android Project,這個工程不需要界面,是以在工程建立導向時不需要添加MainActivity和layout_main.xml,就一個Empty工程即可;

2、在空工程的java檔案夾中建立一個類,該類就是一個子產品類,這裡命名為“Module”,接下來就要配置一下AndaroidManfest.xml和添加xposed_init檔案,如下圖;

Android逆向分析之Xposed的hook技術

3、配置AndroidManifest.xml,其中的meta-data内容要照搬,反正我之前沒照搬說明上的demo,結果出錯了,是以那三個meta-data最好是照着寫。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.samuelzhan.xposehook">

    <application android:allowBackup="true" android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher" android:theme="@style/AppTheme">

        <meta-data
            android:name="xposedmodule"
            android:value="true"/>

        <meta-data
            android:name="xposeddescription"
            android:value="Hook Test!"/>

        <meta-data
            android:name="xposedminversion"
            android:value="54"/>
    </application>

</manifest>
           

4、在main檔案夾下建立一個assets檔案夾,并在裡面建立一個普通的檔案,命名為“xposed_init”,然後打開檔案,在裡面添加一句字元串,即   包名+子產品類名。

Android逆向分析之Xposed的hook技術

5、建立一個檔案夾,命名為“lib”或者“jar”,然後放進一個XposedBridgeApi.jar包,如上圖,并在該jar包上右鍵Add as Library。這裡必須注意兩點細節,一是,放jar包的檔案夾名字一定是“lib”或“jar”,親測放到“libs”裡沒用;二是,需要在build.gradle裡的dependencies将compile改為provided,不然會報錯。聽說是系統裡已有該jar包内容,再次打包進去會沖突,是以改為provided,不要管那條紅色波浪線,無礙~

Android逆向分析之Xposed的hook技術

6、編寫子產品類Module:

public class Module implements IXposedHookLoadPackage {

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (loadPackageParam.packageName.equals("com.samuelzhan.logintest")) {

            XposedHelpers.findAndHookMethod("com.samuelzhan.logintest.LoginActivity",
                    loadPackageParam.classLoader,
                    "isOK",
                    String.class,
                    String.class,
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {

                        }

                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        }
                    });

        }
    }

}
           

說明:

Module繼承了IXposedHookLoadPackage接口,當系統加載應用包的時候回回調 handleLoadPackage;

XposedHelpers的靜态方法 findAndHookMethod就是hook函數的的方法,其參數對應為   類名+loadPackageParam.classLoader(照寫)+方法名+參數類型(根據所hook方法的參數的類型,即有多少個寫多少個,加上.class)+XC_MethodHook回調接口;

這裡的第一個參數類名必須要有包名字首,即“packageName+className”,還有一點,如果代碼被混淆過,即使你明知道代碼中要hook的類名和方法名,但都不一定能用,必須以smali中的名字為準,比如:isOk()混淆之後在smali中的函數名為a,那麼hook的時候就必須寫a,而不是isOK,第一個參數類名同理!

參數裡有一個監聽類XC_MethodHook,該類在hook前後回調,通過回調方法的MethodHookParam可以攔截到函數參數。

Xposed除了hook目标應用的函數之外,還可以hook某些類的構造方法,對應的方法為XposedHelpers.findAndHookConstructor()。

至此,一個子產品基本已完成,接下來将其打包 Build->Generate Signed APK...生成一個APK,并安裝在手機上。因為沒有MainActivity,是以安裝後不會彈出任何界面,但若果此時手機已安裝了Xposed,那麼Xposed會在消息欄彈一個消息,通知你“子產品已更新”,此時可以選擇Xposed菜單中的 “架構”->"軟重新開機",重新開機手機(軟重新開機不會斷電,相當于電腦的重新開機,比硬重新開機要快)。

Android逆向分析之Xposed的hook技術
Android逆向分析之Xposed的hook技術

到這裡,已經可以hook函數了。

現在,試着去攔截isOK(String, String)函數中的賬号密碼,先在回調函數中添加日記列印代碼将其賬号密碼參數暴露出來,順便把傳回結果也顯示一下:

new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            XposedBridge.log("賬号:"+(String)param.args[0]+"   密碼:"+(String)param.args[1]);
                            Log.d("zz","賬号:"+(String)param.args[0]+"   密碼:"+(String)param.args[1]);
                        }

                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            Log.d("zz", param.getResult().toString());
                        }
                    });
           

我在beforeHookedMethod中寫了兩種方法日志,第一個是XposedBridge的靜态log,這個日志會顯示在Xposed的日志選項裡,個人不喜歡這種方法,因為每次運作你要hook的程式,又必須切換頁面到Xposed檢視日志,太麻煩了,但它有個優點,相比Android中的Log.d(), 它能顯示抛出的異常,而Android Log不可以。第二個Android Log就不用說了,這裡我兩種都用了。

編寫完後,我們重新打包這個子產品,并安裝到手機上,然後讓手機軟重新開機,每次更新安裝子產品都必須得重新開機才生效。

好,重新開機後,我們運作一下目标應用,輸入賬号密碼~

Android逆向分析之Xposed的hook技術

然後看看Android Studio中的Logcat和 Xposed中的日志選項:

Android逆向分析之Xposed的hook技術
Android逆向分析之Xposed的hook技術

可以看到,兩者都可以看到攔截到的密碼賬号。因為正确的賬号密碼為samuel  123456,這裡隻是随便輸入zzz   aaa,是以傳回的結果是false,當然也在回調函數afterHookedMethod中可以捕獲得到,這裡顯示false,說明登陸驗證失敗。

除了能讀取參數之外,hook技術還可以修改函數參數。

比如,接下來我修改子產品,讓其無論輸入什麼,我都實作登陸,那我先在hook中把賬号密碼修改成samuel  123456,也就是說,通過hook技術,我怎樣輸入都能成功登陸。

new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            //修改參數
                            param.args[0]="samuel";
                            param.args[1]="123456";
                        }

                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            Log.d("zz", param.getResult().toString());
                        }
                    });
           

然後重新打包,安裝,重新開機手機,再次運作登陸頁面的程式,再次輸入zzz   aaa看看:

Android逆向分析之Xposed的hook技術

不錯,顯示登陸成功,說明修改參數成功。

其實Xposed貌似還有其他更強大的功能,這裡隻用了冰山一角進行逆向分析而已~