环境搭建
build 中引入即可
implementation("com.squareup.okhttp3:okhttp:3.12.0")
主要用到的类是这几个
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
使用流程
- OkHttpClient 对象
OkHttpClient client = new OkHttpClient();
用于配置 OKhttp 框架的各种配置。 当然你可以如上使用默认配置,只初始化就行了。 (也可以配置超时,重连等配置如下)
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor()) // 配置日志拦截器
.readTimeout(5. TimeUnit.SECONDS) // 设置读超时
.writeTimeout(5. TimeUnit.SECONDS) // 设置写超时
.connectTimeout(5. TimeUnit.SECONDS) // 设置连接超时
.retryOnConnectionFailure(true) // 自动重连
.build();
// 还有其他配置,这里不详细写了
// 设置代理,SSL验证,协议版本验证等,也能自定义配置。
- Request 对象
Request request = new Request.Builder()
.url(url)
.build();
配置
Request request = new Request.Builder()
.url(url)
.header(key, value)
.header(key, value) // 同理可以配置各种请求头
.build();
- 发送异步请求
将 Request 封装成 Call 对象后,每次 enqueue 队列中都会产生一次真实的网络请求。(这里主要用的是异步)
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
call.cancel();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//打印输出
Log.d(TAG, response.body().string());
}
}
);
通过调试app可以成功访问百度了
Hook
- 时机1:
request
构建过程 时机2:
newCall
Java.perform(function () { var OkHttpClient = Java.use('okhttp3.OkHttpClient'); OkHttpClient.newCall.implementation = function(request){ var result = this.newCall(request); console.log(request.toString()); // 大部分 object 都支持 toString() return result; } });
时机3: 自带的拦截器, okhttp 自带5大拦截器类似中间件,可以通过 hook 拦截器来拿到想要的数据
Java.perform(function () { var ByteString = Java.use("com.android.okhttp.okio.ByteString"); var Buffer = Java.use("com.android.okhttp.okio.Buffer"); var Interceptor = Java.use("okhttp3.Interceptor"); var MyInterceptor = Java.registerClass({ name: "okhttp3.MyInterceptor", implements: [Interceptor], methods: { intercept: function (chain) { var request = chain.request(); try { console.log("MyInterceptor.intercept onEnter:", request, "\nrequest headers:\n", request.headers()); var requestBody = request.body(); var contentLength = requestBody ? requestBody.contentLength() : 0; if (contentLength > 0) { var BufferObj = Buffer.$new(); requestBody.writeTo(BufferObj); try { console.log("\nrequest body String:\n", BufferObj.readString(), "\n"); } catch (error) { try { console.log("\nrequest body ByteString:\n", ByteString.of(BufferObj.readByteArray()).hex(), "\n"); } catch (error) { console.log("error 1:", error); } } } } catch (error) { console.log("error 2:", error); } var response = chain.proceed(request); try { console.log("MyInterceptor.intercept onLeave:", response, "\nresponse headers:\n", response.headers()); var responseBody = response.body(); var contentLength = responseBody ? responseBody.contentLength() : 0; if (contentLength > 0) { console.log("\nresponsecontentLength:", contentLength, "responseBody:", responseBody, "\n"); var ContentType = response.headers().get("Content-Type"); console.log("ContentType:", ContentType); if (ContentType.indexOf("video") == -1) { if (ContentType.indexOf("application") == 0) { var source = responseBody.source(); if (ContentType.indexOf("application/zip") != 0) { try { console.log("\nresponse.body StringClass\n", source.readUtf8(), "\n"); } catch (error) { try { console.log("\nresponse.body ByteString\n", source.readByteString().hex(), "\n"); } catch (error) { console.log("error 4:", error); } } } } } } } catch (error) { console.log("error 3:", error); } return response; } } }); var ArrayList = Java.use("java.util.ArrayList"); var OkHttpClient = Java.use("okhttp3.OkHttpClient"); console.log(OkHttpClient); OkHttpClient.$init.overload('okhttp3.OkHttpClient$Builder').implementation = function (Builder) { console.log("OkHttpClient.$init:", this, Java.cast(Builder.interceptors(), ArrayList)); this.$init(Builder); }; var MyInterceptorObj = MyInterceptor.$new(); var Builder = Java.use("okhttp3.OkHttpClient$Builder"); console.log(Builder); Builder.build.implementation = function () { this.interceptors().clear(); //var MyInterceptorObj = MyInterceptor.$new(); this.interceptors().add(MyInterceptorObj); var result = this.build(); return result; }; Builder.addInterceptor.implementation = function (interceptor) { this.interceptors().clear(); //var MyInterceptorObj = MyInterceptor.$new(); this.interceptors().add(MyInterceptorObj); return this; //return this.addInterceptor(interceptor); }; console.log("hook_okhttp3..."); });
推荐拦截器
- 推荐 Frida 的 okhttp 成品拦截器
- okhttp 自带的拦截器
okhttp3logging
编译成 dex 后可以给Frida直接调用,简单粗暴(文章末尾可下载)
// 使用 okhttp3logging
function hook_okhttp3() {
// 1. frida Hook java层的代码必须包裹在Java.perform中,Java.perform会将Hook Java相关API准备就绪。
Java.perform(function () {
Java.openClassFile("/data/local/tmp/okhttp3logging.dex").load();
// 只修改了这一句,换句话说,只是使用不同的拦截器对象。
var MyInterceptor = Java.use("com.roysue.octolesson2ok3.okhttp3Logging");
var MyInterceptorObj = MyInterceptor.$new();
var Builder = Java.use("okhttp3.OkHttpClient$Builder");
console.log(Builder);
Builder.build.implementation = function () {
this.networkInterceptors().add(MyInterceptorObj);
console.log("hook Build.build successfully !")
return this.build();
};
console.log("hooking_okhttp3...");
});
}
hook_okhttp3();
然后就可以在终端里用 adb logcat 查看日志了
资料下载
涵盖 Demo 代码, 成品 dex。回复可见
此处内容需要评论回复后(审核通过)方可阅读。
79 comments
学到了,正好在考虑怎么hook异步回调,多谢作者。
用dex来试下拦截效果
dex
nice
想抓包 https,思索摸索了很久:
mitm 替换系统证书、劫持app证书下载、尝试反编译重打包apk, 效果不理想。
后来看到 okhttp 调用到 native tls, 想 hook 底层通信、底层 ssl 库。
再后来偶然看到 frida 框架, 心想这神器就是我要。的。
2324234
赞!
dex
赞一个
dex
感谢大佬文章
没有dex环境,下载dex文件试试。谢谢
下载成品,谢谢楼主
感谢大佬文章,来学习了
下载成品,谢谢楼主
成品 dex
dex