前段时间在自己做开发的时候发现一个很好用的工具,OKHttp的拦截器(何为拦截器?就是在每次发送网络请求的时候都会走的一个回调)大概效果如下:
现在OkHttp也是谷歌推荐的一款网络请求框架。现在很火的Retrofit2也都是基于OkHttp的封装。
如果每次看Log服务器返回的数据等都需要用PostMan发请求显得有点 low,可以直接集成拦截器在发送请求的时候打印出来就如同上图,使用也很简单。
然后在OkHttp创建的时候调用即可:
builder.addInterceptor(loggingInterceptor);
如果我可以通过Xposed实现Hook动态添加自己的拦截器是不是就可以做出来一款基于OkHttp的通杀器。
这个时候需要考虑几个问题:
1、怎么拿到对方进程的Classloader;
2、我应该Hook什么方法才能把我自己的拦截器进行注入;
3、注入以后我应该怎么初始化这个拦截器类将其添加进去;
4、因为OkHttp的拦截器是需要导入三方依赖的,如果 app没有导入,应该如何实现动态加载。
问题1
想拿到地方ClassLoader很简单直接Hook attach固定系统级别的方法。
问题2
在 OkHttp 初始化的完毕的时候, 肯定会调用build方法 。就用这个当突破口直接Xposed 挂钩在挂钩之前需要判断一下对方是否使用了OkHttp用刚刚拿到的,lassloader试着反射一下看看能不能拿到 okHttpClient$Build ,也就是OkHttp里面的特征类 。
拿到了以后直接对build函数进行挂钩。
这块看到了在 build调用之前也就是OkHttpClient 初始化之前进行添加
动态拦截器。
看上面代码可知用了反射拿到这个拦截器集合的字段,然后添加的拦截器。其实在okHttp里面添加拦截器,如下:
其实最终就是在拦截器集合里面的进行添加:
我只需要动态在这个拦截里面添加即可。
问题 3
我应该怎么初始化拦截器?
先试着反射一下,看看对方的App里面是否导入了拦截器的依赖,如果拿到了,直接初始化,这块代码很重要也是核心代码。之前的代码:
在构造里面传的是一个接口,而这个接口就是在这个拦截器里实现内部接口。还需要调用setLevel设等级Body是将全部数据都打印Body这个是 level 里面的一个枚举。
用动态代理的方式 Proxy.newProxyInstance拿到这个接口的实体类,然后作为参数new出来拦截器。
反射拿到枚举作为setLevel的参数进行反射调用即可。始化完毕直接添加到拦截器集合里。
问题4
如果这个App没有导入拦截器的log依赖:
反射这个是拿不到的这个时候需要用他的Classloader进行动态加载。先把拦截器log的jar包放到assets 目录下在App模块,动的时候初始化的把Jar 保存到SD卡内。
在没有找到的时候直接进行动态加载,第四个参数传入目标的 ClassLoader直接进行LoadClass即可,后进行下面的初始化。
大功告成!
随便找了个App测试一下效果还可以,具体就不说了。
这个东西有个弊端,就是比App被混淆了,路径肯定会对不上,我个人想法就是可以根据方法的签名信息定位到。
还有时候虽然集成了OKHTTP,但他没有调用 Build 方法进行初始化,不知道道为啥。这块代码可以优化的,看看有没有其他的突破口。
我现在这个思路只是添加了LOG拦截器。拦截器还有很多种。比如直接修改请求头等参数的拦截器。具体可以百度看看。
项目地址:
https://github.com/w296488320/XposedOkHttpCat
本文由看雪论坛 珍惜Any 原创
网友评论