Xposed学习记录.
https://github.com/rovo89/XposedBridge
交流微信: cjh-18888
1. Xposed 与EdXposed的安装
https://dl-xda.xposed.info/framework/
为什么我2个版本?
官方的xposed正式版支持到sdk25(android 7.1)后,就没继续发布正式版的xposed了。sdk26,27都是beta版。
因此我们在给系统刷入xposed的时候,要分版本对待。
- android系统 <= 7.1 使用官方原本xposed
- android系统 > 7.1 使用EdXposed
由于我这里只想刷高版本的,低版本的就不演示。
我选择了android9的版本,使用的设备是pixel一代.
- 刷机:sailfish-ppr1.180610.009-factory-a945cab8 我选择了这个版本的镜像,解压运行flash_all.bat就可以了
- 下载Magisk,Edxposed.riru.twrp 介绍:Magisk是root,EdXposed就是Xposed的民间版,twrp就是定制的recovery
!!! 都使用ZIP包 !!! github都可以找到,我也传了一份到网盘上
网盘地址: https://drive.weixin.qq.com/s?k=AJEAIQdfAAonAvscTZAHIAKgYiACo
EdXposed 有 sendhook 和YAHFA版, 下载sendhook,当然,yahfa也可以。
magisk-riru-v21.1
Magisk下载的是Magisk-v20.4.zip
- 推入sdcard.
adb push EdXposed-SandHook-v0.4.6.2.4529.-release.zip /sdcard/
adb push magisk-riru-v21.1.zip /sdcard/
adb push Magisk-v20.4.zip /sdcard/
- 刷入临时twrp且安装magisk,magisk-riru,edxposed,
// 进入bootloader模式
adb reboot bootloader
// 刷入临时twrp
fastboot boot twrp-3.3.0-0-sailfish.img
// 安装 Magisk -> Magisk riru -> Edxposed
// 进到漂亮的recovery界面以后 点击 Install ,找到 sdcard, 然后依次安装,然后do not install 就安装完毕了。
- 安装JustTrustMe 测试是否成功
adb install JustTrustMe.apk
// 然后激活模块,重启设备.
adb logcat
// 不出意外是可以顺利找到 Xposed的.
2. 第一个Xposed模块
基本步骤:
- 拷贝XposedBridgeApi.jar 到新建工程的libs目录
- 修改app目录下的build.gradle文件,在AndroidManifest.xml新增Xposed相关的内容
- 新建hook类,编写hook代码
- 新建assets文件夹,然后在assets目录下新建xposed_init,在里面写上hook类的完整路径
1. 在libs导入XposedBridgeApi-54.jar
文件也打包了,复制粘贴就好。
2. 修改AndroidManifest.xml
// 是否配置为Xposed插件 设置为true
<meta-data
android:name="xposedmodule"
android:value="true" />
// 模块名称
<meta-data android:name="xposeddescription"
android:value="hook 构造函数"/>
// 最低版本号
<meta-data android:name="xposedminversion"
android:value="54" />
3. 修改build.gradle
dependencies加入
compileOnly fileTree(dir: 'libs',include:['*.jar'])
4. 创建一个hook类
基本Hook代码
package com.xiaopang.xposed01;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class Xposed01 implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (loadPackageParam.packageName.equals("com.example.test")) {
XposedBridge.log("kanxue " + loadPackageParam.packageName);
};
}
}
我们可以打印一下包名,代码如下.
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("Xposed01", loadPackageParam.packageName);
// XposedBridge.log 在xposedinstall的log信息中是可以看到这部分的log
XposedBridge.log("Xposed01 ->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.example.test")) {
XposedBridge.log("weixin:cjh-18888 " + loadPackageParam.packageName);
};
}
5.创建main/assets目录,新建文本xposed_init
xposed_init里面内容为实现了IXposedHookLoadPackage接口的hook类的完整类名,它可以有多个,每一个hook实现类占一行。
xposed_init的内容
com.xiaopang.xposed01.Xposed01
6. 编译APK,看logcat
编译apk,重启,看logcat, 过滤下
2021-03-23 13:33:55.878 4440-4440/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.qualcomm.fastdormancy
2021-03-23 13:33:56.030 4496-4496/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.qualcomm.embms
2021-03-23 13:33:56.124 4514-4514/? I/EdXposed-Bridge: Xposed01 ->app packagenameorg.codeaurora.ims
2021-03-23 13:33:56.401 4537-4537/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.topjohnwu.magisk
2021-03-23 13:33:56.849 4569-4569/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.android.settings
2021-03-23 13:33:57.024 4584-4584/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.google.android.carriersetup
2021-03-23 13:33:58.283 4609-4609/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.android.cellbroadcastreceiver
2021-03-23 13:33:58.473 4627-4627/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.google.android.apps.messaging
2021-03-23 13:33:59.244 4661-4661/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.google.android.dialer
2021-03-23 13:34:00.028 4701-4701/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.google.android.gms
2021-03-23 13:34:00.314 4718-4718/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.google.android.apps.maps
2021-03-23 13:34:03.260 4797-4797/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.google.android.apps.messaging
2021-03-23 13:34:03.694 4821-4821/? I/EdXposed-Bridge: Xposed01 ->app packagenamecom.google.android.gm
3. Hook构造函数
1. 编写目标APP
- 创建Student类
package com.xiaopang.xposedhook01;
public class Student {
String name = null;
String id = null;
int age = 0;
public Student(){
this.name = "dafault";
this.id = "dafault";
this.age = 100;
}
public Student(String name){
this.name = name;
this.id = "dafault";
this.age = 100;
}
public Student(String name, String id){
this.name = name;
this.id = id;
this.age = 100;
}
public Student(String name, String id,int age){
this.name = name;
this.id = id;
this.age = age;
}
}
- 完善MainActivaty
package com.xiaopang.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.id + "--" + stu.age);
}
@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("xiaohua","2020");
Student dstudent = new Student("xiaohong","2020",20);
printStudent(astudent);
printStudent(bstudent);
printStudent(cstudent);
printStudent(dstudent);
}
}
运行一下可以在日志看到
2021-03-23 13:45:18.094 8422-8422/com.xiaopang.xposedhook01 I/Xposed: dafault--dafault--100
2021-03-23 13:45:18.094 8422-8422/com.xiaopang.xposedhook01 I/Xposed: xiaoming--dafault--100
2021-03-23 13:45:18.094 8422-8422/com.xiaopang.xposedhook01 I/Xposed: xiaohua--2020--100
2021-03-23 13:45:18.094 8422-8422/com.xiaopang.xposedhook01 I/Xposed: xiaohong--2020--20
2. 无参构造函数
- 创建HookConstructors类
// 无参构造函数Hook
XposedHelpers.findAndHookConstructor(StudentClass, new XC_MethodHook() {
@Override // 执行前 可以对参数进行修改
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("com.xiaopang.xposedhook01.Student() is called [beforeHookedMethod]");
}
@Override // 调用后 可以对返回值进行修改
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.xiaopang.xposedhook01.Student is called [afterHookedMethod]");
}
});
3. 有参构造函数
// 有参构造函数Hook
// public Student(String name){
// this.name = name;
// this.id = "dafault";
// this.age = 100;
// }
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.xiaopang.xposedhook01.Student(String) is called [beforeHookedMethod]--" + name);
}
@Override // 调用后 可以对返回值进行修改
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.xiaopang.xposedhook01.Student is called [afterHookedMethod]");
}
});
// 有参构造函数Hook
// public Student(String name, String id){
// this.name = name;
// this.id = id;
// this.age = 100;
// }
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.xiaopang.xposedhook01.Student(String,String) is called [beforeHookedMethod]--" + name + "--" + id);
}
@Override // 调用后 可以对返回值进行修改
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.xiaopang.xposedhook01.Student is called [afterHookedMethod]");
}
});
// 有参构造函数Hook
// public Student(String name, String id){
// 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];
String age = (String) argsObjarray[2];
XposedBridge.log("com.xiaopang.xposedhook01.Student(String,String,int) is called [beforeHookedMethod]--" + name + "--" + id + "--" + age);
}
@Override // 调用后 可以对返回值进行修改
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.xiaopang.xposedhook01.Student is called [afterHookedMethod]");
}
});
3. 修改参数
// 有参构造函数Hook
// public Student(String name, String id){
// 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];
String age = (String) argsObjarray[2];
argsObjarray[0] = "weixin:cjh-18888" // 修改参数
XposedBridge.log("com.xiaopang.xposedhook01.Student(String,String,int) is called [beforeHookedMethod]--" + name + "--" + id + "--" + age);
}
@Override // 调用后 可以对返回值进行修改
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.xiaopang.xposedhook01.Student is called [afterHookedMethod]");
}
});
4. 修改返回值。
// 有参构造函数Hook
// public Student(String name, String id){
// 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];
String age = (String) argsObjarray[2];
argsObjarray[0] = "weixin:cjh-18888" // 修改参数
XposedBridge.log("com.xiaopang.xposedhook01.Student(String,String,int) is called [beforeHookedMethod]--" + name + "--" + id + "--" + age);
}
@Override // 调用后 可以对返回值进行修改
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object
XposedBridge.log("com.xiaopang.xposedhook01.Student is called [afterHookedMethod]");
}
});
3. 修改属性.
如若一个类中拥有这些属性
public class Student {
String name = null;
String id = null;
int age = 0;
private String nikename = null;
public static String teacherName = null;
.......
}
1. 利用反射来修改属性
XposedHelpers.findAndHookConstructor(StudentClass,String.class,String.class,int.class,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];
String age = (String) argsObjarray[2];
argsObjarray[0] = "weixin:cjh-18888"; // 修改参数
argsObjarray[1] = "10000";
String teacher = (String) argsObjarray[3];
String nikename = (String) argsObjarray[4];
XposedBridge.log("com.xiaopang.xposedhook01.Student(String,String,int) is called [beforeHookedMethod]--" + name + "--" + id + "--" + age + "--" + teacher + "--" + nikename);
}
@Override // 调用后 可以对返回值进行修改
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object thisobj = param.thisObject;
Object returnobj = param.getResult();
XposedBridge.log(thisobj + "---" + returnobj);
XposedBridge.log("com.xiaopang.xposedhook01.Student is called [afterHookedMethod]");
}
});
ClassLoader pathClassLoader = loadPackageParam.classLoader;
Class stuClass = pathClassLoader.loadClass("com.xiaopang.xposedhook01.Student");
Field teacherField = stuClass.getDeclaredField("teacher");
teacherField.setAccessible(true);
teacherField.set(null,"teacher666");
String teachername = (String) teacherField.get(null);
Log.d("weixin:cjh-18888", "teacherField->" + teachername);
2. 利用Xposed API修改
// 通过Xposed API来修改属性
String teachername2 = (String) XposedHelpers.getStaticObjectField(stuClass,"teacher");
XposedHelpers.setStaticObjectField(stuClass,"teacher","xiaopang66666");
// 修改对象属性
// XposedHelpers.setObjectField();
它其实也是通过反射的.
public static Object getStaticObjectField(Class<?> clazz, String fieldName) {
try {
return findField(clazz, fieldName).get((Object)null);
} catch (IllegalAccessException var3) {
XposedBridge.log(var3);
throw new IllegalAccessError(var3.getMessage());
} catch (IllegalArgumentException var4) {
throw var4;
}
}
看看findField , 继续深究其实一样是利用了反射的原理
public static Field findField(Class<?> clazz, String fieldName) {
StringBuilder sb = new StringBuilder(clazz.getName());
sb.append('#');
sb.append(fieldName);
String fullFieldName = sb.toString();
Field field;
if (fieldCache.containsKey(fullFieldName)) {
field = (Field)fieldCache.get(fullFieldName);
if (field == null) {
throw new NoSuchFieldError(fullFieldName);
} else {
return field;
}
} else {
try {
field = findFieldRecursiveImpl(clazz, fieldName);
field.setAccessible(true);
fieldCache.put(fullFieldName, field);
return field;
} catch (NoSuchFieldException var5) {
fieldCache.put(fullFieldName, (Object)null);
throw new NoSuchFieldError(fullFieldName);
}
}
}
3. 使用Xposed进行“破解”
apk已传到网盘
反编译后,看到关键代码在这里. content内容长度 = 16 且 Flag2.check(content)为真的时候,返回true;
package com.kanxue.xposedflag;
public class Flag1 {
public static int length = 16;
public static boolean check(String content) {
if (content.length() != length || !new Flag2().check(content)) {
return false;
}
return true;
}
}
这里看到是在判断,content等于this.flag就返回真. 那么通过上面的学习,其实很容易就编写出xposed代码.
public class Flag2 {
public String flag = "aiyaobucuo";
public boolean check(String content) {
if (content.equals(this.flag)) {
return true;
}
return false;
}
}
Xposed代码,
package com.xiaopang.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 hookFlag implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
// com.kanxue.xposedflag
Log.d("weixin:cjh-18888", "packageNmae ->" + loadPackageParam.packageName);
// XposedBridge.log("packageNmae ->" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedflag")) {
Log.d("weixin:cjh-18888", "packageNmae ->" + loadPackageParam.packageName);
// XposedBridge.log("packageNmae ->" + loadPackageParam.packageName);
ClassLoader classLoader = loadPackageParam.classLoader;
// flag 1
Class flag1clazz = classLoader.loadClass("com.kanxue.xposedflag.Flag1");
XposedHelpers.setStaticIntField(flag1clazz,"length",6);
// flag 2
XposedHelpers.findAndHookConstructor("com.kanxue.xposedflag.Flag2", classLoader, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Log.d("weixin:cjh-18888", "into flag 2");
// XposedBridge.log("into flag 2");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
// XposedBridge.log("leave flag2 ");
Log.d("weixin:cjh-18888", "leave flag2 ");
Object flag2obj = param.thisObject;
XposedHelpers.setObjectField(flag2obj,"flag","urlsec");
}
});
};
}
}
4. Hook 一般函数
1. 一般Java函数的hook
无论是public,还是private,还是static都可以用findAndHookMethod
ClassLoader classLoader = loadPackageParam.classLoader;
Class clazz = XposedHelpers.findClass("com.xiaopang.xposedhook01.Student",classLoader);
XposedHelpers.findAndHookMethod(clazz, "publicstaticfunc", String.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Object[] objectarray = param.args;
String arg0 = (String) objectarray[0];
int arg1 = (int)objectarray[1];
XposedBridge.log("beforeHookedMethod publicstaticfunc ->arg0:" + arg0 + "--arg1:" + arg1);
// 修改
// objectarray[0] = "weixin:cjh-18888";
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String result = (String) param.getResult();
// 修改返回值
// param.setResult("weixin:cjh-18888");
XposedBridge.log("afterHookedMethod publicstaticfunc->result:" + result );
}
});
2. 内部类中的函数hook
使用美元符连接内部类
Class personClass = XposedHelpers.findClass("com.xiaopang.xposedhook01.Student$person", loadPackageParam.classLoader);
XposedHelpers.findAndHookMethod(personClass, "getpersonname", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("beforeHookedMethod getpersonname->" + param.args[0]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("afterHookedMethod getpersonname->" + param.getResult());
}
});
3. 匿名内部类函数的hook
匿名内部类其实主要还是找到classname. 匿名内部类一般都是
clssname$1,classname$2
然后就比较常规了
写累了,不想写了/