1、Xposed框架是需要root的,他的功能很全,能够hook掉系统方法,同时也可以hook掉其他应用的一些方法。
2、Dexposed框架是不需要root的,但是他只能hook掉在自己的应用进程中的一些方法,其他应用进程是没办法hook的。
3、Epic是基于Dexposed进行的修改,支持art虚拟机上面的Hook。
一、Xposed原理:设备root之后,替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。
那么这里就引出了一个问题,为什么要替换app_process程序呢?
简述:
关于app_process程序网上也有很多讲解了,他其实是一个程序,存放在system/bin目录下的,他的作用就是启动一个程序,比如我们熟知的zygote进程,还有所有app启动,app_process只要找到需要运行程序的main函数也就是入口函数,然后执行,他不仅能执行C/C++程序,也可以执行Java程序。
详述:
首先在Android系统中,应用程序进程都是由Zygote进程孵化出来的,而Zygote进程是由Init进程启动的。Zygote进程在启动时会创建一个Dalvik虚拟机实例,每当它孵化一个新的应用程序进程时,都会将这个Dalvik虚拟机实例复制到新的应用程序进程里面去,从而使得每一个应用程序进程都有一个独立的Dalvik虚拟机实例。这也是Xposed选择替换app_process的原因。 Zygote进程在启动的过程中,除了会创建一个Dalvik虚拟机实例之外,还会将Java运行时库加载到进程中来,以及注册一些Android核心类的JNI方法来前面创建的Dalvik虚拟机实例中去。注意,一个应用程序进程被Zygote进程孵化出来的时候,不仅会获得Zygote进程中的Dalvik虚拟机实例拷贝,还会与Zygote一起共享Java运行时库。这也就是可以将XposedBridge这个jar包加载到每一个Android应用程序中的原因。XposedBridge有一个私有的Native(JNI)方法hookMethodNative,这个方法也在app_process中使用。这个函数提供一个方法对象利用Java的Reflection机制来对内置方法覆写。
综上就是Xposed框架选择app_proess作为入口的一个原因,因为这个入口有两个好处:
1、一旦修改了,就可以修改了所有的app
2、这里的时机是最早的,可以加载所有的东西
二、Dexposed原理原理简述:
在Dalvik虚拟机下,主要是通过改变一个方法对象方法在Dalvik虚拟机中的定义来实现,具体做法就是将该方法的类型改变为Native并且将这个方法的实现链接到一个通用的Native Dispatch方法上。这个 Dispatch方法通过JNI回调到Java端的一个统一处理方法,最后在统一处理方法中调用before, after函数来实现AOP。在Art虚拟机上目前也是通过改变一个 ArtMethod的入口函数来实现。Alibaba-Dexposed Bug框架原理及源码解析_开发者-CSDN博客_dexposed原理
这里给出大致流程: 1. 调用DexposedBridge.findAndHookMethod,进入到DexposedBridge类(Java层逻辑) 2. 通过XposedHelpers.findMethodExact找到要hook的java方法,然后再用hookMethod进行真正的hook。 3. hookMethod方法先把hook成功后的callback、要hook的方法的参数和返回值类型保存到AdditionalHookInfo中,把它作为参数传给hookMethodNative。hookMethodNative是一个native方法,它的第3个参数slot表示该Method在class的方法表中所处的位置,在native的实现中会用到这个slot。 4. hookMethod 方法中调用hookMethodNative,执行Native层方法。 6. com_taobao_android_dexposed_DexposedBridge_hookMethodNative (JNI入口),把Java层传递的信息构造成DexposedInfo信息,然后设置hook方法accessFlags设置为ACC_NATIVE ,即native方法,并且指定nativeFunc函数 ( 为什么会这么做: method的结构体表示了一个Java层函数, 而其中的accessFlags属性如果是ACC_NATIVE , 则dvm在调用原Java函数的时候, 会转向调用属性nativeFunc 所指向的函数)。 7. native层用dvm的各种函数来操作Method的指针和对象来控制函数,最后通过反射调用handleHookedMethod回到Java层的方法handleHookedMethod,回到Java世界。阿里 Dexposed 热修复原理_小嵩的博客-CSDN博客_dexposed原理
主要分为Java层和Native层的,通过下图一目了然:
第一、首先我们来分析一下Java层的DexposedBridge.java类
这个方法是一个native类型的。
参数说明:
1)需要hook的方法对象
2)需要hook的方法所属的类
3)方法的slot值,关于这个slot的含义就是方法中局部变量存储的最小单位,一个Slot可以存放一个32位以内的数据类型.在Java程序编译为Class文件时,在方法的Code属性的max_locals数据项中确定了该方法所需要分配局部变量表的最大容量.
4)额外附加信息,比如我们需要hook方法的回调的对象,hook方法的返回类型,参数类型等信息,下面看到hookMethodNative方法的调用地方。
handleHookedMethod方法是整个Dexposed框架Java层最核心的一个方法,这个方法就是用来替换我们需要hook的那个方法,具体如何替换的等下面说到native层再说。然后这个方法中做了三件事:
1、执行需要hook之前的所有回调方法beforeMethod
2、执行被hook的原生方法
3、执行需要hook之后的所有回调方法afterMethod
第二、上面分析完了DexposedBridge.java核心类,下面来看一下native层的实现 dexposed.cpp
1、首先在JNI_OnLoad函数中做了三件事:
1)获取设备信息dexposedInfo
2)注册JNI方法(com_taobao_android_dexposed_DexposedBridge_hookMethodNative)
3)初始化信息(获取Java层DexposedBridge中方法的Method对象)
2、然后在com_taobao_android_dexposed_DexposedBridge_hookMethodNative函数中主要做了两件事:
1)把Java层传递的信息构造成DexposedInfo信息
2)设置hook方法为native,并且指定nativeFunc函数
3、最后在执行第二步中的nativeFunc函数dexposedCallHandler函数中主要做了两件事:
1)获取刚刚构造的DexposedInfo信息
2)调用Java层DexposedBridge.java中的handleHookedMethod方法
所以我们在整个过程中可以看到,先通过JNI注册,从Java世界转到Native世界,然后在native世界中主要修改被hook方法的一些信息,然后在通过反射调用handleHookedMethod回到Java世界。Android中免Root实现Hook的Dexposed框架实现原理解析以及如何实现应用的热修复_尼古拉斯.赵四的博客-CSDN博客_dexposed
三、Epic原理直接看作者的讲解:
我为Dexposed续一秒——论ART上运行时 Method AOP实现 | Weishu's Notes
Xposed原理:Xposed原理简介及其精简化 - 简书
Xposed 实现原理分析_l0neman 的博客-CSDN博客_xposed原理
Dexposed原理Android中免Root实现Hook的Dexposed框架实现原理解析以及如何实现应用的热修复_尼古拉斯.赵四的博客-CSDN博客_dexposed
Epic原理我为Dexposed续一秒——论ART上运行时 Method AOP实现 | Weishu's Notes