Xposed快速入门例子(二)----- 调方法的合适时机
本帖最后由 影月 于 2018-8-25 11:30 编辑一、前言
上篇文章已经介绍了如何用Xposed实现调一个小功能的方法(Xposed快速入门例子(一)----- 拉黑好友)
下面补充两点:
1.Android Studio3.0以上已经隐藏了DDMS的功能。DDMS在sdk目录下,/sdk/tools/monitor打开这个文件就可以了。
2.有些手机在DDMS中显示不了进程。需要安装一个apk 。Xposed打上勾,重启手机就可以了。
言归正传,这篇文章介绍Xposed代码的调用时机。我想到了以下两种模式。
二、两种调用方式
1.发送广播
这种方式主要用于测试。
具体思路就是往Xposed模块中注册广播,然后在其它app中发送广播过去。
那么在什么地方注册广播呢? 网上大佬们给的方法很多,但是很多都会出现重复接收的情况。
所以介绍一下我的思路。看以下代码
//注意:这是kotlin代码,kotlin中"=="相当于java中的"equals"
if (lpparam.processName=="com.tencent.mm"){
//在此处注册广播!
val intentFilter = IntentFilter().apply {
addAction("action_pull_black")
}
context.registerReceiver(myReceiver, intentFilter)
}
可以看到注册广播的时候,我是用进程过滤的。因为微信的进程很多,所以不要用包名过滤。这样保证不会收到重复的广播!
/**
* 广播接收器
* */
private val myReceiver = object :BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent) {
if (intent.action=="action_pull_black"){
val wxid = intent.getStringExtra("extra_wxid")
Handle.setBlack(wxid)
}
}
}
通过广播接收器,可以看到收到了一个wxid,直接调拉黑的方法就可以了。
我在app主页,写了一个EditText和一个Button。点拉黑就把广播发送了过去。看以下代码
btn_pull_black.setOnClickListener {
val wxid = et_wxid.text.toString()
if (wxid==""){
Toast.makeText(this, "wxid不能为空!", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
sendBroadcast(Intent().setAction("action_pull_black").apply {
putExtra("extra_wxid", wxid)
})
}
这样这种模式就完成了!
2.hook到微信的方法之后,再调相应的Xposed代码
一般做Xposed模块的项目,主要用到的就是这种模式。
我们可以设想一个实际场景,如果好友说了一句骂人的话,我们就把他拉黑。
所以我们现在要做的就是hook到这个聊天内容和好友的wxid。
如何hook呢。我看大佬们的方法也是千奇百怪。
我觉得做实用的思路就是微信巫师所提供的------trace微信的数据库。
这种方式的好处就是简单明了,不用适配微信的版本。
以下是打开微信的db文件(db文件是加密的,网上有很多解密的方法,请自行百度),通过分析找到了聊天记录的表所在的地方。
我们只要hook插入数据库的方法就可以了。
// Hook SQLiteDatabase to trace all the database operations.
@JvmStatic
fun traceDatabase() {
XposedHelpers.findAndHookMethod(
pkg.SQLiteDatabase, "insertWithOnConflict",
String::class.java, String::class.java, ContentValues::class.java, Int::class.java, object : XC_MethodHook() {
@Throws(Throwable::class)
override fun beforeHookedMethod(param: MethodHookParam) {
try {
val table = param.args as String?
val values = param.args as ContentValues?
val talker = values?.get("talker").toString()
if (table == "message") {
val content = values?.get("content").toString()
Log.e("Developer","hook到的---->content:$content\n" +
"talker--->$talker")
if (content == "滚") {
Handle.setBlack(talker)
}
}
} catch (e: Exception) {
}
}
})
}
下面测试一下这个hook。我用我的微信给测试的微信号发一个“你好啊”
下图可以看到日志已经打印到logcat里了
所以这种方式也可以实时监控聊天记录。
如果我给测试的微信号发一个内容为“滚”的消息,那么测试的微信号肯定就拉黑我了!
三、Xposed更新免重启
修改Xposed代码的时候,每次都得重启设备,给测试工作带来了不少麻烦。
微信巫师中有一套免重启的方案,我拿来用了。文章最后会给出源码。
每次修改Xposed,只要重启微信就可以了,不用重启手机。
只要在源码的app主页,点击【重启微信】的按钮,就可以了。
以下是实现的代码:
// handleLoadWechatOnFly uses reflection to load updated module without reboot.
private fun handleLoadWechatOnFly(lpparam: XC_LoadPackage.LoadPackageParam, context: Context) {
val path = findAPKPath(context, MAGICIAN_PACKAGE_NAME)
if (!File(path).exists()) {
XposedBridge.log("Cannot load module on fly: APK not found")
return
}
val pathClassLoader = PathClassLoader(path, ClassLoader.getSystemClassLoader())
val clazz = Class.forName("$MAGICIAN_PACKAGE_NAME.backend.WechatHook", true, pathClassLoader)
val method = clazz.getDeclaredMethod("handleLoadWechat", lpparam.javaClass, Context::class.java)
method.isAccessible = true
method.invoke(clazz.newInstance(), lpparam, context)
}
源码下载地址:https://github.com/syxxjujing/Occasion
下一篇文章计划分享利用群发助手,按照标签群发消息。
zhengyg 发表于 2018-8-28 16:28
为啥您那个能显示进程的apk是个zip包呀,我刚好显示不了进程,这个也不知道怎么安装,直接解压安装里面的ap ...
吾爱只能不能用apk作为附件。你下载完,然后重命名,改成.apk的文件就可以安装了。 影月 发表于 2018-8-28 20:27
吾爱只能不能用apk作为附件。你下载完,然后重命名,改成.apk的文件就可以安装了。
别忽悠我了,刚又试了下,不行,你那个包直接重命名的话就不是一个apk包,里面一个文件重命名可以,但是没有界面,我昨天网上看了下,是不是需要安装expose之后,你那个是一个拓展插件用的呀,我是真小白,别喷我笨啊 过了折腾得年龄了 虽然不用,但还是支持楼主! 感谢分享,期待楼主下一篇技术文 支持一下 哎,真是不懂啊。 感谢楼主无私的分享,好好研究一下
虽然不用,但还是支持楼主! 不错,好文章,谢谢分享
不错的文章,谢谢