Xposed模块开发

  最近突然看到了Xposed这一项技术,觉得蛮有意思的,现在的蚂蚁森林自动收能量以及微信自动回复等都是通过这个来实现的,因此记录一下Xposed的基本实现。

Xposed框架介绍

概述

  Xposed框架是一款开源框架,其功能是可以在不修改APK的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。Xposed 就好比是 Google 模块化手机的主体,只是一个框架的存在,在添加其他功能模块(Modules)之前,发挥不了什么作用,但是没了它也不行。也正因为如此,Xposed 具有比较高的可定制化程度。

工作原理

  Xposed框架主要通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。与采取传统的Inhook方式相比,Xposed在开机的时候完成对所有的Hook Function的劫持,在原Function执行的前后加上自定义代码。
  为什么需要这么做呢?
  Android基于Linux,第一个启动的进程自然是init进程,该进程会启动所有Android进程的父进程——Zygote(孵化)进程,该进程的启动配置在 /init.rc脚本中,而Zygote进程对应的执行文件是/system/bin/app_process, 该文件完成类库的加载以及一些函数的调用工作。在Zygote进程创建后, 再fork出SystemServer进程和其他进程。Xposed Framework,就是用自己实现的app_process替换掉了系统原本 提供的app_process,加载一个额外的jar包,然后入口从原来的: com.android.internal.osZygoteInit.main()被替换成了: de.robv.android.xposed.XposedBridge.main(),
然后创建的Zygote进程就变成Hook的Zygote进程了,而后面Fork出来的进程 也是被Hook过的。
  这个Jar包在: /data/data/de.rbov.android.xposed.installer/bin/XposedBridge.jar 目录下。
  通过原理我们可以看出,要使用Xposed框架,那么手机必须要拥有最高权限(就是root权限),当然现在还出现了VirtualXposed,这个框架的话就相当于给你的手机开了一个平行空间,这个空间和你的手机系统一样,就相当于一个副本,所以当你在这个空间使用xposed的话,就不需要root,但是在这个空间你需要重新安装你想修改的程序,因为它刚创建出来的时候是什么都没有的,也因此你在这个空间修改并不会影响到你的手机本来的应用,就相当于双开应用。
  值得注意的是,既然给出了最高权限,那么别人就可以做很多坏事了,比如获取你的账号密码,还有一些私密的文件,因此对于别人写的Xposed模块可以看看他是不是开源的再决定用不用,如果不是开源的,建议不要使用。当然如果不想承担这么大的风险又不嫌麻烦的话,可以使用上面介绍的virtualXposed框架。

环境要求

Configuration RequireMent
硬件 安卓手机或者模拟器
软件 PC:Android studio  手机:xposed框架app
Root Access 因为Xposed工作原理是在/system/bin目录下替换文件,在install的时候需要root权限,但是运行时不需要root权限。
版本要求 需要在Android 4.0以上版本的机器中

Xposed资源梳理

  • XposedBridge.jar:XposedBridge.jar是Xposed提供的jar文件,负责在Native层与FrameWork层进行交互。/system/bin/app_process进程启动过程中会加载该jar包,其它的Modules的开发与运行都是基于该jar包的。
    注意:XposedBridge.jar文件本质上是由XposedBridge生成的APK文件更名而来。
  • Xposed:Xposed的C++部分,主要是用来替换/system/bin/app_process,并为XposedBridge提供JNI方法。
  • XposedInstaller:Xposed的安装包,负责配置Xposed工作的环境并且提供对基于Xposed框架的Modules的管理。在安装XposedInstaller之后,app_process与XposedBridge.jar放置在了/data/data/de.robv.android.xposed.installer。
  • XposedMods:使用Xposed开发的一些Modules,其中AppSettings是一个可以进行权限动态管理的应用

Xposed模块实现例子

  从本质上来讲,Xposed 模块也是一个 Android 程序。但与普通程序不同的是,想要让写出的Android程序成为一个Xposed 模块,要额外多完成以下四个硬性任务:

  1. 让手机上的xposed框架知道我们安装的这个程序是个xposed模块。

  2. 模块里要包含有xposed的API的jar包,以实现下一步的hook操作。

  3. 这个模块里面要有对目标程序进行hook操作的方法。

  4. 要让手机上的xposed框架知道,我们编写的xposed模块中,哪一个方法是实现hook操作的。

&emsp: 对应上面的四个步骤我们需要做的修改有:

  1. AndroidManifest.xml

  2. XposedBridgeApi-xx.jar 与 build.gradle

  3. 实现hook操作的具体代码

  4. xposed_Init

  按照上述顺序一个一个实现,就能完成我们的第一个Xposed模块编写:

修改AndroidManifest.xml

  首先我们新建了一个空项目,然后在布局文件中定义了一个按钮,点击效果为Toast出文字“我未被劫持”。将其先安装到手机或者模拟器上。
  基于以上的项目,首先想要我们写的app能够被识别成一个xposed模块的话,我们需要修改AndroidManifest.xml文件,如下:

Xposed模块开发_第1张图片
  插入之后,把手机连上AndroidStudio ,点击“编译”或者“运行”的话,手机就会启动刚刚编写的这个程序。而在手机里的Xposed框架中也会显示出这个模块:
Xposed模块开发_第2张图片
  这说明Xposed框架已经认出了我们写的程序,但是现在这个模块什么都没有做,因为我们还没有做出修改。

配置XposedBridgeApi-xx.jar 与 build.gradle

  从上面的工作原理可以看出来,实现一个xposed模块,那必须需要XposedBridgeApi-xx.jar这个jar包来提供修改的文件,因此这一步的关键是下载XposedBridgeApi-xx.jar包并且将其放到libs工程目录中,当然这是一种方法,不过在Android studio不用这么麻烦,因为Android studio可以通过修改build.gradle来将其集成进来,插入以下代码:

repositories {

jcenter()

}

以及

compileOnly 'de.robv.android.xposed:api:82'

compileOnly 'de.robv.android.xposed:api:82:sources'

  如下:
Xposed模块开发_第3张图片
  这句代码是告诉AndroidStuido使用jcenter作为代码仓库,从这个仓库里远程寻找 de.robv.android.xposed:api:82 这个API,我们不用自己找XposedBridgeApi.jar了。
  注意!此处要用compileOnly这个修饰符!网上有些写的是provide ,现在已经停用了!)

实现hook操作修改

  在MainActivity的同级路径下新建一个类“HookTest.java”,代码如下:

package com.example.root.xposd_hook_new;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class HookTest implements IXposedHookLoadPackage {
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
      if (loadPackageParam.packageName.equals("com.example.root.xposd_hook_new")) {
          XposedBridge.log(" has Hooked!");
          Class clazz = loadPackageParam.classLoader.loadClass("com.example.root.xposd_hook_new.MainActivity");
          XposedHelpers.findAndHookMethod(clazz, "toastMessage", new XC_MethodHook() {
              protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
              super.beforeHookedMethod(param);
           //XposedBridge.log(" has Hooked!");
          }
              protected void afterHookedMethod(MethodHookParam param) throws Throwable {
              param.setResult("你已被劫持");
          }
     });
   }
  }
}

  如图:
Xposed模块开发_第4张图片
  通过IXposedHookLoadPackage接口中的handleLoadPackage方法来实现Hook并篡改程序的输出结果的:

  • 代码中“com.example.root.xposd_hook_new ”是目标程序的包名;
  • ”com.example.root.xposd_hook_new.MainActivity” 是想要Hook的类;
  • “toastMessage”是想要Hook的方法。

  我们在afterHookedMethod方法(用来定义Hook了目标方法之后的操作)中,修改了toastMessage()方法的返回值为“你已被劫持”。

xposed_init文件

  右键点击 “main ” 文件夹 , 选择new –> Folder –>Assets Folder,新建assets 文件夹:然后右键点击 assets文件夹, new–> file,文件名为xposed_init(文件类型选text),并在其中写上入口类的完整路径(就是自己编写的那一个Hook类),这样, Xposed框架就能够从这个 xposed_init 读取信息来找到模块的入口,然后进行Hook操作了,如图:
Xposed模块开发_第5张图片
  注意:最后选择禁用 Instant Run: 单击 File -> Settings -> Build, Execution, Deployment -> Instant Run,把勾全部去掉。因为如果勾选了Instant Run的话,
Xposed模块开发_第6张图片
  最后我们将程序运行到手机上,打开xposed框架,然后勾选我们创建的这个模块,重新打开应用,就会发现:
Xposed模块开发_第7张图片
  这说明我们的修改已经生效了,当然这只是最简单的对于Xposed模块的开发,举一反三,既然我们都可以修改一个应用的返回值,那么我们可以修改的东西可不止这么一些简单的东西,基于此,那么实现自动收能量、自动回复就都是可能的,当然还有一些数据的修改只需要将返回值修改不就实现了吗。
  在GitHub上这两个app源码可以向我们展示怎么hook类的变量、静态变量、公有方法、私有方法、静态方法、内部类、多复杂参数的方法、内部类的变量等。
  原始程序:https://github.com/Gordon0918/XposedHookTarget ;
  hook修改源程序地址:https://github.com/Gordon0918/XposedHook 。
  通过对比,就能发现上述这些是怎么被hook的。
  更深的了解以及实际应用的话可以看这篇帖子:https://www.jianshu.com/p/51dcc24900ba (技术文哦,当初看到这篇文章我才发现还有这么一个东西)。

你可能感兴趣的:(android)