Xposed框架详解

来源:互联网 发布:mac装win7加载驱动程序 编辑:程序博客网 时间:2024/05/16 08:24

        最近接触了Android开发中用到的比较火的一个框架——Xposed框架。那么什么是Xposed框架呢?

     (文章参考了http://blog.csdn.net/zhangmiaoping23/article/details/52572447)

1、什么是Xposed框架?

        百度百科上给出的定义是:Xposed是一款可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于Xposed可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。

        优点:Xposed是基于AOSP(android open source project)开发的,对源代码改动不大的ROM兼容性比较好,这也就使得某一功能可以借助Xposed移植到不同的ROM上。例如:现在你的手机上所拥有的功能你已经很喜欢了,但是又羡慕其他系统所独特拥有的功能,那么我们就可以通过Xpose框架将另一系统上的某些功能模块移植到我们自己的android系统上。如果想要恢复系统的原状的话,只需要在Xposed里取消对其他功能的勾选就可以了。

        注意:Xposed的安装需要root权限。

2、Xposed框架如何配置在eclipse上,进行模块的开发?

        首先准备好eclipse、XposedBridge.jar包、SDK、JDK。将XposedBridge.jar包放在新建项目的lib/libs下面,然后右键buildpath 

3、Xposed框架的核心思想?

        Xposed的核心思想是将Java层的普通的函数注册成本地的JNI(Java native interface)方法,以此来变相实现hook机制。

        Java native interface:它提供了若干的API,实现了Java和其他语言的通信(主要是C/C++)

3.1 Android程序是在Dalvik虚拟机上运行的,那么Dalvik在执行Java层代码时,是如何识别JNI方法的?首先来看一下类的的加载过程:(类第一次被使用)——>(类的字节码被加载到内存)——>(字节码的入口维持着该类所有方法描述符的list)      这些描述符包含着:(方法代码存于何处)(有哪些参数)如果一个方法描述符内有native,这些描述符快将有一个指向该方法的实现的指针。

一个类执行之前会先被装载,之后需要字节码验证,检验完成之后,虚拟机会紧接着调用findClass()来查找并装载main的方法类,然后再调用类中的成员函数.CallStaticVoidMethod执行main方法,程序开始运行。

3.2那么我们如何将Java层的普通的方法注册成JNI方法呢?

(1)SET_METHOD_FLAG(method,ACC_NATIVE):将方法描述符中的accessFlags修改为NATIVE方法
(2)method->nativeFunc=&xposedCallHandler:存储该方法实际调用的本地方法的执行位置,将要hook的Java层方法注册成本地方法。Native层方法统一的入口点设置为xposedCallHandler
(3)method->insns=(const  u2*)hookInfo:insns存储该方法没被native之前的位置
(4)method->registersSize=method->size:为注册的nativeFunc方法参数列表分配内存空间,与Java自带方法的等大小即可

3.3xposed框架在其中做了些什么呢?

        xposed修改了app_process,在执行第一个Java程序之前进行截获,改变程序的执行流程,进入到自身的main函数里面。main函数的执行体内主要完成了下面四个功能:
(1)initNative():——>是本地的方法,完成了xposed框架的初始化工作
(2)initXbridgeZygote():——>主要hook了几个涉及到应用程序创建、启动的关键类。新的应用进程创建时会调用这几个类的特定方法,xposed框架通过截获应用进程创建时的相关信息来决定对其处理逻辑。
(3)loadModules():——>读取系统中放置的hook模块。简单地说就是把hook模块随便找个地方丢进去,然后把该模块的路径写进conf/modules.list中就可以了。
         1)读取conf/modules.list文件中写入的apk的名称
         2)从每一个apk中读取其/assets/xposed_init文件中声明的hook主模块的类的名称
         3)classLoader加载各hook主模块类
         4)判断加载的类属于哪一种类别
(4)执行原com.android.internal.os.ZygotelInit的main函数,完成zygote的初始化工作
xposed框架加载完毕后,将执行权交给com.Android.interbal.os.ZygoteInit,完成正常的系统启动流程
总结:
——创建新的应用,获取包名 等信息
——调用XC_LoadPackage.callAll,依次执行各hook模块的代码,如果有包名匹配的hook模块,则注册模块中要hook的方法为本地Native方法
——当该方法被调用的时候,转移到本地的xposedCallHandler
—— XposedCallHandler回调上层handlerHookedMethod
——handlerHookedMethod执行加载的各hook模块     

4、微信运动   

    微信运动是想获取到我们走了多少步。Android机会有自带的计数传感器。当应用程序想要知道我们走了多少步的时候,需要去询问计数传感器;计数传感器得到请求
之后,会把步数返回给应用程序,这样的话,应用程序就可以通过页面向我们展示我们走的步数了。所以,如果我们想要在不知不觉的情况下,修改步数的话,我们就需要在计
数传感器向应用程序返回数据的时候,进行拦截,然后修改处理逻辑,再将数据返回。
        因为是第一次真正的接触android,所以下面的代码是参考着http://blog.csdn.net/chenhao0428/article/details/51436837写的:
package com.example.xposedandriod;import static de.robv.android.xposed.XposedHelpers.findClass;import java.lang.reflect.Field;import android.app.Activity;import android.hardware.Sensor;import android.util.Log;import android.util.SparseArray;import de.robv.android.xposed.IXposedHookLoadPackage;import de.robv.android.xposed.XC_MethodHook;import de.robv.android.xposed.XposedBridge;import de.robv.android.xposed.callbacks.XC_LoadPackage;public class WeiXinSport extends Activity implements IXposedHookLoadPackage  {/** * @param args */private static int stepCount = 1;@Overridepublic void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable{if(!loadPackageParam.packageName.equals("com.tencent.mm")){//过滤来自微信的请求return;}//hook了andriod.hardware.SystemSensorManager$SensorEventQueue这个类中的dispatchSensorEvent这个方法final Class sensorEL = findClass("android.hardware.SystemSensorManager$SensorEventQueue",loadPackageParam.classLoader);XposedBridge.hookAllMethods(sensorEL,"dispatchSensorEvent", new XC_MethodHook(){@SuppressWarnings("unchecked")@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable{((float[]) param.args[1])[0] = ((float[]) param.args[1])[0] + 1200*stepCount;//计数传感器将步数返回微信运动之前被修改stepCount++;XposedBridge.log("stepCount"+stepCount);Field field = param.thisObject.getClass().getDeclaringClass().getDeclaredField("sHandleToSensor");field.setAccessible(true);//便于调试,将传感器的一些数据打印了出来int handle = (Integer)param.args[0];Sensor sensor = ((SparseArray) field.get(0)).get(handle);XposedBridge.log("sensor = " + sensor);}});}}
原创粉丝点击