Android逆向——定位到某书 Sign 算法(上)

简介: Android逆向——定位到某书 Sign 算法

一、浅谈Okhttp拦截器

添加一个自定义拦截器很简单,只需要实现 Okhttp 的 Interceptor 接口,重写其中的intercept 方法,最后在 OkHttpClient.Builder 链式代码中注册和添加这个拦截器,为什么要称作“自定义“拦截器呢?因为 Okhttp 核心实现就是基于其内部五大拦截器,我们下文再说。

需要注意的是,Retrofit 是基于 Okhttp 的封装,所以当我们谈论“Retrofit的拦截器”,其实就是OKhttp的拦截器。

先看一下上一节,我们用 Okhttp 实现网络请求的 demo


640.jpg


对照着看一下 Okhttp 发送请求的执行流程

640.jpg


我们分析大红框里的内容,这张图有些繁琐,也可以转化640.jpg成下图。



还是直接上图,就像流水线工厂一样,一个一无所有的 Request,依照顺序依次经过五大拦截器的前置拦截,最后拿到response后,再倒序经过五大拦截器的后置拦截。

我们引用@yuashuai 所举的例子,他表述的既生动又贴切。

老张有很多干面条,但是他想吃汤面,可是自己又不会做,但是碰巧村里大郎会做,于是老张拿一包干面条让大郎做成了汤面。但是老张发现他做面不好吃,盐都没放,连个青菜叶子都没有。

这时候老张正好碰到隔壁老王,老王说了这东西我也会做,比他做的好吃多了。于是老张又拿着一包干面条给了老王,老王说老张你等着,我马上回家给你做,做好了就给你送过去。但是老王回家并没有做,而是去家里拿了一包盐,然后去找隔壁老李了,原来老王并不会做面,但是他知道隔壁老李会做,而且做得比较好吃。于是他把干面条和盐都交给了老李。老李对老王说你回去等着吧,做好了马上给你送过去。可是老李同样不会做,但是他知道村里的大郎会做,这时老李首先回厨房拿了两个生菜叶子,然后带着老王给的干面条和盐去找大郎了,对大郎说,生菜叶子,盐,面条都给你了,你快给我做一碗面。大郎对老李说好嘞,3分钟就好了,3分钟后,老李拿着做好了的放了盐和生菜叶子的一碗面回去了。本来打算直接给老王,但是一想,自己放了两个生菜叶子,不吃点这个面吃不是有点亏,于是老李偷偷了吃了几根面。然后老李去找老王说你的面做好了并把面交给了老王。老王一看这面只有两个青菜叶子,营养是不是不够呀!于是老王又买了半斤熟牛肉,切切放了进去。然后老王去找老张说你的面做好了,还说道这么大一碗你也吃不完吧,让小张也吃点。最后老张吃着老王送来的红烧牛肉面感动的肉牛满面。

这里的干面条就可以看做一个最原始的 request,到老王哪里被加了点盐,到老李哪里被加了生菜叶子,于是大郎才能把这个request做成放了盐和生菜叶子的response,这个response回到老李哪里又被啃了几口,到老王哪里又被放了点牛肉。于是最后回到老张里收到的response就是被扣了几口并且加了牛肉的response。这样整个链条是不是就清楚了!

@Wanghao 画了一张非常全面的图。

在第三讲的末尾我们讨论过 BridgeInterceptor 拦截器,它会对我们我们配置的 request请求补充头信息,比如请求类型、UA,如果你自己不加ua,Bridge 拦截器就会添加“okhttp/版本号”这样的ua。

640.jpg


这是 BridgeIntercetpor 的源码

640.jpg


我们也可以自定义拦截器,分为应用级别拦截器和网络级别拦截器,在 @Wanghao 的图上我们可以看到它们分别作用的时机。

1.应用级别拦截器:只会调用一次,获取到最终的 response 结果

2.网络级别拦截器:可以感知到网络的请求的重定向,以及重试会被执行多次

这两种拦截器在注册方式各不同,分别调用 addInterceptor()以及 addNetworkInterceptor 方法进行注册,但实现拦截器的步骤没有不同,所以我们不做过多笔墨。


640.jpg


640.jpg


二、分析一个简单的拦截器

我们随便找一个拦截器 demo 分析一下,我们需要熟悉拦截器的具体操作,找到它代码流程上的一些特征,然后根据这些特征在Jadx中搜索反编译后的 Java 代码,去寻找某书实现添加sign等等11个参数的拦截器。

除此之外还有个思路,上文说到,自定义的拦截器分为 Application 拦截器和 Network 拦截器,但不管哪一种,都需要在 OkHttpClient.Builder 链式代码中通过 addInterceptor/addNetworkInterceptor 方法添加和注册后才能生效,那我们可以全局搜索 addInterceptor 以及 addNetworkInterceptor,然后得到拦截器的线索,这样应该也是可以的。我们先看看当前的这个思路。

640.jpg


我们可以看到三个明显的特征:

一: 是实现Interceptor接口 “public class xxx(自定义的拦截器名) implements Interceptor {”

二: 是重写intercept方法“public (可能有修饰符) Response intercept(Chain Chain)……”

三: 是添加字段时调用的 “.addQueryParameter” 方法(这儿我们加了个“.”,可以缩小检索范围),如果是添加Header 头信息,则会调用 ”.header“ 这个方法

如果 App 没有对 Okhttp 类进行混淆,那我们就可以根据这三个特征找到  Retrofit 的拦截器实现。

我们这儿再多说两句,看图中第九行,Request originalRequest = chain.request(); 这个demo作者为什么要将这个Request命名为 originalRequest(original:原先的,原始的)呢?

再回想一下拦截器的工作原理。想象一下一个流水线,request 是材料,response 是产品,从头到尾经历了许多次加工(拦截器)。每个拦截器先通过 chain.request() 得到这个 reqeust,经过一系列操作后的 request,再放回 chain.proceed 方法,最后return 回去,request 经过了一次洗礼,等待它的是不断的新的洗礼。

640.png

chain.proceed 这个方法名非常精准和有神,Okhttp采用了设计模式中的责任链模式,感兴趣的可以看一下这篇关于责任链的文章https://www.cnblogs.com/aeolian/p/8888958.html

因此,对于每一个拦截器来说,取到的request就是原始和过去的,命名就可能会用”old“、”original“,返回到reqeust就可能用”final“、”new“修饰,解释到这儿,我想大家对拦截器应该有了一个具象的了解了。

上面我们找到了三个特征,那么接下来我们通过 Jadx 的全局搜索功能,开始寻找某书 Retrofit的拦截器,进而找到 sign 等参数的实现。如果你的电脑内存只有 8G,那么接下来的这一步操作对你十分有用,除此之外,它对我们搜索关键代码点也有奇效。

反编译一个App,你会看到成千上万的类和方法,我们可以简单将这些类和方法分成“具体业务逻辑的代码”和“App架构和工具的代码”,前者的类名一般是包名.xxx,比如某书App包名为 com.xingin.xhs,它的业务代码就是 com.xingin.xxxx;而第二类往往五花八门,比如 Android本身的一些方法类 “android.xx”,腾讯的sdk“com.tencent.xxx”,微博的登录接入sdk“com.weibo.xxx”。

我们想要定位到的内容/加解密逻辑等等,基本都在前者的类里,而后者既缭乱人眼,烦人心神,又占用内存,Jadx给我们提供了屏蔽这些类的方法,屏蔽后Jadx将不再反编译这些类,你也无法再跳转到该方法里,或者在全局检索时看到这些类中扰人的代码。

方法很简单,只需要在类列表中选中某个类,右键 exclude 即可屏蔽这个类。

640.jpg


相关文章
|
28天前
|
算法 Android开发
Android签名算法的原理
Android签名算法的原理
20 0
|
5月前
|
缓存 算法 Java
Linux内核新特性年终大盘点-安卓杀后台现象减少的背后功臣MGLRU算法简介
MGLRU是一种新型内存管理算法,它的出现是为了弥补传统LRU(Least Recently Used)和LFU(Least Frequently Used)算法在缓存替换选择上的不足,LRU和LFU的共同缺点就是在做内存页面替换时,只考虑内存页面在最近一段时间内被访问的次数和最后一次的访问时间,但是一个页面的最近访问次数少或者最近一次的访问时间较早,可能仅仅是因为这个内存页面新近才被创建,属于刚刚完成初始化的年代代页面,它的频繁访问往往会出现在初始化之后的一段时间里,那么这时候就把这种年轻代的页面迁移出去
|
5月前
|
JSON Java 定位技术
【Android App】GPS获取定位经纬度和根据经纬度获取详细地址讲解及实战(附源码和演示 超详细)
【Android App】GPS获取定位经纬度和根据经纬度获取详细地址讲解及实战(附源码和演示 超详细)
284 0
|
3月前
|
算法 Android开发
安卓逆向 -- 自吐算法(3DES和AES)
安卓逆向 -- 自吐算法(3DES和AES)
20 1
|
3月前
|
算法 Java Android开发
安卓逆向 -- NDK开发实现MD5算法
安卓逆向 -- NDK开发实现MD5算法
34 0
|
3月前
|
算法 安全 JavaScript
安卓逆向 -- 算法基础(SHA)
安卓逆向 -- 算法基础(SHA)
19 0
|
3月前
|
算法 JavaScript Java
安卓逆向 -- 算法基础(数字签名)
安卓逆向 -- 算法基础(数字签名)
21 1
|
3月前
|
算法 Android开发
安卓逆向 -- 自吐算法(MAC)
安卓逆向 -- 自吐算法(MAC)
22 1
|
3月前
|
移动开发 算法 安全
安卓逆向 -- 算法基础(Base64与HEX)
安卓逆向 -- 算法基础(Base64与HEX)
14 1
|
3月前
|
算法 JavaScript Java
安卓逆向 -- 算法基础(MAC)
安卓逆向 -- 算法基础(MAC)
11 1