一、起因:
最近想實現模擬定位功能。目的是周遊列國而不搞簽證。然而,最開始使用的是android開發者模擬定位的方式,結果微信壓根不鳥我。不過當時髮型釘釘倒是可行。可惜的是,後來釘釘升級了版本後直接把打開這個做了限制。這種方法的模擬定位等於泡湯了。於是,在google搜索了一下有沒有其他方法,最後發現xposed這個東西沒準能行。於是開始折騰xposed之路。
二、分析:
xposed就不用說了,網上資料可以說多,也可以說少。這裏我就不多說了,不過有個問題是我比較擔憂的,因爲我無法確定裝了XposedInstaller後,我本人的android機子還能不能用,我的機子是vivo x27,系統是10.0版本的。於是就有了用mumu模擬器來開發的想法。
三、實施:
- 首先是給MuMu模擬器安裝XposedInstaller這個apk,這裏發張截圖標明下MuMu的設置:
因爲最開始我選的其實就是vivo的機型。
2. 安裝apk
如圖,從CSDN或者別的地方下載對應的apk。(連接地址可以從我的csdn下載中找到)
XposedBridgeApi-54&XposedInstaller_3.1.5.apk資源鏈接
給MuMu安裝了XposedInstaller_3.1.5.apk如圖:
(圖中紅框右邊那個GPS修改器就是我最開始說的那個開發者模擬位置的apk)
3. 安裝Xposed Installer,如圖:
我這裏可能是因爲我已經安裝過了,我是爲了這個文章卸載了,重新安裝,發現上面顯示框架89已經激活。不過沒有關係,點安裝/更新就好。
等待一會。此時此刻,我表示,有錢的捧個錢場,沒錢的找女朋友去減減肥什麼的。
運動。。。。十分鐘。。。。
好了,如圖:
然後他會自動裝,如圖,裝完重啓就行
4、接下來用Android Studio新建一個空的工程。如圖:
MainActivity.java裏面的代碼如下:
package com.cf.xposedhelloworld;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
public class MainActivity extends AppCompatActivity {
private Button mLoginButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLoginButton=(Button)findViewById(R.id.mLoginButton);
mLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, isCanShowContent("登陸","成功"), Toast.LENGTH_LONG).show();
}
});
}
public String isCanShowContent(String content1,String content2)
{
String content=content1+"_"+content2;
return content;
}
}
重要的是這個方法:isCanShowContent,這個方法是故意安排來做劫持的。
MainTest.java代碼如下:
package com.cf.xposedhelloworld;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class MainTest implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
// 將包名不是 com.example.login 的應用剔除掉
if (!loadPackageParam.packageName.equals("com.cf.xposedhelloworld"))
return;
XposedBridge.log("Loaded app: " + loadPackageParam.packageName);
XposedHelpers.findAndHookMethod("com.cf.xposedhelloworld.MainActivity", loadPackageParam.classLoader, "isCanShowContent", String.class,
String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("開始劫持了~");
XposedBridge.log("參數1 = " + param.args[0]);
XposedBridge.log("參數2 = " + param.args[1]);
//打印堆棧查看調用關係
StackTraceElement[] wodelogs = new Throwable("wodelog").getStackTrace();
for (int i = 0; i < wodelogs.length; i++) {
XposedBridge.log("查看堆棧:" + wodelogs[i].toString());
}
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("劫持結束了~");
XposedBridge.log("參數1 = " + param.args[0]);
XposedBridge.log("參數2 = " + param.args[1]);
//獲取類
Class<?> clazz = param.thisObject.getClass();
XposedBridge.log("要hook的方法所在的類:" + clazz.getName());
// 輸入框不爲私有private可通過以下方式獲取
//Field field = clazz.getField("ed_pwd");
// 通過類的字節碼得到該類中聲明的所有屬性,無論私有或公有
// Field field = clazz.getDeclaredField("ed_pwd");
// // 設置訪問權限
// field.setAccessible(true);
// EditText pwd = (EditText) field.get(param.thisObject);
// String str = pwd.getText().toString();
// XposedBridge.log("劫持到的密碼:" + str);
// pwd.setText("123456");
}
});
}
}
xposed_init文件(注意沒有後綴)內容如下:
com.cf.xposedhelloworld.MainTest
就是我們看到的MainTest這個java類。
AndroidManifest.xml內容如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cf.xposedhelloworld">
<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="hello world" />
<!-- 最低版本號 -->
<meta-data
android:name="xposedminversion"
android:value="54" />
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
注意模塊描述等<meta-data…>
在libs裏面有個jar包,如圖:
這個在我上傳的資源中能找到。
build.gradle(Module:app)內容如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.cf.xposedhelloworld"
minSdkVersion 22
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compileOnly fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.0.0'
implementation 'androidx.navigation:navigation-ui:2.0.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
// implementation files('lib/XposedBridgeApi-54.jar')
}
修改完同步一下。就好了。
接下來編譯到MuMu上,如圖,先連上MuMu
如果下拉里面沒有可以看我之前的文章,對於MuMu可以用adb命令連接,在adb中輸入命令:
adb connect 127.0.0.1:7555
連接成功後就能出現在可編譯機器或者下拉里面。
如圖:
打開xposedinstaller,點擊左上角的菜單(就是那三個橫槓咧)
一次執行這個步驟,然後重啓一下如圖:
運行Android Studio編譯的那個XposedHelloWorld的app,點擊按鈕登陸。之後打開Xpose Installer,查看日誌如圖:
嗯。好像是按照我代碼的邏輯走的。
四、總結:
- AndroidManifest.xml和xposed_init兩個都是爲了讓xposed installer裏面模塊中有插件。
- MainTest.java裏面這個類繼承了IXposedHookLoadPackage,並實現了 public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {這個方法,XposedBridge.log是xposed 內部的打印,所以可以在日誌中找到對應的堆棧和日誌參數。
- build.gradle最後面註銷了一行
// implementation files('lib/XposedBridgeApi-54.jar')
這個是因爲會無法Xposed Hook操作,同樣的修改了:compileOnly fileTree(include: ['*.jar'], dir: 'libs')
也是同樣的原理。
五、後續:
接下來要深入的研究研究,爭取早日把暢遊列國不辦簽證的夢想實現了。
所以:
未完待續…
嘎吱…嘎吱…嘎吱…嘎吱…嘎吱…嘎吱…嘎吱…嘎吱…嘎吱…嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱嘎吱
喔…
我要去抽根菸了…