0x00 简介
- 是什么:
Xposed framework
是一个基于Android
系统实现的能够给用户提供修改系统层面或第三方APP功能的框架服务。 - 如何工作:
Android
中有一个叫做Zygote
的核心进程,它会随Android
系统的启动而启动,然后加载系统所需的类,最后再调用初始化方法。每一个APP的进程都是从Zygote
进程fork
出的子进程,这个进程的文件是/system/bin/app_process
。
当安装Xposed framework
后,Xposed framework
会替换一个新的app_process
至/system/bin/
中,同时还会替换虚拟机和其他若干文件。Zygote
启动时,会加载Xposed
所需的JAR
包(/data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar
)至系统目录,并启动Xposed
替换的虚拟机。
Xposed framework
的主要接口由XposedBridge.jar
提供,框架的核心功能在替换的虚拟机中实现。
0x01 示例代码
用户可以使用Xposed framework
去Hook
方法,下面是作者本人给出的一个示例:
package de.robv.android.xposed.mods.tutorial;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import android.graphics.Color;
import android.widget.TextView;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
public class Tutorial implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.systemui"))
return;
findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
TextView tv = (TextView) param.thisObject;
String text = tv.getText().toString();
tv.setText(text + " :)");
tv.setTextColor(Color.RED);
}
});
}
}
这个示例代码实现了对Andoird
系统时钟输出样子和颜色的修改,完整的源码地址是https://github.com/rovo89/XposedExamples/tree/master/RedClock。如此简单的几行代码,它的内部实现机制是怎么的呢?想知道这些,最好的办法当然是分析源码。
0x02 Hook流程分析
这里使用Xposed framework
Hook
java.net.URLEncoder
类的encode
方法作为例子分析,调用逻辑如下所示:
public class Tutorial implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
findAndHookMethod("java.net.URLEncoder", lpparam.classLoader, "encode", String.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
}
});
handleLoadPackage
会在任意一个APP加载的时候被调用,然后就可以在这个接口内部根据包名做逻辑判断,如果是Hook
方法所在的包,则进一步调用findAndHookMethod
去Hook
指定的方法。
通过findAndHookMethod()
接口找到指定方法并进行Hook
。它的参数较多,第一个参数是类名,第二个参数是类加载器,第三个参数是方法名,后面是可变参数,把方法的参数类型依次作为参数,最后一个参数是XC_MethodHook()
对象。另外,在其内部重写beforeHookedMethod
和afterHookedMethod
方法,这两个方法分别会在Hook
方法执行的前后执行,用户可以在其中实现自己的逻辑。
findAndHookMethod
这个接口的实现在XposedHelpers.java
这个文件中,代码如下:
public static XC_MethodHook.Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) {
return findAndHookMethod(findClass(className, classLoader), methodName, parameterTypesAndCallback);
}
public static XC_MethodHook.Unhook findAndHookMethod(Class<?> clazz, String methodName, Object... parameterTypesAndCallback) {
if (parameterTypesAndCallback.length == 0 || !(parameterTypesAndCallback[parameterTypesAndCallback.length-1] instanceof XC_MethodHook))
throw new IllegalArgumentException("no callback defined");
XC_MethodHook callback = (XC_MethodHook) parameterTypesAndCallback[parameterTypesAndCallback.length-1];
Method m = findMethodExact(clazz, methodName, getParameterClasses(clazz.getClassLoader(), parameterTypesAndCallback));
return XposedBridge.hookMethod(m, callback);
}
首先,接口内部会根据类名和类加载器查找Class
对象,再根据Class
对象和方法名去查找Method
对象,最后调用XposedBridge.hookMethod
完成对方法的Hook
。
看一下方法查找的实现:
public static Method findMethodExact(String className, ClassLoader classLoader, String methodName, Object... parameterTypes) {
return findMethodExact(findClass(classNam