xposed是什么?
一个很牛逼的框架,可以在不修改APK的情况下影响程序的运行,比如:
- 直接把APP的界面改成自己想要的样
- 去掉界面里不喜欢的东西,
- 自动抢红包
- 消息防撤回
- 步数修改等等
Xposed的工作原理
在开始修改之前,你应该大致了解Xposed如何工作(如果你觉得太无聊,你可以跳过这一部分)。方法如下:
有一个叫做“Zygote”的过程。从它的名字(中文含义——受精卵)这是Android运行时的核心。每个应用程序都作为它的副本(“fork”)启动。/init.rc
手机启动时,脚本会启动此过程。进程开始完成/system/bin/app_process
,加载所需的类并调用初始化方法。
这就是Xposed发挥作用的地方。安装框架时,会将扩展的app_process可执行文件复制到/system/bin
。这个扩展的app_process就会把XposedBridge.jar加载到运行时环境,这样我们就可以在虚拟机启动之前,甚至是在Zygote的main方法被执行之前做一些爱做的事(捂脸,其实就是加载插件)。此时我们的插件被执行,就是Zygote进程的一部分,所以可以直接获取到应用的上下文Context,然后做很多超出想象的事情——对于任何一个app ,我们都可以hook或者替换掉其中的类或方法或对象。再加上已经root。我们可以为所欲为了。
jar位于,/data/data/de.robv.android.xposed.installer/bin/XposedBridge.jar
其源代码可在此处找到。查看类XposedBridge,您可以看到该main
方法。这就是我上面写的内容,这个过程在一开始就被调用了。在那里进行了一些初始化,并且还加载了模块(稍后我将回到模块加载)。
方法挂钩/更换
真正创造Xposed力量的是“钩”方法调用的可能性。通过反编译APK进行修改时,可以直接在任意位置插入/更改命令。但是,您需要在之后重新编译/签署APK,并且您只能分发整个包。使用可以放置Xposed的钩子,你不能修改方法内的代码(不可能清楚地定义你想在哪个地方做什么样的改变)。相反,您可以在方法之前和之后注入自己的代码,这是Java中可以清楚解决的最小单元。
XposedBridge有一个私有的本机方法hookMethodNative
。此方法也在扩展中实现app_process
。它会将方法类型更改为“native”,并将方法实现链接到其自己的本机通用方法。这意味着每次调用hooked方法时,都会调用泛型方法,而不会让调用者知道它。在此方法中,handleHookedMethod
调用XposedBridge中的方法,将参数传递给方法调用,this
引用等。然后,此方法负责调用已为此方法调用注册的回调。这些可以更改调用的参数,更改实例/静态变量,调用其他方法,对结果执行某些操作...或者跳过任何内容。它非常灵活。
安装:
一、安装XposedInstalle(Xposed安装程序)
XposedInstalle.apk下载链接(安卓5.0以下不用这个,自己找去吧):
下载地址,论坛下面有下载地址
下载完软件打开:
如果点击半天还是等待可以换一种方式安装
二、卡刷:
1、下载
SDK版本 | 安卓版本 |
---|---|
SDK21 | Android 5.0(Lollipop) |
SDK22 | Android 5.1 (也是Lollipop) |
SDK23 | Android 6.0(Marshmallow) |
SDK24 | Android 7.0 |
SDK25 | Android 7.1 |
SDK26 | Android 8.0 |
SDK27 | Android 8.1 |
看到上图里的平台了吗?我是arm64,记住了然后下载的时候选择用
框架的下载链接
暂时我还没发现签名有何用,我只下载了框架,以后发现了用处我再写
** 更新,中间出了点问题,代码当时也有问题,索性重装了一遍带着签名装好的,所以能带签名最好带着签名吧 **
二、安装
将下载好的压缩包放到手机根目录(前提装好adb,或者用其他方式发到手机)
adb push xposed-v90.1-sdk27-arm64-beta3-.zip /sdcard
开机按住开机键
和音量+键
进入recovery(小米的进入方式,其他手机自己查),
点击安装, 选择压缩包,滑动刷入
安装完重启后我的手机一直卡在开机界面,等了半天也没反应,我就强制启动了,打开软件显示我框架已经安装了。
开发模块
一、创建Xposed模块
首先需要知道,Xposed模块是以APK的格式提供的,本身也是需要安装到手机上的,也像普通应用一样可以启动,只是因为APK中包含了一些声明,被Xposed框架检测到了,所以同时也可以以Xposed模块的方式来进行hook操作。那么这些声明是什么呢?
在AndroidManifest.xml中添加下面的声明,
meta-data
中的内容分别用于声明是否为插件,插件的描述和兼容的最低Xposed版本。加入3个meta-data
就好了。
二、添加依赖
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.sxkj_mg.xposeddome"
minSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
// 主要是下面这两行,再下面的是自动生成的
compileOnly 'de.robv.android.xposed:api:82'
//如果需要引入文档,方便查看的话
compileOnly 'de.robv.android.xposed:api:82:sources'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
三、创建xposed_init
在图片位置创建xposed_init,写入代码为:
# 我的是这个,你们根据自己的路径改,最后一个是文件名,一会创建这个文件
com.example.sxkj_mg.xposeddome.HookModule
修改MainActivity.java
package com.example.sxkj_mg.xposeddome;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=findViewById(R.id.tv);
tv.setText("我是渣渣辉");
}
}
编写HookModule
package com.example.sxkj_mg.xposeddome;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.lang.reflect.Field;
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 HookModule implements IXposedHookLoadPackage {
public static final String TAG = "MyHook";
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.d(TAG, "重启手机后,我执行了,说明这个 Xposed 模块生效了");
if (loadPackageParam.packageName.equals("com.example.sxkj_mg.xposeddome")){
Log.d(TAG, "进入到这个app了");
XposedHelpers.findAndHookMethod("com.example.sxkj_mg.xposeddome.MainActivity",loadPackageParam.classLoader,
"onCreate", Bundle.class,new XC_MethodHook(){
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
Log.d(TAG, "这里是hook方法之前");
super.beforeHookedMethod(param);
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable{
Log.d(TAG, "这个是hook方法之后");
Class c= loadPackageParam.classLoader.loadClass("com.example.sxkj_mg.xposeddome.MainActivity");
Field field = c.getDeclaredField("tv");
field.setAccessible(true);
Log.d(TAG, "这次到这里了2");
TextView tv = (TextView) field.get(param.thisObject);
tv.setText("王境泽");
}
});
}
}
}
此时运行一下,就装到手机上了。(前提USB连接手机)
手机打开,是不是还是渣渣辉,然后XposedInstalle启用模块后,手机重启,就显示王境泽
了。
API介绍
IXposedHookLoadPackage接口:App被加载的时候调用,用于App应用的Hook
回调方法是:handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam)XC_LoadPackage.LoadPackageParam:包含与正在加载的应用程序的有关信息。
-
XposedHelpers.findAndHookMethod(要Hook的类,classLoader,方法名,参数,回调对象)
- Hook一个方法的时候使用,回调对象XC_MethodHook()需重写两个方法
- beforeHookedMethod(MethodHookParam param):方法调用前执行
- afterHookedMethod(MethodHookParam param) 方法调用后执行
- 注:可以调用param.setResult()设置方法的返回值!
MethodHookParam:包含与调用方法有关的信息
比较关注的是这个thisObject,代表调用该方法的对象实例,如果是静态方法
的话,返回一个Null,比如这里调用onCreate()方法的是MainActivity,获得
的自然是MainActivity实例。
接着是获取成员变量,分为私有与非私有变量,非私有直接调用下述方法
即可获得class
Class c = lpparam.classLoader.loadClass("com.coderpig.cpwechatxposed.MainActivity");
Field field = c.getField("tv");
如果是私有,则需要先设置访问权限(setAccessible)
Class c = lpparam.classLoader.loadClass("com.coderpig.cpwechatxposed.MainActivity");
Field field = c.getDeclaredField("tv");
field.setAccessible(true);
接着调用获得该对象
TextView tv = (TextView) field.get(param.thisObject);
tv.setText("贪玩难约");
代码外内容
IXposedHookZygoteInit:在Zygote启动时调用,用于系统服务的Hook
回调方法initZygote()IXposedHookInitPackageResources:在资源布局初始化时会回被执行(inflate方法)
回调方法:handleInitPackageResources(XC_InitPackageResources.InitPackageResourcesParam resparam)InitPackageResourcesParam包含两个参数,包名和XResource(资源相关)
有了这个XResource对象,就可以拿到布局资源树了,通过重写hookLayout方法,LayoutInflatedParam,里面这个view就是布局资源树了,你可以拿到遍历,拿到某个特定控件,然后做一些骚操作。
-
XposeHelpers提供了一些辅助方法
callMethod(Object obj,String methodName, Object… args):在APP中调用特定方法; 参数依次是:调用方法的所在类,调用方法名,方法参数
findClass(String className,ClassLoader classLoader):获取class类实例
参数依次是类名,类加载器findMethodExact:通过反射查找类的成员方法(可setAccessible(true)设置非私有)
findConstructorExact:通过反射查找构造函数(同样可设置可访问下性)
findAndHookXXX:查找并Hook
setXxx:通过反射设置对象数据成员的值
setStaticXxx:通过反射设置静态变量的值
XposedBridge.log(“日志内容”):输入日志和写入到/data/xposed/debug.log
Xposed Installer日志那里可以看到!
内部类:通过$符号链接内部类
只能Hook方法与构造方法,不能Hook接口和抽象方法
通过这些api是不是大概清楚Xposed能干啥了,除了Xposed,还有其他的框架可以干这些事比如下面:
Magisk框架,Xposed框架比较,VirtualXposed框架
框架 | Magisk | Xposed | Vxp |
---|---|---|---|
平台 | android5.0~8.1 | android4.4以下,android5.0 ~ 8.1,但是8.0~8.1稳定版还没出来,出来的beta版本 | android5.0~9.0 |
模拟器,真机支持情况 | 都支持 | 都支持 | 不支持 x86,也就是不支持模拟器 |
更新情况 | 更新快一直在更新 | 已经停更了 | 框架一直在更新 |
稳定性 | 模块少,但是可以装systemless版Xposed模块来弥补 | 最稳定、模块最多 | 不会变砖、模块少 |
激活模块 | 必须重启激活模块 | 必须重启激活模块 | 支持免重启手机激活模块 |
root | 内置ROOT | 需要root | 免root |
hook | 支持 | 支持 | 暂不支持资源以及系统api的HOOK 使用必须将需要 hook 的 APP 和模块 APP 安装到VirtualXposed |
github地址 | Magisk | Xposed | VirtualXposed |
原理 | 对系统侵入较少,仅修改boot.img,同时能够对系统隐藏自身存在,支持OTA升级,可以实现Multirom多系统等功能 | Xposed框架的原理是通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik或者art虚拟机的劫持 | 它去启动别的App,在启动过程中通过 epic Hook本进程,从而控制被启动的App |
部分抄袭此博客
部分抄袭此博客