最近在尝试使用 Xposed Hook 其他软件.
Try 0x00
写代码时发现一个问题: Xposed Hook 方法后, 代码是以那个被 Hook 的软件身份运行的, 然而我的 MainActivity 保存下来的 preference 是以我这个插件的身份保存的, Hook时没有访问权限. 然而SharedPreference 的 MODE_WORLD_READABLE 在 Android 7 以上的版本已经被彻底移除, 使用会直接抛出异常.
Try 0x01
后来打算使用安卓推荐的标准 ContentProvider 的方法来传递数据, 可是在被 Hook 的软件中又不方便获取到一个 Context 用于获取 ContentResolver…
Try 0x02
之后又打算使用直接在代码中调用的方法. 举例:
负责GUI的主程序是 me.lyc8503.activity.MainActivity, 我想直接在这个 MainActivity 访问我的 Hook 相关方法 me.lyc8503.Hook.Hooktest, 可是直接出现了 java.lang.NoClassDefFoundError 异常.
同理: 从 Hook 的代码中直接访问 MainActivity 代码也是各种未初始化导致的 NullPointerException
Try 0x03
后来又发现了 Xposed 提供的 XSharedPreference 里面有一个 makeWorldReadable() 方法, 以为是一种对新版安卓安全机制的 workaround, 又试了好久…结果一翻文档:
public boolean makeWorldReadable ()
Tries to make the preferences file world-readable.
Warning: This is only meant to work around permission “fix” functions that are part of some recoveries. It doesn’t replace the need to open preferences with
MODE_WORLD_READABLE
in the module’s UI code. Otherwise, Android will set stricter permissions again during the next save.This will only work if executed as root (e.g.
initZygote()
) and only if SELinux is disabled.Returns
true
in case the file could be made world-readable.
Try 0x04 Final
最后还是回到了 Android 文档里推荐的 Broadcast 和 Content Provider …
这里只是我的 UI 和被 Hook 代码之间的通讯, 用 Broadcast 好像不是很合适… 就最终用了 Content Provider.
最终的问题是我对 Context 的理解不够到位. 我误以为所有 Context 都是直接由 Activity.getContext() 获取的, 最后参考了这篇文章.
可以看到Activity.Service.Application都是Context的子类;
也就是说,Android系统的角度来理解:Context是一个场景,代表与操作系统的交互的一种过程.从程序的角度上来理解:Context是个抽象类,而Activity.Service.Application等都是该类的一个实现.
再仔细看一下上图:Activity.Service.Application都是继承自ContextWrapper,而ContextWrapper内部会包含一个base context,由这个base context去实现了绝大多数的方法.
还有一张不同 Context 功能的图:
大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?下面一个一个解释:
数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task.一般情况不推荐.
数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用.
数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值.(可以无视)
注:ContentProvider.BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用.
好了,这里我们看下表格,重点看Activity和Application,可以看到,和UI相关的方法基本都不建议或者不可使用Application,并且,前三个操作基本不可能在Application中出现.实际上,只要把握住一点,凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏.
所以其实只需要使用 AndroidAppHelper.currentApplication().getApplicationContext() 就可以直接获得一个 Application Context, 进而用于获取 Content Resolver.
以此文记录因为对 Context 理解不透彻导致的踩坑.
本文采用 CC BY-NC-SA 4.0 许可协议发布.
作者: lyc8503, 文章链接: https://blog.lyc8503.net/post/xposed-cross-application-communication/
如果本文给你带来了帮助或让你觉得有趣, 可以考虑赞助我¬_¬