一、 Api说明

1. IXposedHookLoadPackage.java

加载回调接口,在xposed入口类继承,实现handleLoadPackage方法

  • handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam)
    这个方法用于在加载应用程序的包的时候执行用户的操作
    参数:
    LoadPackageParam loadPackageParam: 这个参数包含了加载的应用程序的一些基本信息

2. IXposedHookInitPackageResources.java

加载回调接口,用于修改app的资源文件,在xposed入口类继承,实现handleInitPackageResources(InitPackageResourcesParam resparam)方法

  • handleInitPackageResources(InitPackageResourcesParam resparam)
    这个方法用于在加载应用程序的包的时候执行用户的操作
    参数:
    InitPackageResourcesParam resparam: 这个参数包含了加载的应用程序的一些资源基本信息

3. XposedHelpers.java

一些辅助方法,简化连接和调用方法/构造函数,获取和设置字段,这里直说重要的方法

  • findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object… parameterTypesAndCallback)
    hook一个类中的方法
    参数:
    className: 要hook的方法的所在类
    classloader: 要hook的包的classLoader,一般都写loadPackageParam.classLoader
    methodName: 要hook的方法
    parameterTypesAndCallback: 方法的参数和监听器。

  • callMethod(Object obj, String methodName, Object… args)
    在目标app中调用方法
    参数:
    Object: 要调用方法的所在类
    methodName: 要调用的方法名称
    args: 方法的参数

  • findClass(String className, ClassLoader classLoader)
    获取class类实例
    参数:
    className: 类名
    classLoader: 类加载器

4. XposedBridge.java

  • log(String text)
    在Xposed的app的日志功能里输出日志和/data/xposed/debug.log 这个文件中
    参数
    text: 要输出的内容

二、 Hook过程

Xposed 框架中真正起作用的是对方法的hook,hook到之后,在方法之前之后进行修改添加或者替换,那么寻找正确的目标方法名和所在的类名就很关键了。一般寻找目标方法有两种方法:

  • 开源的直接查看源码,主要是系统应用
  • 反编译查看源码,常见的有apkTool,jadx,jeb

1. Find

通过特定的类加载器加载要hook的类,通过反射找到被hook的成员。工具类XposedHelpers提供了一些工具方法来简化find过程;XposedBridge的hook*方法用于处理hook并执行回调。

XposedHelpers静态方法 描述
findClass 使用classLoader加载class
findField* 通过反射查找类的数据成员并设置可访问性(setAccessible(true))
findMethod* 通过反射查找类的成员函数并设置可访问性
findConstructor* 通过反射查找类的构造函数并设置可访问性
setStatic* 通过反射设置类静态变量的值
set* 通过反射设置对象数据成员的值
findAndHook* 查找并hook

2. Hook

XC_MethodHook中定义了回调方法:

beforeHookedMethod(MethodHookParam param):被hook方法调用前执行,调用param.setResult可以跳过被hook的方法。
afterHookedMethod(MethodHookParam param): 被hook方法调用后执行,调用param.setResult更改被hook方法的执行结果。
replaceHookedMethod: 继承自XC_MethodReplacement,能替换Hook的方法

XC_MethodReplacement: 继承自XC_MethodHook,通过在beforeHookedMethod中调用param.setResult实现了方法的替换。

1
2
3
4
5
6
7
8
9
@Override
protected final void beforeHookedMethod(MethodHookParam param) throws Throwable {
try {
Object result = replaceHookedMethod(param);
param.setResult(result);
} catch (Throwable t) {
param.setThrowable(t);
}
}

三、注意点和技巧

1. Hook内部类

通过美元符号 $ 连接内部类

2. 只能hook方法和构造方法,不能hook接口和抽象方法

3. context上下文获取

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
Class<?> ContextClass = findClass("android.content.ContextWrapper", loadPackageParam.classLoader);
findAndHookMethod(ContextClass, "getApplicationContext", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Context applicationContext = (Context) param.getResult();
XposedBridge.log("得到上下文");
}
});
} catch (Throwable t) {
XposedBridge.log("获取上下文出错"+t);
}

4. 获取控件

例如获取一个EditText,上一篇文章的例子,获取TextView,修改字符。。打开被hook的app就会发现文本变成了”我是被Xposed修改的啦”

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
/**
* Created by LITP on 2016/9/16.
*/
public class Main implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
findAndHookMethod("com.tpnet.companycalc.MainActivity",
loadPackageParam.classLoader,
"onCreate",
Bundle.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//获取到当前hook的类,这里是MainActivity
Class clazz = param.thisObject.getClass();
XposedBridge.log("class name:" + clazz.getName());
// 输入框不为私有private 可通过以下方式获取
//Field field = clazz.getField("tv_text");// 密码输入框 id
// 通过反射获取控件,无论parivate或者public
Field field = clazz.getDeclaredField("tvText");
// 设置访问权限(这点对于有过android开发经验的可以说很熟悉)
field.setAccessible(true);
TextView textView = (TextView) field.get(param.thisObject);
String string = textView.getText().toString();
XposedBridge.log("原来的字符 : " + string);
// 设置属性
textView.setText("我是被Xposed修改的啦");
}
}
);
}
}

5. 参数中有自定义类

通过反射获得得到自定义类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class<?> hookMessageListenerClass = null;
hookMessageListenerClass = lpparam.classLoader.loadClass("org.jivesoftware.smack.MessageListener");
findAndHookMethod("org.jivesoftware.smack.ChatManager", lpparam.classLoader, "createChat", String.class , hookMessageListenerClass ,new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String sendTo = (String) param.args[0];
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});

6. hook 构造方法

findAndHookConstructor

7.打开Activity

1
2
3
4
Activity activity = (Activity) param.thisObject;
Intent intent = new Intent();
intent.setClassName(activity,"com.ushaqi.zhuishushenqi.ui.home.HomeActivity");
activity.startActivity(intent);