1. 简介
Xposed
框架的原理是替换安卓系统/System/bin
目录下的文件,从而实现对系统某些功能的替换,进而给予基于 Xposed 框架开发的App更多权限。
下图是作者rovo89 在github上Xposed工程目录:
从上图可以看出Xposed共有五个部分:
Xposed:Xposed的C++部分,主要是用来替换/system/bin/app_process
,并为 XposedBridge
提供JNI方法;
XposedBridge:Xposed的Java部分,以XposedBridge.jar
文件存在,负责在Native 层与FrameWork层进行交互。/system/bin/app_process
进程启动过程中会加载该jar包,其它的Modules的开发与运行都是基于这个jar;
XposedInstaller:Xposed的安装包,负责配置Xposed工作的环境并且提供对基于Xposed框架的Modules的管理。在安装XposedInstaller之后,app_process与XposedBridge.jar放置在了/data/data/de.robv.android.xposed.installer
;
XposedMods:用Xposed Framework实现的实现的demo;
XposedAppSettings: 使用Xposed开发的一些Modules,其中AppSettings是一个可以进行权限动态管理的应用;
2. 运行原理
Xposed通过替换/system/bin/app_process
程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持;
当系统中安装了 Xposed Framework 之后,会对 app_process 进行扩展,也就是说,Xposed Framework 会拿自己实现的 app_process 覆盖掉 Android 原生提供的 app_process 文件,当系统启动的时候,就会加载由 Xposed Framework 替换过的进程文件,并且XposedFramework 还有一个 jar 包,系统启动的时候,也会加载这个包:XposedBridge.jar。
Xposed框架实现Hook的原理介绍: Zygote进程是 Android 的核心,每运行一个 app,Zygote 就会 fork 一个虚拟机实例来运行 app。Zygote 的启动配置在/init.rc 脚本中,由系统启动的时候开启此进程,对应的执行文件是/system/bin/app_process,这个文件完成类库加载及一些函数调用的工作。当系统中安装了 Xposed 框架 之后,会对 app_process 进行扩展,也就是说,Xposed 框架会拿自己实现的 app_process 覆盖掉 Android 原生提供的 app_process 文件,当系统启动的时候,就会加载由 Xposed Framework 替换过的进程文件,并且,Xposed框架 还定义了一个 jar 包,系统启动的时候,也会加载这个XposedBridge包。
3.Xposed运行的条件
- 从上述原理可以看出Xposed需要替换/system/bin/app_process,因此需要手机获得root权限;
手机需要安装XposedInstaller.apk;
Xposed的使用流程
Xposed使用起来还是相对简单(到目前为止个人麻烦的是对需要hook的混淆过的app业务逻辑的分析,混淆!!), 大致流程可以分为五步:
建立一个空的Android工程;
修改AndroidManifest.xml, 并且添加Xposed配置信息;
删除Activity有关的信息,并且添加如下三项meta-data内容:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.appchina.xpoesd">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="xposedmodule"
android:value="true"/>
<meta-data
android:name="xposeddescription"
android:value="微信抢红包"/>
<meta-data
android:name="xposedminversion"
android:value="54"/>
</application>
</manifest>
在工程目录下新建一个libs文件夹, 将下载好的XposedBridgeApi-54.jar包放入其中;
3. 在assets目录下新建一个xposed_init文件,
格式为:包名+类名,如:com.appchina.xposed.XposedWeChatMoney
hook函数的编写, 这也是最核心的部分,在这部分你可以劫持需要hook的app的参数以及做一些我们自己想要完成的事情(可不要做太过分和违法的事情哦);
(1). 将之前新建的工程的java类实现IXposedHookLoadPackage接口并重新它的两个方法;
(2). 在handleLoadPackage()方法中对包名进行过滤,如果不是我们想要hook的包则什么都不做;
(3). 这也是最核心的一步,在这一步我们将处理我们的核心业务,如果前面过滤得到的是我们需要hook的包,在这里我们就需要对其它所属的方法进行hook,也就是对原app具体业务逻辑的hook,使用Xposed提供的findAndHookMethod()直接进行Hook操作,具体分为hook前执行的方法beforeAndHookMethod()和hook后需要执行的方法afterAndHookMethod(),在hook的回调中可以使用XposedBridge.log()方法打出log日志.
public class XposedWeChatMoney implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!loadPackageParam.packageName.equals("com.appchina.xposed")) {
return;
}
XposedBridge.log("loadPackageParam = "+loadPackageParam.packageName);
XposedHelpers.findAndHookMethod("android.app.application",
loadPackageParam.classLoader, "onCreate", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("beforeHookedMethod");
XposedBridge.log("loadPackageParam 0 = "+param.args[0]);
XposedBridge.log("loadPackageParam 1 = "+param.args[1]);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
XposedBridge.log("afterHookedMethod");
XposedBridge.log("loadPackageParam 0 = "+param.args[0]);
XposedBridge.log("loadPackageParam 1 = "+param.args[1]);
}
});
}
}
重写XC_MethodHook的两个方法beforeHookedMethod和afterHookedMethod,这两个方法会在原始的方法的之前和之后执行.您可以使用beforeHookedMethod 方法来打印/篡改方法调用的参数(通过param.args) ,甚至阻止调用原来的方法(发送自己的结果).afterHookedMethod 方法可以用来做基于原始方法的结果的事情.您还可以用它来操纵结果 .当然,你可以添加自己的代码,它将会准确地在原始方法的前或后执行.