1. 程式人生 > >6、XPOSED二、叉叉助手框架--用XPOSED實現

6、XPOSED二、叉叉助手框架--用XPOSED實現

繼《xposed框架初探》之後,編寫一個小小的demo應用,剛好之前分析叉叉的遊戲輔助框架(參考《叉叉助手逆向分析續集--模擬實現遊戲外掛框架--再擴充套件到脫殼機》,我們是用了libsubstrate的hook框架來完成的),這次就用XPOSED實現一下。 相關參考: 看雪論壇《XPOSED的小筆記,文章介紹的很詳細很清晰。 準備工作: 上一篇中我們用的是“華為專用Xposed框架”,也並不是很完美,於是還是從官網上下載穩定版本的,這個要視不同手機而定。 http://repo.xposed.info/module/de.robv.android.xposed.installer,點下面的“Show older versions”逐個版本安裝試用,每個版本都要啟用一次並重啟手機,還是挺麻煩的,好在試到2.5.1版本的時候成功了!這個版本確實比
華為專用Xposed框架”要穩定完美許多,果斷換用2.5.1官方版本。 實現思路: 實現介面IXposedHookLoadPackage的介面函式handleLoadPackage,判斷引數包名是否是目標APK,若是則呼叫findAndHookMethod對目標啟動類的onCreate函式進行HOOK,在afterHookedMethod函式中動態載入外掛,將引數中有關activity的例項傳給外掛。 一個 XposedModule 本質上是設定了部分特殊元資料標誌位的普通應用程式,需要在 AndroidManifest.xml 檔案中新增如下設定:  AndroidManifest.xml => Application => Application Nodes (at the bottom) => Add => Meta Data 新增節點:name = xposedmodule,value = true。name = xposedminiversion, value = API level。
<
application android:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name" android:theme="@style/AppTheme"android:name=".MainApplication"> <!-- Xposed --> <meta-dataandroid:name="xposedmodule" android:value="true" /> <meta-dataandroid:name="xposedminversion"
 android:value="42+" /> <meta-data android:name="xposeddescription"android:value="GameAssistant" />
 <activityandroid:name="com.netease.ga.view.MainActivity"android:theme="@android:style/Theme.NoTitleBar.Fullscreen"><intent-filter> <actionandroid:name="android.intent.action.MAIN" /> <categoryandroid:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activityandroid:name=".view.MyGamesActivity"android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/><activity android:name=".view.PluginsActivity" /> <activityandroid:name=".view.MoreActivity" /> <receiverandroid:name=".receiver.MyReceiver" /> </application>
新增標記的作用估計是讓XPOSED安裝器識別為外掛。 新增庫檔案:XposedBridgeApi.jar 需要注意的是這個jar包不能放到工程的libs目錄,否則執行會出現異常。最好是放到工程主目錄下,然後在eclipse裡右鍵選擇該jar-Build Path => Add to Build Path。 注意這個jar包版本選擇,經測試XposedBridgeApi-54.jar在2.5.1版本的xposedinstaller下是相容的,但是最新版的靠譜助手(2.5.1143)上預設整合安裝了2.6.1版本的xposedinstaller,測試發現XposedBridgeApi-54.jar並不是很穩定,後來改用XposedBridgeApi-42.jar是可以的。

Next, make the XposedBridge API known to the project. You can downloadXposedBridgeApi-<version>.jarfrom the first post ofthis XDA thread. Copy it into a subfolder calledlib. Then right-click on it and select Build Path => Add to Build Path. The<version>from the file name is the one you insert asxposedminversionin the manifest.

Make sure that the API classes are not included (but only referenced) in your compiled APK, otherwise you will get an IllegalAccessError. Files in thelibs (with "s") folder are automatically included by Eclipse, so don't put the API file there.

這個設定對應到androidstudio的操作步驟: F4開啟工程結構,選擇Modules-當前專案-Dependencies-+-選擇“Jar or directiories”, 選擇jar包後,在“Scope”欄選擇“Provided”,不要選擇“Complie”。 然後宣告一個類XposedXXHook實現介面IXposedHookLoadPackage 在 assets 目錄下新建一個 xposed_init 檔案,這個檔案聲明瞭需要載入到 XposedInstaller 的入口類:com.netease.ga.XposedXXHook 由於改動不大,因此直接在原來的GA工程(基於libsubstrate的叉叉遊戲輔助框架)上新增。 完善XposedXXHook的程式碼:
package com.netease.ga; import android.app.Activity; import android.content.Context;import android.content.SharedPreferences; import android.os.Build; importandroid.os.Bundle; import android.util.Log; import java.lang.reflect.Method; importdalvik.system.DexClassLoader; import de.robv.android.xposed.IXposedHookLoadPackage;import de.robv.android.xposed.XC_MethodHook; importde.robv.android.xposed.callbacks.XC_LoadPackage; import staticde.robv.android.xposed.XposedHelpers.findAndHookMethod; import staticde.robv.android.xposed.XposedHelpers.findClass; /** * Created by sing on 14-9-17. * desc: */ public class XposedXXHook implements IXposedHookLoadPackage { private staticfinal String TAG = "XposedXXHook"private static final String TARGET_PACKAGE = "com.example.helloapplication"private static final String TARGET_CLASS = "com.example.helloapplication.MainActivity"private static final String TARGET_FUNCTION = "onCreate"//private SharedPreferences sp; /** * * @param param *@throws Throwable */ @Override public voidhandleLoadPackage(XC_LoadPackage.LoadPackageParam param) throws Throwable { String packageName = param.packageName; Log.d(TAG, "handleLoadPackage: " + packageName); if(packageName.equals(TARGET_PACKAGE) == false) { return; } Log.d(TAG,"handleLoadPackage: star hook"); XC_MethodHook.Unhook unhook = findAndHookMethod(TARGET_CLASS, param.classLoader, TARGET_FUNCTION, Bundle.classnewXC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param)throws Throwable { Log.d(TAG, "[handleLoadPackage]beforeHookedMethod"); } @Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable { Log.d(TAG,"[handleLoadPackage]afterHookedMethod: " + param.thisObject.toString()); String plugApkPath = "/data/data/com.netease.ga/app_plugin/lianmengplug.apk"; String plugSoPath = "/data/data/com.netease.ga/app_plugin/libxxlianmeng_mm.so"; String dexOutputDir = "/data/data/" + TARGET_PACKAGE + "/cache"; ClassLoader localClassLoader = ClassLoader.getSystemClassLoader(); DexClassLoader localDexClassLoader new DexClassLoader(plugApkPath, dexOutputDir, null, localClassLoader); java.lang.Class<?> plugClass = localDexClassLoader.loadClass("com.xxAssistant.UI.UniversalUI"); Method mInit = plugClass.getDeclaredMethod("init", Activity.class, String.class); mInit.invoke(null, param.thisObject, plugSoPath); } }); if (unhook!=null) { Log.d(TAG,"handleLoadPackage: hook ok"); }else{ Log.d(TAG, "handleLoadPackage: hook failed"); } } }
注意這段程式碼只HOOK包名為com.example.helloapplication的應用程式,如果要HOOK其他應用程式則把包名過濾的判斷去掉,並動態解析應用程式的主啟動類即可。 編譯安裝好後在xposed安裝器的模組中啟用GA並重啟手機。 啟動手機後不用執行xposed安裝器和GA,直接執行helloapplication程式: 可以看出外掛已經被我們成功載入了。 常見錯誤: 09-17 07:58:42.049: I/Xposed(2447): java.lang.NoSuchMethodError: com.example.helloapplication.MainActivity#onCreate()#exact 錯誤為未找到對應的函式,在hook的時候需要指定函式的引數形式。
findAndHookMethod(TARGET_CLASS, param.classLoader, TARGET_FUNCTION, newXC_MethodHook(){...});
因為onCreate是有引數的,所以正確的呼叫方式是:
findAndHookMethod(TARGET_CLASS, param.classLoader, TARGET_FUNCTION, Bundle.classnewXC_MethodHook(){...});

xposed與libsubstrate的對比: 測試都需要經過反覆的重啟,此次xposed的測試demo也是如是,即便寫的只是java層程式碼,也需要每次改動都要重啟手機。而之前用libsubstrate實現的底層hook,在每次改動JNI程式碼後也是需要重啟手機的。 程式碼量方面還是xposed框架下少很多,而且都是java層程式碼,寫起來速度也快不容易出錯,測試的時間自然也少很多。