前言

是的,我又写前言了。

什么是Xposed

开发者(项目仓库也在主页):https://github.com/rovo89

来自维基百科:

Xposed(也被称作Xposed框架、XP框架、Xposed framework),是一个运行于Android操作系统的钩子框架。其通过替换Android系统的关键文件,可以拦截几乎所有Java函数的调用,并允许通过Xposed模块中的自定义代码更改调用这些函数时的行为。因此,Xposed常被用来修改Android系统和应用程序的功能。

Xposed Installer是Xposed框架的官方安装器,可以在拥有root)权限的设备上安装Xposed框架。Xposed Installer也提供模块的下载、管理、日志显示等功能。

工作原理

Xposed框架主要通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。与采取传统的Inhook方式相比,Xposed在开机的时候完成对所有的Hook Function的劫持,在原Function执行的前后加上自定义代码。
  为什么需要这么做呢?
  Android基于Linux,第一个启动的进程自然是init进程,该进程会启动所有Android进程的父进程——Zygote(孵化)进程,该进程的启动配置在 /init.rc脚本中,而Zygote进程对应的执行文件是/system/bin/app_process, 该文件完成类库的加载以及一些函数的调用工作。在Zygote进程创建后, 再fork出SystemServer进程和其他进程。Xposed Framework,就是用自己实现的app_process替换掉了系统原本 提供的app_process,加载一个额外的jar包,然后入口从原来的: com.android.internal.osZygoteInit.main()被替换成了: de.robv.android.xposed.XposedBridge.main(),
然后创建的Zygote进程就变成Hook的Zygote进程了,而后面Fork出来的进程 也是被Hook过的。
  这个Jar包在: /data/data/de.rbov.android.xposed.installer/bin/XposedBridge.jar 目录下。
  通过原理我们可以看出,要使用Xposed框架,那么手机必须要拥有最高权限(就是root权限),当然现在还出现了VirtualXposed,这个框架的话就相当于给你的手机开了一个平行空间,这个空间和你的手机系统一样,就相当于一个副本,所以当你在这个空间使用xposed的话,就不需要root,但是在这个空间你需要重新安装你想修改的程序,因为它刚创建出来的时候是什么都没有的,也因此你在这个空间修改并不会影响到你的手机本来的应用,就相当于双开应用。
  值得注意的是,既然给出了最高权限,那么别人就可以做很多坏事了,比如获取你的账号密码,还有一些私密的文件,因此对于别人写的Xposed模块可以看看他是不是开源的再决定用不用,如果不是开源的,建议不要使用。当然如果不想承担这么大的风险又不嫌麻烦的话,可以使用上面介绍的virtualXposed框架。
————————————————
来自:https://blog.csdn.net/baidu_38661691/article/details/95977655

官方教程

WIKI:https://github.com/rovo89/XposedBridge/wiki/Development-tutorial

中文翻译:https://vbill.github.io/2015/02/10/xposed-1/

Xposed Framework APIhttps://api.xposed.info/reference/packages.html

开发环境:

Windows10

Android studio 4.0.1

夜神模拟器:6.6.1.7

开始

声明这是一个Xposed模块

AndroidManifest.xml

<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">

        <meta-data
            android:name="xposedmodule"
            android:value="true" />
        <meta-data
            android:name="xposeddescription"
            android:value="OA助手" />
        <meta-data
            android:name="xposedminversion"
            android:value="51" />

    </application>

声明启动类

src/main/assets/xposed_init

top.jsls9.oa.HookMain

需要引入的包

compileOnly("de.robv.android.xposed:api:82")

具体编写hook代码

...

应用反编译

反编译网上教程很多,把dex转成jar,查看jar代码

反编译后的代码都是混肴的怎么办?

答:hook时不需要源代码的类名、方法名,用你反编译后的即可。

不过需要注意,比如b.java 里除了本身还有一个b class。

jdk-gui查看jar时会有这种情况,而载MT管理器上会显示b$b这样的,要以b&b

如我在hook一个class时是下方这样的写法:

//点击结算按钮
        try {
            hookclass = mAppClassLoader.loadClass("com.huluxia.framework.base.widget.dialog.b$a$1");

        } catch (Exception e) {
            XposedBridge.log("com.huluxia.framework.base.widget.dialog.b$a$1报错");
            return;
        }
        XposedBridge.log("寻找com.huluxia.framework.base.widget.dialog.b$a$1成功");
        XposedHelpers.findAndHookMethod(hookclass,
                "onClick",
                //int.class,
                View.class,
                new XC_MethodHook(){

                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        TextView view = null;
                        XposedBridge.log("=====hook方法前=====");
                        if(param != null && param.args.length > 0){
                            //XposedBridge.log("查看参数");

                            for (int i = 0; i < param.args.length; i++) {
                                //XposedBridge.log("arg:" + param.args[i]);

                                //参数类型明明是TextVie偏偏转不成View,奇奇怪怪的
                                if(param.args[i] instanceof TextView){

                                    view = (TextView) param.args[i];

                                    if(UI.OA_BUTTON.equals(view.getText())){
                                        settlement(String.valueOf(postId), context);
                                    }
                                    //Toast.makeText(context, "点击了一下,postId"+postId, Toast.LENGTH_SHORT).show();
                                }


                            }
                            XposedBridge.log("========拦截前完毕=====");
                        }
                    }
                });

怎么定位hook的点?

答:

  1. 需要hook的app至少自己是熟悉大致功能的,方便查看反编译后的代码;可以通过一些app页面上的关键字、抓到到的接口去搜索,逐步去找到类、方法等。当然,需要有一些开发上的封装,或者某些Android的原理(我不懂Android,只是会写点Java,在这上面吃了大亏)。
  2. 暴力遍历,通过一些特定的方法,去遍历输出你操作时的类、方法、参数。总不能全部输出到Xposed上,移动设备要连接在电脑上的,Android studio可以查看起来。当然你能通过1来定位到大致位置的话遍历起来更方便一些。这个方法还是需要懂一些Android,不然就去搜索,还是有一些的。

上面那个代码片段就是我常用的(我本来也就刚写了几天,写了个demo,所以也就这一个)

  1. 使用DDMS录制行为轨迹

DDMS的使用具体可以百度,连接上设备不能查看进程可以参考最下放的链接。

这个方式很好用的,你肯定知道在怎么操作app的时候要修改app什么。所以准备好你要的操作,使用DDMS录制轨迹,查看轨迹,比如你点击了个按钮,那你就在轨迹里搜索click

遇到的问题以及解决方案

1、Android studio打包的时候编译不通过,这个我觉得也就我自己会遇到这个问题了,只是编码(jdk1.8的路径以及gradle奇奇怪怪的版本号)的问题,在下方选择GBK。

2、DDMS不显示进程:https://www.cnblogs.com/hally/p/12659508.html

3、DDMS启动的路径(Android studio上找不到这个Tools了):https://blog.csdn.net/qq_42023080/article/details/105842271

4、对我帮助最大的开发项目(demo架子是参考的这个项目):https://github.com/dreamncn/Qianji_auto