Skip to content

一个基于Magisk&Riru的Module,可以助你用超低成本开发各种Hook插件,无须Xposed

Notifications You must be signed in to change notification settings

wuyr/HookwormForAndroid

Repository files navigation

一个基于Magisk&Riru的Module,可以助你用超低成本开发各种Hook插件,无须Xposed

此Module仅供大家学习研究,请勿用于商业用途。利用此Module进行非法行为造成的一切后果自负!

背景:

前段时间在WanAndroid每日一问里有个问题:"应用进程中那4个Binder线程分别是跟谁通讯?"

一番简单分析无果后,就想着写个Xposed插件来hook Thread对象的创建,但是看到有同学提醒:"Xposed插件的handleLoadPackage方法是在handleBindApplication时才回调的!"。 没办法,只能找其他的方案了。

忽然想到了Magisk,但是我又不会做Magisk插件……

第二天看了下自己一直在用的那个【开启微信指纹支付】的Magisk模块源码(其实之前也看过好多遍了,一直没看懂,一头雾水),发现核心代码其实就是libs下面的那个APK的dex!

反编译看了下,大概摸清了思路,但是想到用这种方式(先手动打包成apk放在插件项目libs下)开发起来太繁琐了,而且维护起来成本又高,还没有一个规范的模板,这样就很难抽出来为自己所用。

于是心有不甘的我又继续在github上面搜Riru相关的模块,看到一个叫【QQ Simplify】的项目,是用来阉割QQ一些 “花里胡哨” 的功能的,看了下代码,它是在进程Fork之后,用反射把ServiceFetcher里面的LayoutInflater对象换成自己的代理类,这样就可以在布局inflate时,选择性地把一些View的宽高set为0,达到隐藏的效果。

结合这两个项目的部分代码以及思路,我封装出来一个入侵程度非常低的Module,开发新的插件的话,只需要添加这个Module的依赖,然后在module.properties中配置一下模块属性就行了,非常简单!


原理:

有一个叫Riru的Magisk模块,它会把系统的libmemtrack.so替换掉(新版改为指定ro.dalvik.vm.native.bridge属性值为自己的so),并对外公开Zygote初始化进程的一些API,比如forkAndSpecializePost

在Zygote Fork进程的前后,都会对外 “发通知” ,如果趁这个时机向指定进程注入自己的代码,那么,当进程启动完成后,自己的代码就运行在指定进程内了,这样就可以为所欲为扩展一些功能,或者更改某些逻辑等等。


Q&A:

这个Module能做什么?

要知道,你的代码是运行在目标进程中的,这就相当于你参与了目标app的开发!

所以理论上目标进程中的所有数据以及行为,都能修改成你想要的结果,只要你能拿到对应的对象。

至于怎样拿到对象,这就看具体场景了。

比如你想修改某个app的某个页面按钮点击行为,那就可以先监听目标Activity的生命周期来获取到对应的Activity对象,进一步find到View实例然后给它重新set一个OnClickListener。

再比如你想修改某个app的启动图,一个比较通用的方法是:监听对应Activity的onCreate,在这里把Activity.mWindowmContentParent替换成你自定义的FrameLayout,这样你就能在onLayout之前找到显示启动图的View实例,并对它做手脚。

它跟Xposed的关系/区别?

可以说是完全无关系的。

从能力上来看,很明显Xposed更强大,不过相对的,Xposed插件开发起来难度也会高一些,因为它的优势主要体现在能监听任何一个方法调用,这就非常考验你对目标app代码的熟悉程度了,如果没掌握一定的逆向知识是搞不来的。

反观这个Module,它的能力是不如Xposed的,比如它不能监听哪些Class被加载,不能直接感知到哪些对象被创建。只能用一些比较原始的方法来修改数据和行为,比如反射,动态代理等。优势是开发成本很低,甚至你不用反编译目标app,没有逆向基础也可以,只需要一个UIAutomatorViewer工具来帮助获取到布局结构和资源id就能着手开发了。还有就是,目标app很难感知到这个插件的存在,它不像Xposed在异常堆栈中能看到相关字眼。无论安装和运行,都可以说是不留痕迹的。


亮点:

  • 配置成本极低,添加这个Module依赖就行了,你只需关注你自己的代码逻辑;

  • 所有的配置都集中到了module.properties文件里,直接修改这个文件即可,比如主入口类,目标进程等;

  • 提供了一些基本的API,方便进行Hook工作,一般情况下,只需要几行代码就能监听到按钮的点击,或者布局的加载了;

  • 自动刷入! 是的,从此解放双手,像开发普通应用那样,编译完就能自动刷入手机了,如果是手动安装的话,每次至少浪费20秒时间;

  • 免重启(最小化)安装! 提供快速调试的能力;


使用:

  1. 首先,clone或直接下载这个Module(注意!这只是一个Module,需要被依赖到一个APP Module才能正常运作);

  2. 新建一个Android项目,Minimum SDK至少为23(即6.0)。为了避免不必要的麻烦,Language请选择Kotlin而不是默认的Java,因为这个Module用到了Kotlin;

  3. 新建好项目后,创建一个入口类,名字随便,比如就叫ModuleMain。然后,在里面声明一个 public static void main(String packageName) 方法,这个方法是必须有的!当插件启动后会被调用;

  4. 导入刚刚下载Module,并依赖到主模块中;

  5. 配置插件属性,先把模块根目录下的module.properties.sample复制一份,并改名为module.properties,然后编辑这个module.properties,根据里面的注释来完善插件信息,比如给moduleMainClass属性填上刚刚创建的ModuleMain完整类名(带包名);


module.properties属性如下:

  • moduleId:模块唯一标识,只能使用字母 + 下划线组合,如:my_module_id;

  • moduleName:模块名称,自由填写;

  • moduleAuthor:模块作者,自由填写;

  • moduleDescription:模块描述,自由填写;

  • moduleVersionName:模块版本名,自由填写;

  • moduleVersionCode:模块版本号,自由填写;

  • moduleMainClass:主入口类名,例:com.demo.ModuleMain;

  • targetProcessName:目标进程名/包名,即要寄生的目标。不填写则寄生所有进程。同时寄生多个目标,用 ; 分隔,如: com.demo.application1;com.demo.application2;

  • automaticInstallation:编译完毕自动安装模块(需要手机已通过adb连接到电脑(只能连一台),并已安装Magisk和Riru模块!)。1为开启,其他值为关闭;

  • debug:Debug提供最小化安装(除首次安装外免重启)能力,可以快速测试模块(开启此选项需先开启automaticInstallation)。

配置好这些属性之后,就可以编写代码,编译打包运行了! 注意,编译打包的话,需要运行project:assemble(Tasks/build/assemble)这个Task,不是app:assemble也不是module:assemble


常用API:

Name Description
Hookworm.setTransferClassLoader(true) 转接插件Dex的ClassLoader
如果引用到了目标应用的一些自定义类或接口(或第三方库),则需要开启转接,否则会报ClassNotFoundException
Hookworm.setHookGlobalLayoutInflater(true) 劫持全局的LayoutInflater
Hookworm.setOnApplicationInitializedListener 监听Application初始化
Hookworm.registerActivityLifecycleCallbacks 监听Activity的生命周期
Hookworm.registerPostInflateListener 拦截LayoutInflater布局加载
Hookworm.getApplication 获取进程Application实例
Hookworm.getActivities 获取进程存活Activity实例集合
Hookworm.findActivityByClassName 根据完整类名查找Activity对象
HookwormExtensions.findViewByIDName 根据资源id名来查找View实例
HookwormExtensions.findAllViewsByIDName 根据资源id名来查找所有对应的View实例
HookwormExtensions.findViewByText 根据显示的文本来查找View实例
HookwormExtensions.findAllViewsByText 根据显示的文本来查找所有对应的View实例
HookwormExtensions.containsText 检测目标View是否包含某些文本


感谢:

首先感谢鸿神和WanAndroid每日一问,如果没有那天的那个问题就没有这个库。

感谢Fingerprint pay for WeChatQQ Simplify,从这两个项目中学到很多思路以及代码。。。

感谢RiruMagisk,这两个东西是此Module的根基。

最后感谢大家的小星星🌟🌟,虽然可能屏幕前的你还没有点,但是先谢谢了!

About

一个基于Magisk&Riru的Module,可以助你用超低成本开发各种Hook插件,无须Xposed

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published