各位读者你们好呀!有两个星期没有更新了,主要是懒癌犯了!
OkHttp
Okhttp 是一个网络框架,现在的Android应用基本都使用的是这个开源库了。
想要拦截 OkHttp,首先就要熟悉它的API和原理。这里就不展开了,可以查找一些文章或者自己看源码。
OkHttp的工作模式有点像 OSI 模型,它里面的拦截器就相当于一个层次。每个拦截器都负责两部分的工作:
- 将请求进行封装,y = f(x)
- 将返回结果解封装,y’ = f’(x)
以 BridgeInterceptor 为例:
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val userRequest = chain.request()
val requestBuilder = userRequest.newBuilder()
// ... 处理请求体
val networkRequest = requestBuilder.build()
val networkResponse = chain.proceed(networkRequest)
cookieJar.receiveHeaders(networkRequest.url, networkResponse.headers)
val responseBuilder =
networkResponse.newBuilder()
.request(networkRequest)
// ... 处理响应体
return responseBuilder.build()
}
为了调试方便,OkHttp 里面还自带了一个日志拦截器:
有了这个拦截器,就可以打印所有请求的请求体与响应体。
所以一个最简单的思路就是使用 frida 将这个日志拦截器添加到 okhttp 的实例对象里面就ok。
拦截OkHttp
这里有一篇文章,使用 frida 的 api 实现了一个拦截器,感觉有点蛋疼。
肯定是使用加载 dex 的方式会好些,找到所有OkHttpClient的实例对象,然后给他们加上拦截器:
// 加载包含logging-interceptor拦截器的DEX
Java.openClassFile("/data/local/tmp/xxxxx.dex").load();
// 获取日志拦截器类
const MyInterceptor = Java.use("com.xxxx.okhttp3Logging");
var MyInterceptorObj = MyInterceptor.$new();
// interceptors 是一个不可变集合,所以需要重新创建一个新的集合
Java.choose("okhttp3.OkHttpClient", {
onMatch: function (instance) {
console.log("1. found instance:", instance)
console.log("2. instance.interceptors():", instance.interceptors().$className)
console.log("3. instance._interceptors:", instance._interceptors.value.$className)
//console.log("4. interceptors:",gson2.$new().toJson(instance.interceptors()))
console.log("5. interceptors:", Java.use("java.util.Arrays").toString(instance.interceptors().toArray()))
var newInter = Java.use("java.util.ArrayList").$new();
newInter.addAll(instance.interceptors());
console.log("6. interceptors:", Java.use("java.util.Arrays").toString(newInter.toArray()));
console.log("7. interceptors:", newInter.$className);
newInter.add(MyInterceptorObj);
newInter.add(curlInter);
instance._interceptors.value = newInter;
}, onComplete: function () {
console.log("Search complete!")
}
})
混淆处理
为了防止被快速逆向分析,部分 app 针对 okhttp 的代码进行了混淆。
有一个开源项目就是做了这个事情:
它里面的核心逻辑是对混淆类的寻找:
它寻找特征的方法也很简单粗暴。就是先去所有可能属于 okhttp 框架层的类中找到 OkHttpClient$Builder 内部类。该类的特征为有四个 List 类型的成员变量,其中两个有 final 修饰符,两个的列表类型为接口类型。一旦找到满足这个条件的类,就可以通过 getEnclosingClass 方法获取该类的外部类,也就定位到了关键类 OkHttpClient。然后顺藤摸瓜一直找下去。
感觉会有更好的方式,可以自己混淆一下代码观察下特征。
根据 README 的介绍来看:
`find()` 检查是否使用了Okhttp & 是否可能被混淆 & 寻找okhttp3关键类及函数
`switchLoader("okhttp3.OkHttpClient")` 参数:静态分析到的okhttpclient类名
`hold()` 开启HOOK拦截
`history()` 打印可重新发送的请求
`resend(index)` 重新发送请求
这个库需要在一定程度上结合静态分析才能使用,当然如果 find 能找出来最好,只需要替换一下就行了。