Xposed_Hook构造函数
编写准备
1.拷贝XposedBridgeApi.jar
到新建工程的libs目录
2.修改App目录下的build.gradle
文件,在androidmanifest.xml
中新增Xposed
相关内容
3.新建Hook
类,编写Hook代码
4.新建assets
文件夹,然后在assets
目录下新建路径Xposed_init
,在里面写上Hook类的完整路径
不想怎么麻烦可以使用如下(可以自动化创建Xposed
模块Hook)
https://github.com/monkeylord/XposedTemplateForAS
(新手推荐,但本文未使用)
Tips
:AS版本3.6.2以上废掉了模板功能
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xposed01">
<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" /> //是否配置为Xposed插件,需要设置为true
<meta-data
android:name="xposedminversion"
android:value="54" /> //最低版本号
<meta-data
android:name="xposeddescription" //模块名字
android:value="Xposed第一个" /> //描述
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Xposed插件编写
1.新建Hook类,命名为XMdodule
,并实现IXPosedHookLoadPackage
即可,并实现里面的关键方法handleLoadPackage(XC_LoadPackage.LoadPackageParam Ipparam)
,该方法会在每个软件被启动的时候回调,所以一般需要通过目标包名过滤。如下
Xposed01.java
public class Xposed01 implements IXposedHookLoadPackage{
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable{
Log.i("Xposed01", loadPackageParam.packageName);
XposedBridge.log("App packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.example.test")){
XposedBridge.log("Xposed01" + loadPackageParam.packageName);
}
}
}
loadPackageParam.packageName
可以获取Xposed插件运行在哪个App进程空间当中
这里的日志输出Log.i
会输出在安卓的日志中,XposedBridge.log
会输出在Xposed程序日志中
多模块
如果有多个模块Xposed01
,Xposed02
,Xposed03
...可以在assets/xposed_init中调整,按照先后顺序执行
com.example.xposed01.Xposed01
com.example.xposed01.Xposed02
com.example.xposed01.Xposed03
....
Tips:xposed_init是入口
在新建一个Xposed插件
这里我们需要自己写一个带有构造函数的App
Student.java
package com.example.xposedhook01;
public class Student {
String name=null;
String id=null;
int age=0;
public Student(){
name="default";
id="default";
age=100;
}
public Student(String name){
this.name=name;
id="default";
}
public Student(String name,String id){
this.name=name;
this.id=id;
}
public Student(String name,String id,int age){
this.name=name;
this.id=id;
this.age=age;
}
}
MainActivity.java
package com.example.xposedhook01;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
public void printStudent(Student stu){
//打印学生信息
Log.i("Xposed",stu.name+"- -"+stu.name+"- -"+stu.name+"- -"+stu.name);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//调用四个构造函数
Student astudent = new Student();
Student bstudent = new Student("xiaoming");
Student cstudent = new Student("xiaoming","2022");
Student dstudent = new Student("xiaoming","2022",20);
printStudent(astudent);
printStudent(bstudent);
printStudent(cstudent);
printStudent(dstudent);
}
}
Xposed Hook修改参数信息或者修改返回对象
运行情况
Hook构造函数就需要用到XposedHelpers.findAndHookConstructor
,AS中有两个
public static XC_MethodHook.Unhook findAndHookConstructor(Class<?> clazz, Object... parameterTypesAndCallback)
public static XC_MethodHook.Unhook findAndHookConstructor(String className, ClassLoader classLoader, Object... parameterTypesAndCallback)
第一个是java.lang.Class
类型 可以通过反射获取Class
进行加载
第二个是java.lang.String
需要传入类名和ClassLoader
(就是当前的类被加载到哪个ClassLoader
当中)后面就是构造函数的参数信息,最后就是一个回调。已知可以拿到的classloader和类名的
这里可以通过两种方式
首先需要获取Classloader
,首先我们写的App并没有加壳,所以直接使用如下直接获取
ClassLoader classLoader=loadPackageParam.classLoader;
loadPackageParam
类有当前包名/当前进程名/classLoader
1.无参构造函数Hook(使用第一个API)
package com.example.xposed01;
import android.util.Log;
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 Xposed01 implements IXposedHookLoadPackage{
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable{
Log.i("Xposed01", loadPackageParam.packageName);
XposedBridge.log("App packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.example.xposedhook01")){
XposedBridge.log("Xposed01" + loadPackageParam.packageName);
ClassLoader classLoader=loadPackageParam.classLoader;
Class StudentClass=classLoader.loadClass(" com.example.xposedhook01.Student");//反射调用相关的api,得到StudentClass
//public Student(){
//name="default";
//id="default";
//age=100;
//}
XposedHelpers.findAndHookConstructor(StudentClass, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param); //调用前,用于参数修改等
XposedBridge.log("com.example.xposedhook01.Student() is Classed!!beforeHookedMethod");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);//调用后,用于返回值修改或获取等
XposedBridge.log("com.example.xposedhook01.Student() is Classed!!afterHookedMethod");
}
});
}
}
}
2.有参构造函数Hook(使用第一个API)
不管是beforeHookedMethod
还是afterHookedMethod
都有一个参数叫MethodHookParam
有当前对象thisObject
,参数args
,可以看到是一个数组,同时还有一个result
(函数执行后),一般用着三个
// public Student(String name){
// this.name=name;
// id="default";
XposedHelpers.findAndHookConstructor(StudentClass, String.class, new XC_MethodHook() { //需要传入参数类型,这样就可以获取到参数信息了
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
java.lang.Object[] argsobjarray=param.args;
String name=(String) argsobjarray[0]; //强制转换
XposedBridge.log("com.example.xposedhook01.Student(String) is Classed!!beforeHookedMethod- -"+name);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});
// public Student(String name,String id){
// this.name=name;
// this.id=id;
// }
//在参数传入中多加一个String.class
XposedHelpers.findAndHookConstructor(StudentClass, String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
java.lang.Object[] argsobjarray=param.args;
String name=(String) argsobjarray[0]; //强制转换
String id=(String) argsobjarray[1];
XposedBridge.log("com.example.xposedhook01.Student(String,String) is Classed!!beforeHookedMethod- -"+name+"---"+id);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});
//public Student(String name,String id,int age){
// this.name=name;
// this.id=id;
// this.age=age;
// }
XposedHelpers.findAndHookConstructor(StudentClass, String.class, String.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
java.lang.Object[] argsobjarray=param.args;
String name=(String) argsobjarray[0]; //强制转换
String id=(String) argsobjarray[1];
int age=(int) argsobjarray[2];
//修改参数
argsobjarray[1]="2050";
argsobjarray[2]=1000;
XposedBridge.log("com.example.xposedhook01.Student(String,String,int) is Classed!!beforeHookedMethod- -"+name+"---"+id+"- -"+age);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});
(使用第二个API)
//第二种方式需要知道准确的Classloader,其他内容和上面的差不多
XposedHelpers.findAndHookConstructor("com.example.xposedhook01.Student", loadPackageParam.classLoader, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});