一、Xposed框架简介
- Xposed是Android平台上的一个常用的HOOK框架,可以在不改变程序源代码的前提下,影响程序的运行。一个支持Xposed的Android应用程序被称为一个Xposed模块,用户可以在Xposed中安装各种各样的Xposed模块,在启用或关闭Xposed模块之后,需要重新引导系统才能生效。
- Xposed模块使用Java语言开发,这意味着开发人员可以使用Android Studio开发一个自己的Xposed模块,就像开发一个Android应用程序一样简单。
二、Xposed框架安装
- 安装Xposed框架的前提是手机要有root权限,或者有第三方Recovery
- 在Android手机上安装Xposed是一件有风险的事,在尝试之前需要对手机的Recovery、root等知识有一定的了解,否则请不要贸然尝试。同时不建议在日常使用的手机上尝试安装Xposed框架,因为一些应用程序可以检测它,并且以此为理由来封禁您的帐号(例如微信)。
- Xposed有两种安装方法,第一种是通过Xposed Installer来安装,首先安装上Xposed Installer,它会自动检测手机的Android版本,同时可以下载Xposed来执行安装,安装时候可以直接进行安装(可能需要root权限)也可以通过Recovery来安装。第二种方式就是直接下载Recovery的包来安装,使用Recovery进行刷入。
- 以上资源在XDA论坛上都有提供,下载地址:[OFFICIAL] Xposed for Lollipop/Marshmallow/Nougat/Oreo [v90-beta3, 2018/01/29]
三、Xposed框架开发环境搭建
- 上文已经提到,开发一个Xposed模块并不困难,因为Xposed模块也是使用Java语言开发的,这里使用Android Studio来开发一个Xposed模块。关于Android应用开发的基本知识,这里不再赘述,读者如果不了解Android开发,可以参考Android Developers上的入门指南。
- 在创建好工程之后,首先需要配置Gradle,以添加Xposed依赖库,在app文件夹下的build.gradle文件中,将以下语句添加到
dependencies
中:
compileOnly 'de.robv.android.xposed:api:82'
compileOnly 'de.robv.android.xposed:api:82:sources'
provided 'de.robv.android.xposed:api:82'
provided 'de.robv.android.xposed:api:82:sources'
- 这样就配置好了Xposed的依赖库,下面我们需要在
AndroidManifest.xml
中,声明本程序是一个Xposed模块,在<application></application>
中添加以下XML语句:
<meta-data
android:name="xposedmodule"
android:value="true"/>
<meta-data
android:name="xposeddescription"
android:value="My Xposed Module"/>
<meta-data
android:name="xposedminversion"
android:value="54"/>
- 上面三个meta-data指定了Xposed模块标识、Xposed模块描述(显示在Xposed Installer中的模块库中)以及最低Xposed版本。
- 最后,我们在工程的
assets
文件夹下新建一个文本文件,命名为xposed_init
,这个文件用于配置Xposed的入口类名,在文件中直接写入实现了IXposedHookLoadPackage
接口的类名即可,本类中的实例为:
cn.xiaolus.xposed_xiaolu.XposedMain
- 经过上述配置,Xposed开发环境就已经准备完毕,可以开始编写Xposed模块了。
四、Xposed API使用
- Xposed最常用的功能就是修改函数的行为,例如返回值,这里也只阐述这部分API的使用。首先我们新建一个Java类,命名为
XposedMain
,位于包cn.xiaolus.xposed_xiaolu
当中,这和xposed_init
中的配置一致,该类需要实现IXposedHookLoadPackage
接口。在该接口中,提供了一个名为handleLoadPackage
的方法,这个方法在Android系统每次加载一个包的时候都会被调用。
public class XposedMain implements IXposedHookLoadPackage {
/**
* 加载每个包时的回调方法
* @param loadPackageParam 加载的Package的参数
* @throws Throwable
*/
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) {
//Do something
}
}
- 如前所属,因为在每个包加载的时候这个方法都会被调用,所以请勿在此方法中编写耗时的操作,否则整个系统都可能会卡死。一般而言我们只需要关心我们目标程序所在的包即可,通过以下的方法可以取出加载的包名:
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) {
//判断当前加载的包名
if(loadPackageParam.packageName.equals("cn.xiaolus.syscheck")) {
//Do something
}
}
- 对于我们关心的包来说,我们还需要找到对应的类和方法,这样才可以修改其运行的行为,通过以下代码可以实现我们的目标:
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) {
// 判断当前加载的包名
if(loadPackageParam.packageName.equals("cn.xiaolus.syscheck")) {
//
XposedHelpers.findAndHookMethod("cn.xiaolus.syscheck.SecCheck",
loadPackageParam.classLoader,
"checkRoot", new XC_MethodHook() {
/**
* 在Hook指定的方法之前调用此回调方法
* @param param 方法Hook参数
* @throws Throwable
*/
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
param.setResult(false);
}
/**
* 在Hook指定的方法之后调用此回调方法
* @param param 方法Hook参数
* @throws Throwable
*/
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
param.setResult(false);
}
});
}
}
- 上面的代码使用了
XposedHelpers
的findAndHookMethod
方法,需要四个参数或者五个参数,四个参数的用于HOOK无参数的方法,参数分别为完整类名、ClassLoader对象、方法名以及一个回调接口;五个参数的话在方法名之后需要提供Class[]形式的参数类型表,其他参数相同。
- XC_MethodHook接口有两个回调方法,一个是
beforeHookedMethod
,一个是afterHookedMethod
,分别是在HOOK指定的函数之前调用和之后调用,具体使用哪个回调方法可以自己尝试。在这两个方法中可以通过MethodHookParam
参数获得并修改函数的各种参数,例如通过setResult
方法修改函数的返回值,就实现了对函数方法返回值的修改。
- 运行程序,目标函数无论执行情况如何,返回值都为false,这一般用于一些权限或者框架检测的破解和绕过,也可以用于其他的用途。
五、总结
- Xposed是一款优秀的Android HOOK框架,优势是模块编写起来相对比较容易,功能强大,缺点也比较明显,每次重新编译框架或者开启、关闭框架,都需要重新引导系统,比较麻烦,同时不能直接HOOK C/C++编写的函数,也比较容易被检测出来(当然了你可以把检测代码也HOOK掉),也是其局限性之一。