Xposed框架是一款可以在不修改APK的情況下影響程序運行(修改系統)的框架服務,可謂喜歡搗鼓的人的必備神器。而且使用上也極為簡單,下面我就來看看如何在Android Studio上開發xposed模塊。
環境設置就不再贅述了,需要以下前提準備工作。
電腦端 | 手機端 |
---|---|
Android studio | root |
Android sdk | 安裝了xposed installer |
XposedBridgeApi jar包 | 已安裝并激活xposed框架 |
一、創建xposed模塊
1、新建Android工程
其實就是一路next,選擇Empty Activity,創建工程完成后等待gradle加載完畢。
2、導入XposedBridgeApi jar包
導入完成后,修改下app/build.gradle中的依賴聲明。將XposedBridgeApi的依賴由implementation改成provided。改完后記得sync一下gradle。
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
provided files('lib/XposedBridgeApi-54.jar')
}
3、修改AndroidManifest
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="這里填寫xposde說明" />
<meta-data
android:name="xposedminversion"
android:value="54" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
xposedmodule: 表示這是一個xposed模塊
xposeddescription: 描述該模塊的用途,可以引用string.xml中的字符串
xposedminversion:要求支持的Xposed Framework最低版本
4、模塊實現
創建一個或者幾個類,并實現IXposedHookLoadPackage,IXposedHookZygoteInit或者其他IXposedMod的子接口。
package de.robv.android.xposed.mods.tutorial;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import android.util.Log;
public class TestDemo implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Loaded app: " + lpparam.packageName);
Log.d("YOUR_TAG", "Loaded app: " + lpparam.packageName )
}
}
XposedBridge.log會將日志輸出到logcat,并寫入日志文件
也可以用 android.util.Log輸出到logcat。
5、聲明xposed入口
我們需要新建一個assets文件夾,并創建文件xposed_init,在里面填上xposed模塊的入口.
這里我們聲明自己的類“com.johnhao.testdemo.TestDemo”
到這里,這個簡單的模塊就算開發完了。雖然沒有界面,沒有任何實際的功能,但這也是一個確確實實的xposed模塊。可以被安裝到設備上,也可以被xposed installer檢測到。
二、實踐技巧
前面只是簡單的搭出了框子,并沒有任何實際功能,接下來我們往里添加一些內容。
技巧1:檢測模塊是否啟動
如果你使用過xposed插件,那么一定有概率碰上模塊未啟動的情況,即便是你已經勾選激活該模塊。那么有沒有什么方法來分辨模塊是否真的啟動了呢?當然有,而且很簡單。原理就是:
在MainActivity實現一個boolean方法,然后用xposed hook自己Activity里的函數。能hook成功,自然代表模塊成功啟動了,反之亦然。
// MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!isModuleActive()){
Toast.makeText(this, "模塊未啟動", LENGTH_LONG).show();
}
else {
Toast.makeText(this, "模塊已啟動", LENGTH_LONG).show();
}
}
private boolean isModuleActive(){
return false;
}
hook自己
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
// Xposed模塊自檢測
if (loadPackageParam.packageName.equals("your.package.name")){
XposedHelpers.findAndHookMethod("your.package.name.MainActivity", loadPackageParam.classLoader, "isModuleActive", XC_MethodReplacement.returnConstant(true));
}
}
這樣,如果模塊成功激活,就會在啟動app的時候彈一個模塊已啟動的toast,如果沒有啟動則會彈模塊未啟動的toast。
技巧2:hook帶殼應用
隨著人們安全意識越來越高,很多應用開發者都選擇給應用加殼來保護自己。從最開始簡單的dex加密到現在的onCreate函數虛擬化技術,逆向的難度也越來越高。如何脫殼和修復onCreate函數不是本文的所要講的內容。
這里以去年某款答題app為例子講解,我們期望獲得答題的題目和選項。
拿到app反編譯,明顯發現使用了某廠商的加密技術。第一步是脫殼,然后拿到smali后開始分析(這里我們不去修復onCreate方法)。
我們通過socket中的關鍵詞showQuestion字段,最終在Lcom/chongdingdahui/app/socket/MessageManager$7類里面發現了處理數據的代碼。
找到了關鍵的方法,接下來便是如何hook帶殼的應用。如果直接hook的話,會發現找不到目標class,所以我們這里可以采用四哥的方法。
// 應用被加殼,采用這種方式加載類
try {
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
context = (Context) param.args[0];
ClassLoader loader = context.getClassLoader();
// 獲取題目和答案
try {
Class clazz = loader.loadClass("com.chongdingdahui.app.socket.MessageManager$7");
if (clazz != null){
XposedHelpers.findAndHookMethod(clazz, "call", Object[].class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Object[] obj = (Object[]) param.args[0];
String content = obj[0].toString();
Log.d(TAG, content);
question = Util.getQuestion(content);
answers = Util.getAnswer(content);
}
});
}
}catch (Exception e){
Log.e(TAG, "socket.MessageManager$7 clazz not found" + Log.getStackTraceString(e));
}
這樣就能得到題目和答案了。因為目前答題類應用早已規范化了,所以展示的代碼僅供方法參考,并不能實際應用,但原理都是一樣的。
感興趣的話可以在我的微信公眾號回復xposed,獲取以上樣例的源碼。看到這兒,伙伴們有沒有get到新技能呢?