环境:
已root手机一枚
Android Studio一枚
官方文档参考 这里 .
准备工作
我们需要事先下载一个 Xposed installer 安装在手机上,用来管理所有的模块.
安装完成后打开:
点击 框架
,
点击 安装/更新
安装框架,
点击确定重启,框架界面是这样的:
编写新模块
打开android studio,新建工程,选择 Add no activity
新建完成后,找到 app
目录下的 build.gradle
文件,将 dependencies
中的
compile fileTree(dir: 'libs', include: ['*.jar'])
改为:
provided fileTree(dir: 'libs', include: ['*.jar'])
下载 XposedBridgeApi-54.jar 并放入app目录下的libs文件夹.
在 AndroidManifest.xml
文件的 application
中添加如下代码,其中的54是前面下载的文件中的号码.
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="kiya's test module" />
<meta-data
android:name="xposedminversion"
android:value="54" />
新建一个 Test
类,写入:
package space.kiya.xposedtest;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class Test implements IXposedHookLoadPackage{
@Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
XposedBridge.log("loaded: " + loadPackageParam.packageName);
}
}
新建 assets
文件夹,在里面新建文件名为 xposed_init
,写入刚刚的类名,此处应为 space.kiya.xposedtest.Test
.
这时就可以编译安装了.
测试
因为工程没有activity,所以在桌面上看不到该应用。
来到 xposed installer
的 模块
中,可以看到我们的模块出现在这里,现在勾选它:
在重启使之生效之前,我们在logcat新建一个tag为 Xposed
的过滤器,这样就可以过滤出模块输出的log.
大概是这样的:
Loading Xposed v54(for Zygote)...
Loading modules from /data/app/space.kiya.xposedtest-1.apk
Loading class space.kiya.xposedtest.Test
Loaded: android
...
这样的日志在 xposed installer
的 日志
中也是可以看到的.
如果log中出现了错误:
java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
说明是前面步骤中没有修改 build.gradle
导致的.
xposed怎样工作?
开机时, ./init.rc
脚本文件会启动 Zygote
进程,Zygote对应的具体程序是 /system/bin/app_process
,然后加载需要的类,调用初始化的方法,之后启动的每个应用都是Zygote的拷贝,所以Zygote进程是十分重要的.
通过在类路径中添加一个jar包,在 app_process
的特定位置调用jar包中的方法,Xposed框架实现了带扩展功能的 app_process
,然后将原有的 app_process
替换掉.
在 /data/data/de.robv.android.xposed.installer/bin/
目录下有一个 XposedBridge.jar
文件,它就是被引用的jar包,源码在 github ,main函数在 /src/de/robv/android/xposed/XposedBridge.java
中,每个进程每次启动时都会被调用.加载模块的功能也是在这里实现.
Xposed真正强大的是它可以hook调用的方法.当你反编译修改apk时,你可以在里面插入xposed的命令,于是你就可以在方法调用前后注入自己的代码.
XposedBridge有一个私有的本地方法 hookMethodNative
,代码实现放在 app_process
中.在调用被hook的方法前会先调用此方法, hookMethodNative
有一个 handleHookedMethod
方法,可以修改传递给被hook函数的参数,变量甚至是调用其他方法.