Xposed二进制补丁插件开发

介绍

Xposed是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。在这个框架下,我们可以编写并加载自己编写的插件APP,实现对目标apk的注入拦截等。

原理就是控制zygote进程,通过替换/system/bin/app_process程序控制zygote进程,使得它在系统启动过程中会加载Xposed framework的一个jar文件即XposedBridge.jar,从而完成对zygote进程及其创建的Dalvik/ART虚拟机的劫持,并且能够运行开发者独立的替代任何class,例如framework本身,系统UI又或者随意的一个app。

4.4以下Android版本安装较为简单,将root后的手机安装xposedInstaller,不过官网不再维护,导致无法直接通过xposedInstaller下载补丁包。

5.0开始,谷歌使用ART替换Dalvik,xposed分为两个部分,xposed*.zip和XposedInstaller.apk,zip文件是框架主体,需要进入Recovery后刷入,apk文件是xposed模块管理应用,主要用于下载,激活,是否启用模块等管理功能。首先完成对手机root,并刷入recove(如twrp),下载对应zip补丁包,进入recovery刷入,重启手机安装xposedinstaller并收入root权限。

Nexus6前arm32,后arm64

image-20220504174619207

image-20220504174958428

安卓8以上安装Edxposed,对于Xposed官方不支持的较新的Android版本可以先安装magisk,接着安装riru模块,最后再进行Edxposed的安装。

  • Android Red Velvet Cake (11, sdk30)
  • Android Queen Cake (10, sdk29)
  • Android Pie (9, sdk28)
  • Android Oreo (8.1, sdk27)
  • Android Oreo (8.0, sdk26)

Magisk-v24.3.apk 实现root

1
2
3
4
5
EdXposed-SandHook-v0.4.6.2.4529.-release.zip
EdXposed-YAHFA-v0.4.6.2.4529.-release.zip
EdXposedManager-4.5.7-45700-org.meowcat.edxposed.manager-release.apk
magisk-riru-v21.1.zip
Magisk-v20.4.zip

Hook

  1. 拷贝XposedBridgeApi.jar到新建工程的libs目录
  2. 修改app目录下的build.gradle文件,在AndroidManifest.xml中增加Xposed相关内容
  3. 新建hook类,编写hook代码
  4. 新建assets文件夹,然后在assets目录下新建xposed_init,在里面写hook类的完整路径

app/libs放入XposedBridgeApi-54.jar

app/build.gradle

1
2
3
4
5
6
7
8
dependencies {
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

AndroidManifest.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kanxue.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" />
<meta-data android:name="xposeddescription" android:value="第一个Xposed插件"/>
<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>

</manifest>

Xposed01.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import android.content.pm.ApplicationInfo;
import android.telephony.TelephonyManager;
import android.util.Log;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XC_MethodReplacement;
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("Xposed01->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.example.test")) {
XposedBridge.log("kanxue " + loadPackageParam.packageName);
XposedHelpers.findAndHookMethod(TelephonyManager.class, "getDeviceId", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
return XposedBridge.invokeOriginalMethod(param.method,param.thisObject,param.args);
//return "this is imei";
}
});
XposedHelpers.findAndHookMethod(TelephonyManager.class, "getSubscriberId", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
return "this is imsi";
}
});

}
;
}
}

app/src/main/assets/xposed_init

1
2
com.kanxue.xposed01.Xposed01
com.kanxue.xposed01.HookConstructors

构造函数

java反射或xposed的api属性修改

HookConstructors.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
public class HookConstructors implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("Xposed01", loadPackageParam.packageName);
XposedBridge.log("Xposed01->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedhook01")) {
//XposedBridge.log("kanxue " + loadPackageParam.packageName);

// 无参构造函数
ClassLoader classLoader = loadPackageParam.classLoader;
Class StudentClass = classLoader.loadClass("com.kanxue.xposedhook01.Student");
XposedHelpers.findAndHookConstructor(StudentClass, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("com.kanxue.xposedhook01.Student() is called!!beforeHookedMethod");
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.kanxue.xposedhook01.Student() is called!!afterHookedMethod");
}
});

// public Student(String name2) {
// this.name = name2;
// this.id = "default";
// }
// public java.lang.Object thisObject;
// public java.lang.Object[] args;
// private java.lang.Object result;
// 一个参数的构造函数
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.kanxue.xposedhook01.Student(String) is called!!beforeHookedMethod--" + name);
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.kanxue.xposedhook01.Student(String) is called!!afterHookedMethod");
}
});
// public Student(String name2, String id2) {
// this.name = name2;
// this.id = id2;
// }
// 两个参数的构造函数
XposedHelpers.findAndHookConstructor("com.kanxue.xposedhook01.Student", loadPackageParam.classLoader, 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.kanxue.xposedhook01.Student(String,String) is called!!beforeHookedMethod--" + name + "---" + id);
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.kanxue.xposedhook01.Student(String,String) is called!!afterHookedMethod");
}
});


// 获取属性
ClassLoader pathClassLoader= loadPackageParam.classLoader;
final Class stuClass=pathClassLoader.loadClass("com.kanxue.xposedhook01.Student");
XposedBridge.log("StudentClass->"+stuClass);

// 使用java反射修改属性
/* Field teacherField=stuClass.getDeclaredField("teacher");
teacherField.setAccessible(true);
teacherField.set(null,"teacher666");
String teachername1= (String) teacherField.get(null);
XposedBridge.log("teacherField->"+teachername1);*/

// 使用Xposed的api修改属性
//(java.lang.Class<?> clazz, java.lang.String fieldName, java.lang.Object value)
XposedHelpers.setStaticObjectField(stuClass,"teacher","teacher888");
String teachername2= (String) XposedHelpers.getStaticObjectField(stuClass,"teacher");
XposedBridge.log("XposedHelpers.getStaticObjectField->"+teachername2);

//public Student(String name, String id, int age, String teachername, String nickname)
// 5个参数的构造函数
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];
int age = (int) (argsobjarray[2]);

argsobjarray[1] = "2050"; // 修改值
argsobjarray[2] = 100;

String teacher= (String) argsobjarray[3];
String nickname= (String) argsobjarray[4];
XposedBridge.log("com.kanxue.xposedhook01.Student(String,String) is called!!beforeHookedMethod--" + name + "---" + id + "--" + age+"---"+teacher+"---"+nickname);
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object thisobj = param.thisObject;
/* Field nicknameField=stuClass.getDeclaredField("nickname");
XposedBridge.log(stuClass+"--nicknameField->"+nicknameField);
nicknameField.setAccessible(true);
nicknameField.set(thisobj,"bear");*/

XposedHelpers.setObjectField(thisobj,"nickname","chick");
Object returnobj = param.getResult();
XposedBridge.log(thisobj + "---" + returnobj);
XposedBridge.log("com.kanxue.xposedhook01.Student(String,String,int) is called!!afterHookedMethod");
}
});
}
}
}

动静属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class HookFlag implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("HookFlag", loadPackageParam.packageName);
XposedBridge.log("HookFlag->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedflag")) {
XposedBridge.log("HookFlag " + loadPackageParam.packageName);

// 修改静态属性
ClassLoader classLoader=loadPackageParam.classLoader;
Class Flag1Class=classLoader.loadClass("com.kanxue.xposedflag.Flag1");
XposedHelpers.setStaticIntField(Flag1Class,"length",8);

// 修改Flag2的flag动态属性为123456
XposedHelpers.findAndHookConstructor("com.kanxue.xposedflag.Flag2", classLoader, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("go into com.kanxue.xposedflag.Flag2()->beforeHookedMethod");
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("leave com.kanxue.xposedflag.Flag2()->afterHookedMethod");
Object Flag2obj=param.thisObject;
XposedHelpers.setObjectField(Flag2obj,"flag","12345678");
}
});
}
}
}

DexClassLoader

Xposed不止可以实现对app自己试下拿到类构造函数hook,对于系统框架层的java函数可以进行hook,Hook所有classLoader包括加载dex中的,并打印这些classLoader中的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class HookDexClassLoader implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("HookDexClassLoader", loadPackageParam.packageName);
XposedBridge.log("HookDexClassLoader->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.loaddex")) {

//public DexClassLoader(String dexPath, String optimizedDirectory,
// String librarySearchPath, ClassLoader parent) {
// super(dexPath, null, librarySearchPath, parent);
// }
XposedHelpers.findAndHookConstructor(DexClassLoader.class, String.class, String.class, String.class, ClassLoader.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Object array[]=param.args;
String dexpath= (String) array[0];
String optimizedDirectory= (String) array[1];
String librarySearchPath= (String) array[2];
XposedBridge.log("DexClassLoader beforeHookedMethod:"+dexpath+"---"+optimizedDirectory+"---"+librarySearchPath);

}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
DexClassLoader dexClassLoader= (DexClassLoader) param.thisObject;
XposedBridge.log("DexClassLoader afterHookedMethod:"+dexClassLoader);
GetClassLoaderClasslist(dexClassLoader);
// 指定classLoader
XposedHelpers.findAndHookMethod("com.kanxue.test02.TestClass", dexClassLoader, "testcontent", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Object[] objectarray = param.args;
String arg0 = (String) objectarray[0];
XposedBridge.log("beforeHookedMethod11 privatefunc->arg0:" + arg0);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
// String result = (String) param.getResult();
// XposedBridge.log("afterHookedMethod11 privatefunc->result:" + result);
param.setResult(true);
}
});
}
});
}
}
}

一般函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
public class HookJavaFunction implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("Xposed01", loadPackageParam.packageName);
XposedBridge.log("HookJava->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedhook01")) {
XposedBridge.log("kanxue " + loadPackageParam.packageName);
ClassLoader classLoader = loadPackageParam.classLoader;

XposedBridge.log("loadPackageParam.classLoader->" + classLoader);
Class StuClass = classLoader.loadClass("com.kanxue.xposedhook01.Student");
// public static String publicstaticfunc(String arg1, int arg2) {
// String result = privatestaticfunc("privatestaticfunc", 200);
// return arg1 + "---" + arg2 + "---" + result;
// }
// 公有函数的hook与修改
XposedHelpers.findAndHookMethod(StuClass, "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];
objectarray[0]="changedbyxposedjava";
objectarray[1]=888;
XposedBridge.log("beforeHookedMethod publicstaticfunc->arg0:"+arg0+"---arg1:"+arg1);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String result= (String) param.getResult();
param.setResult("changedbyxposed->afterHookedMethod");
XposedBridge.log("afterHookedMethod publicstaticfunc->result:"+result);

}
});
// 私有函数的hook与修改
XposedHelpers.findAndHookMethod(StuClass, "privatestaticfunc", 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];
objectarray[0] = "changedbyxposedjava";
objectarray[1] = 888;
XposedBridge.log("beforeHookedMethod privatestaticfunc->arg0:" + arg0 + "---arg1:" + arg1);
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String result = (String) param.getResult();
param.setResult("changedbyxposed->afterHookedMethod");
XposedBridge.log("afterHookedMethod privatestaticfunc->result:" + result);
}
});
// private static String privatestaticfunc(String arg1, int arg2) {
// return arg1 + "---" + arg2;
// }
XposedHelpers.findAndHookMethod(StuClass, "publicfunc", 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];
objectarray[0] = "changedbyxposedjava";
objectarray[1] = 888;
XposedBridge.log("beforeHookedMethod publicfunc->arg0:" + arg0 + "---arg1:" + arg1);
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String result = (String) param.getResult();
param.setResult("changedbyxposed->afterHookedMethod");
XposedBridge.log("afterHookedMethod publicfunc->result:" + result);
}
});
// private String privatefunc(String arg1, int arg2) {
// return arg1 + "---" + arg2;
// }

// 指定classLoader
XposedHelpers.findAndHookMethod("com.kanxue.xposedhook01.Student", loadPackageParam.classLoader, "privatefunc", 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("beforeHookedMethod11 privatefunc->arg0:" + arg0 + "---arg1:" + arg1);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String result = (String) param.getResult();
XposedBridge.log("afterHookedMethod11 privatefunc->result:" + result);
}
});
// 内部类,匿名内部类$1,$2...
Class personClass = XposedHelpers.findClass("com.kanxue.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());
}
});
// public static java.lang.Class<?> findClass(java.lang.String className, java.lang.ClassLoader classLoader)
//Class StuClassByXposed=XposedHelpers.findClass("com.kanxue.xposedhook01.Student",classLoader);
}
}
}

JNI函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class HookJni implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("Xposed01", loadPackageParam.packageName);
XposedBridge.log("HookJava->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.loaddex")) {

Class MainActivityClass=XposedHelpers.findClass("com.kanxue.loaddex.MainActivity",loadPackageParam.classLoader);

XposedHelpers.findAndHookMethod(MainActivityClass, "onCreate", Bundle.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("beforeHookedMethod onCreate->"+param.args[0]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("afterHookedMethod onCreate->"+param.thisObject);
}
});
XposedHelpers.findAndHookMethod(MainActivityClass, "replaceClassloader", ClassLoader.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("beforeHookedMethod replaceClassloader->Classloader:"+param.args[0]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("afterHookedMethod replaceClassloader->"+param.thisObject);
}
});
}
}
}

主动调用

对于类中的静态函数,直接调用即可。对于非静态函数,需要先得到类的实例,才能完成调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
public class HookActiveInvoke implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("XposedActiveInvoke", loadPackageParam.packageName);
XposedBridge.log("XposedActiveInvoke->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedhook01")) {
XposedBridge.log("kanxue " + loadPackageParam.packageName);

// 主动调用
// public static String publicstaticfunc(String arg1, int arg2) {
// String result = privatestaticfunc("privatestaticfunc", 200);
// Log.i("Xposed","publicstaticfunc is called!");
// return arg1 + "---" + arg2 + "---" + result;
// }
// 反射调用
ClassLoader classLoader = loadPackageParam.classLoader;
Class StuClass = classLoader.loadClass("com.kanxue.xposedhook01.Student");
Method publicstaticfunc_method = StuClass.getDeclaredMethod("publicstaticfunc", String.class, int.class);
publicstaticfunc_method.invoke(null, "InvokedByXposed", 100);

// api调用静态函数
java.lang.Class<?>[] parameterTypes = {String.class, int.class};
XposedHelpers.callStaticMethod(StuClass, "publicstaticfunc", parameterTypes, "publicstaticfunc is called by XposedHelpers.callStaticMethod11", 100);
XposedHelpers.callStaticMethod(StuClass, "publicstaticfunc", "publicstaticfunc is called by XposedHelpers.callStaticMethod22", 200);
XposedHelpers.callStaticMethod(StuClass, "privatestaticfunc", parameterTypes, "privatestaticfunc is called by XposedHelpers.callStaticMethod11", 400);
XposedHelpers.callStaticMethod(StuClass, "privatestaticfunc", "privatestaticfunc is called by XposedHelpers.callStaticMethod22", 300);

// 反射调用静态函数
Method privatestaticfunc_method = StuClass.getDeclaredMethod("privatestaticfunc", String.class, int.class);
privatestaticfunc_method.setAccessible(true);
String result = (String) privatestaticfunc_method.invoke(null, "privatestaticfuncIsInvokedByXposed", 200);
XposedBridge.log("privatestaticfuncIsInvokedByXposed->result:" + result);
// private static String privatestaticfunc(String arg1, int arg2) {
// Log.i("Xposed","privatestaticfunc is called!");
// return arg1 + "---" + arg2;
// }
// api调用动态函数
Object StuObjByXposed = XposedHelpers.newInstance(StuClass, "StuObjByXposed.newInstance", "500");
String result1 = (String) XposedHelpers.callMethod(StuObjByXposed, "publicfunc", "publicfunc is called by XposedHelpers.callMethod", 125);
XposedBridge.log("publicfunc XposedHelpers.callMethod result->" + result1);
XposedHelpers.callMethod(StuObjByXposed, "privatefunc", "privatefunc is called by XposedHelpers.callMethod", 130);

// 反射调用动态函数
Method publicfunc_method = StuClass.getDeclaredMethod("publicfunc", String.class, int.class);
// public Student(String name, String id) {
// this.name = name;
// this.id = id;
// }
// public Student(String name, String id) 调用构造函数获得对象 反射主动调用
Constructor StuCon = StuClass.getDeclaredConstructor(String.class, String.class);
Object StuObj = StuCon.newInstance("InstanceByXposed", "300");
publicfunc_method.invoke(StuObj, "publicfuncInvokedByXposed", 100);

// public String publicfunc(String arg1, int arg2) {
// String result = privatefunc("privatefunc", 300);
// Log.i("Xposed","publicfunc is called!"+"---"+arg1+"---"+arg2);
// person tmp=new person();
// String tmpresult=tmp.getpersonname("person");
// return arg1 + "---" + arg2 + "---" + result+"---"+tmpresult;
// }
//

Method privatefunc_method = StuClass.getDeclaredMethod("privatefunc", String.class, int.class);
privatefunc_method.setAccessible(true);
String privatefunc_result = (String) privatefunc_method.invoke(StuObj, "privatefuncInvokedByXposed", 200);
XposedBridge.log("privatefunc activeInvokeByXposed-->" + privatefunc_result);
// private String privatefunc(String arg1, int arg2) {
// Log.i("Xposed","privatefunc is called!"+"---"+arg1+"---"+arg2);
// return arg1 + "---" + arg2;
// }


//Student cstudent = new Student("xiaohua", "2020");
// hook 构造函数
XposedHelpers.findAndHookConstructor(StuClass, String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("Student(String,String) is called beforeHookedMethod");
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("Student(String,String) is called afterHookedMethod");
Object cstudent=param.thisObject;
XposedHelpers.callMethod(cstudent,"publicfunc","publicfunc is called XposedHelpers.findAndHookConstructor",666);
XposedHelpers.callMethod(cstudent,"privatefunc","privatefunc is called XposedHelpers.findAndHookConstructor",888);
}
});


// public String getNickname() {
// return nickname;
// }
// hook 普通函数
XposedHelpers.findAndHookMethod(StuClass, "getNickname", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Object obj=param.thisObject;
XposedHelpers.callMethod(obj,"publicfunc","beforeHookedMethod publicfunc is called XposedHelpers.callMethod",444);
XposedHelpers.callMethod(obj,"privatefunc","beforeHookedMethod privatefunc is called XposedHelpers.callMethod",333);
XposedBridge.log("getNickname is called beforeHookedMethod->"+obj);
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Object obj=param.thisObject;
XposedHelpers.callMethod(obj,"publicfunc","afterHookedMethod publicfunc is called XposedHelpers.callMethod",222);
XposedHelpers.callMethod(obj,"privatefunc","afterHookedMethod privatefunc is called XposedHelpers.callMethod",111);
XposedBridge.log("getNickname is called afterHookedMethod->"+param.thisObject);
}
});

}
}
}

加壳app处理

类不在classLoader中,在自定义的Application中的attachBaseContext和onCreate中完成dex的解密和classLoader修正。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
public class HookJava implements IXposedHookLoadPackage {
public static Field getClassField(ClassLoader classloader, String class_name, String filedName) {

try {
Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
return field;
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;

}

public static Object getClassFieldObject(ClassLoader classloader, String class_name, Object obj, String filedName) {

try {
Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
Object result = null;
result = field.get(obj);
return result;
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;

}

public static Object invokeStaticMethod(String class_name, String method_name, Class[] pareTyple, Object[] pareVaules) {

try {
Class obj_class = Class.forName(class_name);
Method method = obj_class.getMethod(method_name, pareTyple);
return method.invoke(null, pareVaules);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;

}

public static Object getFieldOjbect(String class_name, Object obj, String filedName) {
try {
Class obj_class = Class.forName(class_name);
Field field = obj_class.getDeclaredField(filedName);
field.setAccessible(true);
return field.get(obj);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
return null;

}

// 获取当前classLoader
public static ClassLoader getClassloader() {
ClassLoader resultClassloader = null;
Object currentActivityThread = invokeStaticMethod( "android.app.ActivityThread", "currentActivityThread", new Class[]{}, new Object[]{});
Object mBoundApplication = getFieldOjbect( "android.app.ActivityThread", currentActivityThread, "mBoundApplication");
Application mInitialApplication = (Application) getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mInitialApplication");
Object loadedApkInfo = getFieldOjbect( "android.app.ActivityThread$AppBindData", mBoundApplication, "info");
Application mApplication = (Application) getFieldOjbect("android.app.LoadedApk", loadedApkInfo, "mApplication");
resultClassloader = mApplication.getClassLoader();
return resultClassloader;
}

// 打印classLoader中所有的类
public void GetClassLoaderClasslist(ClassLoader classLoader) {
//private final DexPathList pathList;
XposedBridge.log("start dealwith classloader:" + classLoader);
Object pathListObj = XposedHelpers.getObjectField(classLoader, "pathList");
//private final Element[] dexElements;
Object[] dexElementsObj = (Object[]) XposedHelpers.getObjectField(pathListObj, "dexElements");
for (Object i : dexElementsObj) {
//private final DexFile dexFile;
Object dexFileObj = XposedHelpers.getObjectField(i, "dexFile");
//private Object mCookie;
Object mCookieObj = XposedHelpers.getObjectField(dexFileObj, "mCookie");
//private static native String[] getClassNameList(Object cookie);
// public static java.lang.Object callStaticMethod(java.lang.Class<?> clazz, java.lang.String methodName, java.lang.Object... args) { /* compiled code */ }
Class DexFileClass = XposedHelpers.findClass("dalvik.system.DexFile", classLoader);

String[] classlist = (String[]) XposedHelpers.callStaticMethod(DexFileClass, "getClassNameList", mCookieObj);
for (String classname : classlist) {
XposedBridge.log(dexFileObj + "---" + classname);
}
}
XposedBridge.log("end dealwith classloader:" + classLoader);
}

@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("Xposed01", loadPackageParam.packageName);
XposedBridge.log("HookJava->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedhook01")) {
XposedBridge.log("kanxue " + loadPackageParam.packageName);
ClassLoader classLoader = loadPackageParam.classLoader;
XposedBridge.log("loadPackageParam.classLoader->" + classLoader);
/*
01-09 05:26:25.678 29011-29011/? I/Xposed: loadPackageParam.classLoader->dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.kanxue.xposedhook01-1/base.apk"],nativeLibraryDirectories=[/data/app/com.kanxue.xposedhook01-1/lib/arm, /vendor/lib, /system/lib]]]
01-09 05:26:25.679 29011-29011/? I/Xposed: start dealwith classloader:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.kanxue.xposedhook01-1/base.apk"],nativeLibraryDirectories=[/data/app/com.kanxue.xposedhook01-1/lib/arm, /vendor/lib, /system/lib]]]
01-09 05:26:25.681 29011-29011/? I/Xposed: /data/app/com.kanxue.xposedhook01-1/base.apk---com.qihoo.util.Configuration
01-09 05:26:25.681 29011-29011/? I/Xposed: /data/app/com.kanxue.xposedhook01-1/base.apk---com.qihoo.util.DtcLoader
01-09 05:26:25.681 29011-29011/? I/Xposed: /data/app/com.kanxue.xposedhook01-1/base.apk---com.qihoo.util.QHDialog
01-09 05:26:25.681 29011-29011/? I/Xposed: /data/app/com.kanxue.xposedhook01-1/base.apk---com.qihoo.util.ᵢˋ
01-09 05:26:25.681 29011-29011/? I/Xposed: /data/app/com.kanxue.xposedhook01-1/base.apk---com.qihoo.util.ᵢˎ
01-09 05:26:25.681 29011-29011/? I/Xposed: /data/app/com.kanxue.xposedhook01-1/base.apk---com.qihoo.util.ᵢˏ
01-09 05:26:25.681 29011-29011/? I/Xposed: /data/app/com.kanxue.xposedhook01-1/base.apk---com.stub.StubApp
01-09 05:26:25.681 29011-29011/? I/Xposed: end dealwith classloader:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.kanxue.xposedhook01-1/base.apk"],nativeLibraryDirectories=[/data/app/com.kanxue.xposedhook01-1/lib/arm, /vendor/lib, /system/lib]]]
*/
GetClassLoaderClasslist(classLoader);
ClassLoader parent = classLoader.getParent();
// 将当前classLoader双亲委派模型打印
while (parent != null) {
XposedBridge.log("parent->" + parent);
if (parent.toString().contains("BootClassLoader")) {
} else {
GetClassLoaderClasslist(parent);
}
parent = parent.getParent();
}
/*
* 01-09 05:05:34.284 24462-24462/? I/Xposed: loadPackageParam.classLoader->dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.kanxue.xposedhook01-1/base.apk"],nativeLibraryDirectories=[/data/app/com.kanxue.xposedhook01-1/lib/arm, /vendor/lib, /system/lib]]]
01-09 05:05:34.284 24462-24462/? I/Xposed: parent->dalvik.system.PathClassLoader[DexPathList[[dex file "/data/dalvik-cache/xposed_XResourcesSuperClass.dex", dex file "/data/dalvik-cache/xposed_XTypedArraySuperClass.dex"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]]
01-09 05:05:34.284 24462-24462/? I/Xposed: parent->java.lang.BootClassLoader@6c4cdad
* */
// hook壳的onCreate
Class StubAppClass=XposedHelpers.findClass("com.stub.StubApp",loadPackageParam.classLoader);
// 获取该类所有函数
Method[] methods=StubAppClass.getDeclaredMethods();
for(Method i:methods){
XposedBridge.log("com.stub.StubApp->"+i);
}
XposedHelpers.findAndHookMethod("com.stub.StubApp", loadPackageParam.classLoader, "onCreate", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("com.stub.StubApp->onCreate beforeHookedMethod");
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.stub.StubApp->onCreate afterHookedMethod");

ClassLoader finalClassLoader=getClassloader();
XposedBridge.log("finalClassLoader->" + finalClassLoader);
GetClassLoaderClasslist(finalClassLoader);
XposedHelpers.findAndHookMethod("com.kanxue.xposedhook01.Student", finalClassLoader, "privatefunc", 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("beforeHookedMethod11 privatefunc->arg0:" + arg0 + "---arg1:" + arg1);

}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);

String result = (String) param.getResult();
XposedBridge.log("afterHookedMethod11 privatefunc->result:" + result);

}
});

Class personClass = XposedHelpers.findClass("com.kanxue.xposedhook01.Student$person", finalClassLoader);
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());
}
});


}
});
}
}
}

Lebo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("Xposed01", loadPackageParam.packageName);
XposedBridge.log("HookLebo->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.f0208.lebo")) {
XposedBridge.log("kanxue " + loadPackageParam.packageName);
Class StubAppClass=XposedHelpers.findClass("com.f0208.lebo.MyWrapperProxyApplication",loadPackageParam.classLoader);
Method[] methods=StubAppClass.getDeclaredMethods();
for(Method i:methods){
XposedBridge.log("com.f0208.lebo.MyWrapperProxyApplication->"+i);
}
XposedHelpers.findAndHookMethod("com.f0208.lebo.MyWrapperProxyApplication", loadPackageParam.classLoader, "onCreate", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("com.f0208.lebo.MyWrapperProxyApplication->onCreate beforeHookedMethod");
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("com.f0208.lebo.MyWrapperProxyApplication->onCreate afterHookedMethod");

ClassLoader finalClassLoader=getClassloader();
XposedBridge.log("finalClassLoader->" + finalClassLoader);
XposedHelpers.findAndHookMethod("com.zw.lebo.MainActivity", finalClassLoader, "onCreate", Bundle.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("beforeHookedMethod com.zw.lebo.MainActivity.onCreate");

}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("afterHookedMethod com.zw.lebo.MainActivity.onCreate");

}
});
}
});
}
}

SO函数处理

32位hook

Xposed01动态加载dex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 @Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("XposedHookSo", loadPackageParam.packageName);
XposedBridge.log("XposedHookSo->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedhookso")) {
XposedBridge.log("XposedHookSo " + loadPackageParam.packageName);
// 6.0 XposedHelpers.findAndHookMethod("java.lang.Runtime", loadPackageParam.classLoader, "loadLibrary", String.class,ClassLoader.class, new XC_MethodHook() {
// 7.0 XposedHelpers.findAndHookMethod("java.lang.Runtime", loadPackageParam.classLoader, "loadLibrary", ClassLoader.class, String.class, new XC_MethodHook() {
XposedHelpers.findAndHookMethod("java.lang.Runtime", loadPackageParam.classLoader, "loadLibrary0", String.class,ClassLoader.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
// 7.0 String soname= (String) param.args[1];
String soname= (String) param.args[0]; // 6.0
XposedBridge.log("beforeHookedMethod Runtime.load("+soname+","+param.args[1]+")");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
// 7.0 String soname= (String) param.args[0];
String soname= (String) param.args[0]; // 6.0
XposedBridge.log("afterHookedMethod Runtime.load("+soname+")");
if(soname.contains("native-lib")){
System.load("/data/data/com.kanxue.xposedhookso/files/hookso.so");
}
}
});
}
}

git clone https://github.com/ele7enxxh/Android-Inline-Hook.git inline的hook库面向32位,复制include,inlineHook.c,relocate.c,relocate.h到cpp下,并在CMakeLists.txt中引入

1
2
3
4
5
6
7
8
9
10
11
add_library( # Sets the name of the library.
native-lib

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
inlineHook.c
relocate.c

native-lib.cpp)

native-lib.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <jni.h>
#include <string>
#include <android/log.h>
#include <dlfcn.h>
#include <unistd.h>
#include <fcntl.h>

extern "C" {
#include "include/inlineHook.h"
}
void *(*old_strstr)(char *, char *) = nullptr;

void *new_strstr(char *arg0, char *arg1) {
__android_log_print(4, "hookso", "strstr is called,arg1:%s,arg2:%s", arg0, arg1);
if (strcmp(arg1, "hookso") == 0) {
int a = 1;
return &a;
} else {
void *result = old_strstr(arg0, arg1);
return result;
};
}

void starthooklibc() {

void *libchandle = dlopen("libc.so", RTLD_NOW);
void *strstr_addr = dlsym(libchandle, "strstr");
if (registerInlineHook((uint32_t) strstr_addr, (uint32_t) new_strstr,
(uint32_t **) &old_strstr) !=
ELE7EN_OK) {
return;
}
if (inlineHook((uint32_t) strstr_addr) == ELE7EN_OK) {
__android_log_print(4, "hookso", "hook libc.so->strstr success!");
//return -1;
}

}

extern "C" void _init(void) {
__android_log_print(4,"kanxuetest","go into _init");
starthooklibc();
}
__attribute__ ((constructor(10), visibility ("hidden"))) void initarray_4(void) {
__android_log_print(4,"kanxuetest","go into initarray_4");
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = nullptr;
jint result = -1;
__android_log_print(4,"kanxuetest","go into JNI_OnLoad");
//starthooklibc();
if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
printf("err!!");
return JNI_ERR;
}
return JNI_VERSION_1_6;
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_kanxue_hookso_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
__android_log_print(4,"kanxuetest","go into Java_com_kanxue_hookso_MainActivity_stringFromJNI");
std::string hello = "Hello from C++";
if(strstr("aaaaabbbbb","hookso")!= nullptr){
__android_log_print(4,"kanxuetest","find hookso");
}else{
__android_log_print(4,"kanxuetest","not find hookso");
}
return env->NewStringUTF(hello.c_str());
}

编译生成的libnative-lib.so重命名为hookso.so放到手机/data/data/com.kanxue.xposedhookso/files下,给予权限,重新启动,打开Xposed01 app,完成调用libc的strstr函数的hook。

64位hook

git clone https://github.com/asLody/SandHook.git 将cpp中代码拷贝到XposeeHookSoBySandHook项目的cpp中

build.gradle

1
2
3
4
5
6
7
externalNativeBuild {
cmake {
arguments '-DBUILD_TESTING=OFF'
cppFlags "-frtti -fexceptions -Wpointer-arith"
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}

native-lib.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <jni.h>
#include <string>
#include "sandhook_native.h"
#include "utils/log.h"
#include <android/log.h>
#include <unistd.h>
#include <cassert>
#include <cstdlib>

#include "includes/elf.h"

class instance;

void *(*old_strstr)(char *, char *) = nullptr;

void *new_strstr(char *arg0, char *arg1) {
__android_log_print(4, "hooksoarm64", "strstr is called,arg1:%s,arg2:%s", arg0, arg1);
if (strcmp(arg1, "hookso") == 0) {
int a = 1;
return &a;
} else {
void *result = old_strstr(arg0, arg1);
return result;
};
}

void starthooklibc() {
if (sizeof(void *) == 8) {
const char *libcpath = "/system/lib64/libc.so";
old_strstr = reinterpret_cast<void *(*)(char *, char *)>(SandInlineHookSym(libcpath,
"strstr",
reinterpret_cast<void *>(new_strstr)));
} else {
const char *libcpath = "/system/lib/libc.so";
old_strstr = reinterpret_cast<void *(*)(char *, char *)>(SandInlineHookSym(libcpath,
"strstr",
reinterpret_cast<void *>(new_strstr)));
}
}

bool testhook(const char *content) {
if (strstr(content, "hookso") != nullptr) {
__android_log_print(4, "xposedhookso", "find hookso");
return true;
} else {
__android_log_print(4, "xposedhookso", "not find hookso");
}
return false;
}

int (*testhookfunctin)(const char *) = nullptr;

extern "C" void _init(void) {
LOGD("go into _init");
//starthooklibc();
}
// 比initarray中的方法早
extern "C" jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
LOGD("go into JNI_OnLoad");
starthooklibc();
return JNI_VERSION_1_6;
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_kanxue_xposeehooksobysandhook_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}

编译生成so拷贝到/data/data/com.kanxue.xposedhookso/files/hookso.so下并配置权限

主动调用

XposeeHookSoBySandHook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
bool testhook(const char *content) {

if (strstr(content, "hookso") != nullptr) {
__android_log_print(4, "xposedhookso", "find hookso");
return true;
} else {
__android_log_print(4, "xposedhookso", "not find hookso");
}
return false;

}
extern "C" jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
LOGD("go into JNI_OnLoad");
//starthooklibc();
activecalltesthook();

return JNI_VERSION_1_6;
}
void activecalltesthook() {
typedef int (*testhook)(const char *a1);

testhook testhookfunction = nullptr;
//得到函数地址
/* extern "C"
EXPORT void* SandGetModuleBase(const char* so);*/

void *libnativebase = SandGetModuleBase("libnative-lib.so");
//thumb 0x8B4C是testhook的基地址偏移
if(sizeof(void*)==4){
// 指针不能直接参与运算 32位
unsigned long tmpaddr = (unsigned long) libnativebase + 0x8B4C + 1;
void *testhookaddr = reinterpret_cast<void *>(tmpaddr);
testhookfunction = reinterpret_cast<testhook>(testhookaddr);
}else{
// 64位
unsigned long tmpaddr = (unsigned long) libnativebase + 0xf67c;
void *testhookaddr = reinterpret_cast<void *>(tmpaddr);
testhookfunction = reinterpret_cast<testhook>(testhookaddr);
LOGD("libnative-lib.so base:%p,testfuncaddr:%p",libnativebase,(void*)tmpaddr);
}

int result1 = testhookfunction("aaaaahookso");

LOGD("testhookfunction(\"aaaaahookso\"); return:%d", result1);

int result2 = testhookfunction("aaaabbbbb");
LOGD("testhookfunction(\"aaaabbbbb\"); return:%d", result2);

}

编译生成的libsandhook-native.so推送到/sdcard/32.so,重命名为hookso.so复制到/data/data/com.kabxue.xposedhookso/files下

进入xposed01项目中,定义XposedActiveCallSoFunction类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 @Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.i("XposedHookSo", loadPackageParam.packageName);
XposedBridge.log("XposedHookSo->app packagename" + loadPackageParam.packageName);
if (loadPackageParam.packageName.equals("com.kanxue.xposedhookso")) {
XposedBridge.log("XposedHookSo " + loadPackageParam.packageName);
// 6.0 XposedHelpers.findAndHookMethod("java.lang.Runtime", loadPackageParam.classLoader, "loadLibrary", String.class,ClassLoader.class, new XC_MethodHook() {
// 7.0 XposedHelpers.findAndHookMethod("java.lang.Runtime", loadPackageParam.classLoader, "loadLibrary", ClassLoader.class, String.class, new XC_MethodHook() {
XposedHelpers.findAndHookMethod("java.lang.Runtime", loadPackageParam.classLoader, "loadLibrary0", String.class,ClassLoader.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
// 7.0 String soname= (String) param.args[1];
String soname= (String) param.args[0]; // 6.0
XposedBridge.log("beforeHookedMethod Runtime.load("+soname+","+param.args[1]+")");
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
// 7.0 String soname= (String) param.args[0];
String soname= (String) param.args[0]; // 6.0
XposedBridge.log("afterHookedMethod Runtime.load("+soname+")");
if(soname.contains("native-lib")){
System.load("/data/data/com.kanxue.xposedhookso/files/hookso.so");
}
}
});
}
}

指纹检测与定制反检测

  1. Xposed插件管理-XposedInstaller
  2. Xposed对函数hook根本原理-java函数变native函数
  3. Xposed大量api
  4. Xposed框架特定文件等

XposedChecker

Xposed框架组成

  1. XposedInstaller 完整的Android工程,编译生成apk,用于管理Xposed框架的插件
  2. Xposed 对Zygote进程定制,能够实现对接下来任何一个app进程的hook
  3. android_art 用于支持对Java类函数hook而对ART源码进程的一系列定制
  4. XposedBridge Xposed的java部分,可单独作为Android工程进行编译
  5. XposedTools 用于编译和打包Xposed框架

简单定制

修改Xposed框架中所有关于Xposed相关的类,函数等指纹信息(比如关键字Xposed),便可以绕过大多数Xposed框架指纹检测技术,其他的根据Xposed对Java函数hook的根本原理进行检测(如判断函数属性是否变为native),也可以在编写对应插件进行绕过。

文章作者: J
文章链接: http://onejane.github.io/2022/05/04/Xposed二进制补丁插件开发/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 万物皆可逆向
支付宝打赏
微信打赏