Xposed功能:
Xposed理论上能够hook到系统任意一个Java进程,由于是从底层hook,所以需要root权限,并且每次更新都要重新启动。
[1] 对普通函数或者构造函数有作用(针对具体实现类,不包括接口,抽象类的实现函数也可以hook)。
[2] 对目标函数进行 before、after 代码插桩,多用于操作(查看或修改)api的入参以及返回值。
[3] 目标函数替换,多用于功能变更、版本升级。
主要API:
1、IXposedHookLoadPackage 接口,App被加载的时候调用,用于App应用的hook回调方法是handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam)
lpparam包含正在加载的应用程序的有关信息。
2、XposedHelps 类,hook函数/构造函数,获取变量的辅助类
findMehtod/findConstructor/findField方法
上述三种方法可以不适用反射技术来检索methods,constructors和fields。当然,你可以使用“best match”通过确切的参数类型来查找methods和constructors。例如:调用findMethodBestMatch(Class<?> clazz,String methodName,Object… args)
callMethod/callStaticMethod/newInstance方法
通过利用上述的findxxx 方法,可以很容易地调用方法或创建一个类的实例。调用者无需对此使用反射。在这之前不许检索方法,仅仅使用上述三个方法就可以做到即时调用。参数类型会自动地从实际参数值和被调用的best-matching方法中拷贝过来。假使你想要精确地为一个参数指定类型,那么需要创建一个 Class<?>数组并传递给callMethod/callStaticMethod/newInstance方法。你可以丢弃数组中一些null值仅仅使用类的实际参数,但是数组的长度不得不与参数的数量想匹配。
getxxxField/setxxxField/getStaticxxxField/setStaticxxxField方法
上述四种方法常被使用来获取或设置实例的内容和类的变量。只需要获得对对象的引用,就可以获得对象的field的名称和类型。如果你想要 get/set 一个静态的字段,并且没有对象的引用,那么这时就可以使用getStaticxxx和setStaticxxx方法。当你获得一个对象的引用时,就可以使用getxxx和setxxx方法,因为没必要再区分静态和实例字段。
getAdditionalxxxField/setAdditionalxxxField方法
上面的两个方法可以让你要么与一个对象的实例关联任何值,要么与整个类关联任何值。这些值都是以键值对的形式存储在map中,所以你可以为每个对象保存许多值。键名key可以是string类型的,包括对象真实的字段名。请注意你不能通过调用getAdditionalInstanceField方法来检索一个以setAdditionalStaticField方法存储的值。使用getAdditionalStaticField方法可以。
getProcessPid方法
这个方法可以通过它的/proc/[pid]/cmdline的第一部分找到一个进程并且以字符串的形式返回PID。
getMD5Sum方法
这个方法可以返回文件系统中的一个文件的md5值。这需要app有对文件读取的权限。
#####assetAsByteArray方法
这个方法可以将一个asset资源以字节数组的形式返回。如果想要加载module的资源,可以通过以下的方法实现:
public class XposedTweakbox implements IXposedHookZygoteInit { @Override public void initZygote(StartupParam startupParam) throws Throwable { Resources tweakboxRes = XModuleResources.createInstance(startupParam.modulePath, null); byte[] crtPatch = assetAsByteArray(tweakboxRes, "crtfix_samsung_d506192d5049a4042fb84c0265edfe42.bsdiff"); ...
MethodHookParam param 包含与调用方法有关的信息。可以通过调用param.setResult()设置方法返回值。
param.thisObject,代表调用该方法的对象实例,如果是静态方法的话,返回一个NULL。
hook重载函数时候,只需要忽略参数的具体类型即可。这种方式其实可以达到两种效果:1. 高效的处理函数重载问题 2.目标函数参数类型太复杂,自定义的类型太多
3、XposedBridge 类,打印日志log(),有长度限制(1024),否则会被截断
hookAllMethods和hookAllConstructors方法
如果想通过明确的函数名或者一个类的构造函数 来hook所有的方法,我们可以使用这两个方法。如果要hook的类有不同的变体,这将是很有用的,但你想执行的代码(before/after)已经被调用了。注意其他不同的ROM可能也会有不同的变体,那么他们也会被hook。特别要留意你得到的回调函数的参数。
实例解析:
1.不需要获取类对象,即可直接修改类中的私有静态变量staticInt
XposedHelpers.setStaticIntField(clazz, "staticInt", 99);
2.Hook无参构造函数,啥也不干。。。。
XposedHelpers.findAndHookConstructor(clazz, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("Haha, HookDemo constructed was hooked" );
//大坑,此时对象还没有建立,即不能获取对象,也不能修改非静态变量的值
//XposedHelpers.setIntField(param.thisObject, "publicInt", 199);
//XposedHelpers.setIntField(param.thisObject, "privateInt", 299);
}
});
3.Hook有参构造函数,修改参数
XposedHelpers.findAndHookConstructor(clazz, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = "Haha, HookDemo(str) are hooked";
}
});
4.Hook有参构造函数,修改参数------不能使用XC_MethodReplacement()替换构造函数内容
//XposedHelpers.findAndHookConstructor(clazz, String.class, new XC_MethodReplacement() {
// @Override
// protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
// Log.d("HookDemo" , "HookDemo(str) was replace");
// }
//});
5.Hook公有方法publicFunc
// 1、修改参数
// 2、修改下publicInt和privateInt的值
// 3、再顺便调用一下隐藏函数hideFunc
//XposedHelpers.findAndHookMethod("com.example.xposedhooktarget.HookDemo", clazz.getClassLoader(), "publicFunc", String.class, new XC_MethodHook()
XposedHelpers.findAndHookMethod(clazz, "publicFunc", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = "Haha, publicFunc are hooked";
XposedHelpers.setIntField(param.thisObject, "publicInt", 199);
XposedHelpers.setIntField(param.thisObject, "privateInt", 299);
// 让hook的对象本身去执行流程
Method md = clazz.getDeclaredMethod("hideFunc", String.class);
md.setAccessible(true);
//md.invoke(param.thisObject, "Haha, hideFunc was hooked");
XposedHelpers.callMethod(param.thisObject, "hideFunc", "Haha, hideFunc was hooked");
//实例化对象,然后再调用HideFunc方法
//Constructor constructor = clazz.getConstructor();
//XposedHelpers.callMethod(constructor.newInstance(), "hideFunc", "Haha, hideFunc was hooked");
}
});
6.Hook私有方法privateFunc,修改参数
//XposedHelpers.findAndHookMethod("com.example.xposedhooktarget.HookDemo", clazz.getClassLoader(), "privateFunc", String.class, new XC_MethodHook()
XposedHelpers.findAndHookMethod(clazz, "privateFunc", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = "Haha, privateFunc are hooked";
}
});
7.Hook私有静态方法staticPrivateFunc, 修改参数
XposedHelpers.findAndHookMethod(clazz, "staticPrivateFunc", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = "Haha, staticPrivateFunc are hooked";
}
});
8.Hook复杂参数函数complexParameterFunc
Class fclass1 = XposedHelpers.findClass("java.util.Map", loadPackageParam.classLoader);
Class fclass2 = XposedHelpers.findClass("java.util.ArrayList", loadPackageParam.classLoader);
XposedHelpers.findAndHookMethod(clazz, "complexParameterFunc", String.class,
"[[Ljava.lang.String;", fclass1, fclass2, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = "Haha, complexParameterFunc are hooked";
}
});
9.Hook私有方法repleaceFunc, 替换打印内容
XposedHelpers.findAndHookMethod(clazz, "repleaceFunc", new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
Log.d("HookDemo", "Haha, repleaceFunc are replaced");
return null;
}
});
10.Hook方法, anonymousInner, 参数是抽象类,先加载所需要的类即可
Class animalClazz = loadPackageParam.classLoader.loadClass("com.example.xposedhooktarget.Animal");
XposedHelpers.findAndHookMethod(clazz, "anonymousInner", animalClazz, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("HookDemo This is test");
param.args[1] = "Haha, anonymousInner are hooked";
}
});
11.Hook匿名类的eatFunc方法,修改参数,顺便修改类中的anonymoutInt变量
XposedHelpers.findAndHookMethod("com.example.xposedhooktarget.HookDemo$1", clazz.getClassLoader(),
"eatFunc", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = "Haha, eatFunc are hooked";
XposedHelpers.setIntField(param.thisObject, "anonymoutInt", 499);
}
});
12.hook内部类的构造方法失败,且会导致hook内部类的InnerFunc方法也失败,原因不明
// XposedHelpers.findAndHookConstructor(clazz1, new XC_MethodHook() {
// @Override
// protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// XposedBridge.log("Haha, InnerClass constructed was hooked" );
// }
// });
13.Hook内部类InnerClass的InnerFunc方法,修改参数,顺便修改类中的innerPublicInt和innerPrivateInt变量
final Class<?> clazz1 = XposedHelpers.findClass("com.example.xposedhooktarget.HookDemo$InnerClass", loadPackageParam.classLoader);
XposedHelpers.findAndHookMethod(clazz1, "InnerFunc", String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = "Haha, InnerFunc was hooked";
XposedHelpers.setIntField(param.thisObject, "innerPublicInt", 9);
XposedHelpers.setIntField(param.thisObject, "innerPrivateInt", 19);
}
});
//getFields()与getDeclaredFields()区别:
//getFields()只能访问类中声明为公有的字段,私有的字段它无法访问,能访问从其它类继承来的公有变量.
//getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,不能访问从其它类继承来的变量
//getMethods()与getDeclaredMethods()区别:
//getMethods()只能访问类中声明为公有的方法,私有的方法它无法访问,能访问从其它类继承来的公有方法.
//getDeclaredFields()能访问类中所有的字段,与public,private,protect无关,不能访问从其它类继承来的方法
//getConstructors()与getDeclaredConstructors()区别:
//getConstructors()只能访问类中声明为public的构造函数
//getDeclaredConstructors()能访问类中所有的构造函数,与public,private,protect无关
简单使用:
1、新建Android project,将jar包api-xx.jar api-xx-sources.jar拷贝到新建lib文件夹,不能使用Android自带的libs文件夹
2、在app/main下新建assets文件夹,新建文件xposed-init ,只包含hook类全路径(例如:com.ex.yu.xposed_demo.Main)
3、配置app下build.gradle文件,dependencies中添加jar包依赖
provided 'de.robv.android.xposed:api:xx'
4、编辑AndroidManifest.xml,添加:
<meta-data
android:name="xposedmodule"
android:value="true"/>
<meta-data
android:name="xposeddescription"
android:value="hello xposed"/>
<meta-data
android:name="xposedminversion"
android:value="82"/>
5、编写Main文件