Xposed模块开发基本方法记录
由于某些课程实验的要求,需要通过xposed框架对某应用进行hook操作,笔者选用了开源且免费的xposed框架进行实现。虽然网上存在一些利用xposed实现特定功能的文章资源,但大多均将xposed模块的构建作为一个小节内容一笔带过,而且介绍的内容随着考虑的因素、使用的编辑环境不同也大有区别,使得笔者在实际构建过程中往往提心吊胆,出现了错误也不知道如何去改正。故而这里特将笔者最近摸索和学习到的简单xposed构建的知识记录,以供查阅和参考。
Xposed 框架
想要使用Xposed模块实现特定的功能,必须依赖Xposed框架,正如 apk 的运行需要Android系统提供支持一样,Xposed模块任务的完成也离不开Xposed框架的支持,Xposed框架提供了Xposed模块运行所必需的环境和功能接口,同时也可以对系统上已安装的模块进行禁用、卸载等管理。故而在想通过Xposed模块完成一定任务之前,必须安装Xposed框架。
Xposed框架Installer下载地址:http://repo.xposed.info/module/de.robv.android.xposed.installer,安装的过程可参考网络资料。
注意:由于Xposed框架安装时需要将系统文件夹/system/bin的部分文件进行替换和备份,故而手机需要具备root权限。
Xposed 模块
下面以Android Studio 3.0.1为例,总结下简单的Xposed模块的编写所需的配置和注意事项。
项目创建
Xposed模块实际上是作为一种较为特殊的apk安装在系统上,由于Xposed 模块的功能通常借助于其他应用和系统资源实现,其一般没有应用界面,故而创建一个没有活动的项目即可。
A.在Android Studio中,点击 file -> new -> new project 进行新项目的创建。指定应用名称、公司域名、存储位置和包名等信息,这里需要注意应用名和包名这两个名字;
B.勾选 Phone and Tablet 选项,选择该 Xposed 模块( 实际就是apk)将要运行的 Android 环境所对应的 API。注意这里的API指定的是Android环境与apk之间交互的接口,只有该API与之后apk实际运行的Android环境相匹配,apk才能正确的安装和运行。如笔者的 Xposed 模块将要运行在 Android 4.4上,则应该选择 Android 4.4 对应的API 19.
C.在接下来的界面中,选择“ add no activity ”即不添加活动( Xposed 模块不需要活动 ),即可完成项目的创建。
项目配置
Xposed模块被视为一种特殊的apk,故而在创建项目之外,还需要针对其进行 Xposed 模块相关的配置。
A. 切换目录结构。点击界面左上方的竖式 Project,展开项目界面,将项目结构从 Android 切换至 Project 模式,方便之后的编辑;
B. 添加 Xposed API依赖。Xposed 模块的功能借助 Xposed 框架实现,Xposed 模块通过对应的 Xposed 框架 API 来使用 Xposed 框架提供的功能。想要使用 Xposed 框架 API,则必须提供对应的库( 名为 XposedBridge API jar)的路径等信息。(以下信息来自 Using the Xposed Framework API )
*针对 Android Studio
Android Studio 中使用gradle进行项目的构建,故而想要使用 Xposed 框架 API 对应的库,则需要在 gradle 的配置文件中进行指定。在 应用名(test) -> app -> build.gradle 中加入以下内容:
repositories { //通常新项目的 build.gradle 中不包含有repositories块,直接在空白处增加1-3行即可
jcenter(); } dependencies { //通常 build.gradle 文件中已包含dependncies块,所以只需将第6行的内容添加进已有的 dependencies 中即可
provided 'de.robv.android.xposed:api:53'
provided 'de.robv.android.xposed:api:53:sources' //该行是可选的,用于下载API相关的文档等信息
}
其中,第2行表示将 jcenter 作为代码仓库,可在上面引用开源项目,而第 6 行则指定引用项目的项目名和版本信息。
第6行的声明需要注意两点:
a) 使用 provided 关键字而不是 compile,后者会将引用的 Xposed 框架 API 类打包至生成的 apk 中,而这些类在安装好的 Xposed 框架中是已经存在的,所以可能会产生冲突,而 provided 关键字则仅保留对 API 的引用,实现具体功能的类则由安装好的 Xposed 框架提供;
b)使用系统对应的 Xposed 框架 api 版本,不同的 Xposed 框架 API 在不同的 Android 环境中发挥作用。如Android 4.x 环境则只能选择 API 53。
*针对 eclipse
eclipse 环境下无法通过指定 jcenter 中的开源项目来实现对其的引用,所以必须在实际的项目中手动添加所需引用的库文件 XposedBridge API jar 的路径,在这里手动下载所需的 API 版本,将其复制到项目的文件夹下( 注意不要放置在项目本身已经有的 lib / libs 文件夹下,原因与Android Studio环境下使用 provided 而不是 compile 一致 ),选中 jar 包 右键 -> Build Path -> add to build path 即可。
C. Android Studio 环境下需要禁用 Instant run 。在 File -> Settings -> Build, Execution, Deployment -> Instant Run 中取消其勾选,否则源程序中的类会由一个 stub 应用加载,而不是直接包含在 apk 文件中,而 Xposed 框架目前无法处理这样的情况。
D. 修改 AndroidManifest.xml 文件中的属性。在 应用名(test) -> app -> src -> main 文件夹中找到 AndroidManifest.xml,修改其中的属性,使得我们最终生成的 apk 能够被 Xposed 框架识别。请保证最终文件的部分内容为以下格式。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" > // App相关的信息 <meta-data
android:name="xposedmodule" //标志该 apk 为一个 Xposed 模块,供 Xposed 框架识别
android:value="true" />
<meta-data
android:name="xposedminversion"
android:value="53" /> //xposed最小版本号,请与(2)步中选用的api版本保持一致
<meta-data
android:name="xposeddescription"
android:value="hook a function" /> //针对该模块的描述,会在Xposed框架的模块管理界面中显示出来,便于模块管理 </application>
完成上述步骤后,则可将项目文件打包成 apk ( Android Studio 下打包 apk 的简单步骤可以参见这里),并在手机中安装。安装成功后,在 Xposed 框架的模块管理界面会出现该模块对应的管理项,证明对 Xposed 模块的配置是成功的。勾选对应的模块,并重启设备,重启之后该模块则开始发挥功能。当然目前我们并没有实现任何功能。
简单示例
在完成 Xposed 框架的配置后可在该项目中进行框架功能的编写。在 应用名(test) -> app -> src -> main -> java 目录下,可以看到 Android Studio 已经自动根据我们在创建项目时指定的包名生成了一个包( package )的条目,如笔者项目中的包名为 xposed.test(见创建项目时的界面截图),选中该包右键 -> new -> java ->class ,创建自己的一个 class ,如 test.class 。用户可在该 class 中实现简单的xposed hook功能。
( 以下部分不涉及具体的实现原理,仅提供函数的简单功能的描述,更多关于Xposed 框架API的功能可在这里查看)
一个 Xposed 模块可以有多个不同的入口,其中实现的方法既可以在 Android 系统启动时被调用,也可在一个应用程序包被加载时被调用,想要在不同的时期被调用,则该功能类需要实现不同的接口。
Xposed公共接口
package:de.robv.android.xposed.IXposedHookZygoteInit
interface :IXposedHookZygoteInit //在Android系统启动时被调用,作用于初始的zygote进程,可用于实现应用于所有应用的hook package:de.robv.android.xposed.IXposedHookLoadPackage
interface:IXposedHookLoadPackage //当指定应用被加载时被调用,一般用于hook特定应用的方法 package:de.robv.android.xposed.IXposedHookInitPackageResources
interface:IXposedHookInitPackageResources//指定应用的资源进行初始化时被调用,一般用于资源的替换
以实现 IXposedHookLoadPackage 接口的模块为例,实现一个简单的hook功能。
通常使用 findAndHookMethod 方法来定位待 hook 的类中的方法(官方解释在这里)
findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback)
className:被hook的方法所在类的完整名称,包括 包名 + 类名
classLoader:可通过 lpparam.classLoader 获得
methodName:被hook的方法的名,注意如有混淆,则应该用混淆后的名字
object... 与为被hook的方法的参数对应
Callback :指定该方法被调用时,需要被执行的回调
例如,想要hook如下代码,即hook包 com.test.example 中的类 a 下的 b 方法
package com.test.example
public class a{
public int b(String s, int i, MyClass m)
{}
}
则对应的 findAndHookMethod方法应该写作
findAndHookMethod("com.test.example.a", lpparam.classLoader,"b", String.class, int.class, "com.test.example.MyClass", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
do somthing
}
});
这里需要注意:
(1)对于待hook函数中的java自带类型的参数,如 int 和 String,则应使用 int.class 和 String.class 作为findAndHookMethod的参数
(2)若待Hook函数中包含有形如 MyClass 这样的自定义类型的参数,则直接使用该类型的完整路径名即可,如 "com.test.example.MyClass"
在 findAndHookMethod 方法的参数中,直接定义了一个 XC_MethodHook 回调,其中一般有两个方法可供使用者重新定义。
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// 该方法在被hook函数之前被调用
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 该方法在被hook函数之后被调用
}
以下代码实现了微信的一个日志函数的简单 hook 。
package xposed.xposed_wechat_log; //实现的类所在的包 import android.util.Log; //系统提供的Log方法的包
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; //findAndHookMethod方法所在的包
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; public class test implements IXposedHookLoadPackage { //test类实现了IXposedHookLoadPackage接口
@Override
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { // handleLoadPackage 在任意包被加载时被调用,参数lpparam,包含有加载的 app 的信息
if ( lpparam.packageName.equals("com.tencent.mm")) { // 可通过 lpparam 中包含的包信息对包进行筛选,如这里表示 com.tencent.mm 包加载时,才执行下一步操作
findAndHookMethod("com.tencent.mm.sdk.platformtools.x",lpparam.classLoader, "d" , String.class, String.class, Object[].class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String str0 = (String) param.args[0]; //可通过 param.args[i]获得 hook 方法的参数
String str1 = (String) param.args[1];
Object[] obj2= (Object[]) param.args[2];
String str = obj2 == null ? str1 : String.format(str1, obj2); if( str==null)
str = ""; Log.e( "Xposed_hook_d"+str0,str);
super.beforeHookedMethod(param);
}
});
}
}
}
simple_hook
完成上述模块功能的编写后,需在 应用名(test) -> app -> src -> main 目录下新建一个 assets 目录,并在该目录下建立一个名为 exposed_init 的文本文件。该文件中记录模块中所有实现了Xposed 功能接口的类的完整路径名,每一行书只写一个这样的路径。
如在上述实例模块中,test 类实现了接口 IXposedHookLoadPackage,则 exposed_init 文件中应该有以下内容:
xposed.test.test //其中 xposed.test 为包名,test为实现接口的类名
所有实现了 Xposed 接口的类均要在该文件中记录,以供 Xposed 框架进行处理。
之后即可打包完成的项目,将其安装至设备上进行验证了。
参考资料:
1. [TUTORIAL]Xposed module development详细的xposed模块开发示例
2. Using the Xposed Framework API关于如何在模块中使用Xposed框架提供的API
3. Development tutorial简单的xposed模块示例
Xposed模块开发基本方法记录的更多相关文章
- Xposed模块开发学习记录
Xposed模块相关API可以参考在线文档: https://api.xposed.info/reference/packages.html 入门教程可以参考: https://github. ...
- Xposed模块开发教程
转:http://vbill.github.io/2015/02/10/xposed-1/ http://blog.csdn.net/zhangmiaoping23/article/detai ...
- 安卓手机安装虚拟定位的方法Xposed安装器+模拟位置(Xposed模块)
原文:https://www.52pojie.cn/thread-571328-1-1.html 未测试,据说只支持某些手机,小米和华为很难安装,建议买其他品牌. Xposed安装器步骤:·ROOT你 ...
- python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheetahcherrypy:一个WEB frameworkctype ...
- Qt开发的应用记录读取用户习惯设置的方法
Qt开发的应用记录读取用户习惯设置的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/w ...
- javascript的模块开发方法;
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- js模块开发(一)
现在嵌入页面里面的javascript代码越来越复杂,于是可能依赖也越来越严重,使用别人开发的js也越来越多,于是在理想情况下,我们只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. 于是j ...
- 基于ASP.NET MVC的热插拔模块式开发框架(OrchardNoCMS)--模块开发
之前文章中给大家说明了下我这个小小的想法,发现还是有不少人的支持和关注.你们的鼓励是对我最大的支持. 我总结了了大家的评论,有以下几个问题: 1.希望有更多的文档说明. 2.希望介绍下Orchard的 ...
- js模块开发
js模块开发(一) 现在嵌入页面里面的javascript代码越来越复杂,于是可能依赖也越来越严重,使用别人开发的js也越来越多,于是在理想情况下,我们只需要实现核心的业务逻辑,其他都可以加载别人已经 ...
随机推荐
- UOJ #188. 【UR #13】Sanrd
Description 给定 \(\sum_{i=l}^r f[i]\) \(f[i]=\) 把 \(i\) 的每一个质因子都从小到大排列成一个序列(\(p_i^{c_i}\)要出现 \(c_i\) ...
- Common class for judge IPV6 or IPV4
import java.util.regex.Pattern; import org.apache.http.annotation.Immutable; /** * A collection of u ...
- 在Ubuntu16.04.4和Windows10上安装jdk
在Ubuntu16.04.4和Windows10上安装jdk 一.在Ubuntu16.04.4上安装jdk 1.下载jdk安装包 首先我们在oracle官网上下载jdk-8u161-linu ...
- static关键字作用
之前讲到final关键字的作用是每次面试的时候我必问求职者的两个问题之一,另外一个问题就是文本会写到的static.final和static一样,都是一个小问题可以看到一个人的基础是否扎实以及平时是否 ...
- spss C# 二次开发 学习笔记(一)——配置数据源
由于项目的需要,使用Spss进行数据统计分析. Spss对于数据统计分析的功能有多强主要是客户关注的事情,我所主要关注的是,Spss的二次开发有多复杂. 学习的基本思路是: (1)首先了解统计基本知识 ...
- springcloud 集成kafka问题记录,发消息报错:ERROR o.s.kafka.support.LoggingProducerListener - Exception thrown when sending a message with key='null' and payload='{-1,
在springcloud集成kafka,发送消息时报错: 2018-08-15 16:01:34.159 [http-nio-8081-exec-1] INFO org.apache.kafka.c ...
- css 样式加载次序
一般而言,所有的样式会根据下面的规则层叠于一个新的虚拟样式表中,其中数字 4 拥有最高的优先权(本人理解为:先加载1的样式,然后用2的样式覆盖1中的样式,3.4同理) 浏览器缺省设置(浏览器默认的样式 ...
- BZOJ4598: [Sdoi2016]模式字符串(点分治 hash)
题意 题目链接 Sol 直接考虑点分治+hash匹配 设\(up[i]\)表示\(dep \% M = i\)的从下往上恰好与前\(i\)位匹配的个数 \(down\)表示\(dep \% M = i ...
- mac关闭渐隐和弹出动画效果
苹果系统应用程序的窗口和对话框每次使用的时候都有华丽的特效,但是如果你感觉这种特效显得有点慢(MacGG闲的蛋疼),那该如何取消掉他呢? 方法很简单,打开"终端"(Finder-& ...
- Javascript获取For循环所用时间
第一种: let tOne = new Date().getTime(); let n = new Date(); let hour = n.getHours() < 10 ? "0& ...