前言
本来想抓取酷安api接口,但是他们客户端应该是使用了证书锁定(Certificate Pinning),导致无法抓包,okhttp的使用方法具体使用可以参考https://github.com/square/okhttp/wiki/HTTPS
既然无法抓包那就直接在apk里面植入log代码也可以看到,当然也有其他的办法比如hook。
开始
准备工具Android Studio, Apktool, JEB
我已经写好了两个简单的脚本方便反编译和重新打包,https://github.com/8enet/shell-tools
需要用到的脚本有decompile.sh(反编译) 和 rebuild.sh(重新打包编译),先根据注释配置好apktool路径
同时需要framework-res.apk,请在android 7.0的手机上提取adb pull /system/framework/framework-res.apk
#安装framework-res.apk
./apktool if framework-res.apk
rebuild.sh 脚本用于重新打包并签名,签名需要一个keystore,可以通过keytool生成并修改其中的值
如何生成keystore请参考官方文档
先反编译一个apk试试,./decompile.sh app.apk
文件验证通过,开始反编译...
删除旧文件...
I: Using Apktool 2.2.3 on com.coolapk.market.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/zl/Library/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Baksmaling classes2.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
反编译 com.coolapk.market.apk 成功!
文件保存在 /Users/zl/tools/apk_decompile/com.coolapk.market
上面提示保存成功
再来重新打包,注意参数路径是刚才反编译之后输出的路径./rebuild.sh /Users/zl/tools/apk_decompile/com.coolapk.market
删除 build、dist文件夹
assamble apk
I: Using Apktool 2.2.3
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether sources has changed...
I: Smaling smali_classes2 folder into classes2.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Copying libs... (/lib)
I: Building apk file...
I: Copying unknown files/dir...
开始签名apk
jar 已签名。
...
signed apk file: /Users/zl/tools/apk_decompile/com.coolapk.market/dist/com.coolapk.market_rebuild_signed.apk
如果看到上面的输则表示重新打包签名成功了。
初步修改
首先建议开启debug模式,修改AndroidManifest.xml 文件,在<application>
节点添加android:debuggable="true"
属性,如下<application android:allowBackup="false" android:debuggable="true" android:icon="@mipmap/ic_launcher" ...
重新打包运行就可以在Android Studio 中方便的过滤log了,而且也可以打断点了,如何加断点调试下次再详细说明
分析类名
因为代码混淆的缘故,仅通过文件名和一些目录很难找到okhttp中相关的类名
祭出神器JEB
可以大致猜测 com.coolapk.market.network.HttpClientFactory 这个类用于生成okhttpclient,我们可以给OkHttpClient 添加一个Interceptor拦截请求
先看代码
光看CoolMarketHeaderInterceptor类名和方法public ab intercept(a.t$a arg6) throws IOException
其中 intercept 方法签名是不是和 Interceptor.java 很相似?!
想法
以上一切都是猜测,没有猜测就没有下一步
现在假设我们找到的类是正确的,如果要添加log,我们只需要在return arg6.a(v3.a());
之前添加一行代码android.util.Log.e("coolapk","http -> "+...);
实现
首先尽可能的减少错误,在return前调用方法把Request传进去会更好,手写smali代码还是很痛苦的,可以使用AndroidStudio帮我们生成!
安装java2smali插件,
然后在任意一个类里面添加一个方法private void logRequest(Request request){
Log.e("test", "http --> "+request.method()+" "+request.url()+"\n"+request.headers());
}
任何在Build->Compile to smail 查看编译生成的smail代码
生成的代码如下.method private logRequest(Lokhttp3/Request;)V
.registers 5
.param p1, "request" # Lokhttp3/Request;
.prologue
.line 87
const-string v0, "test"
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v2, "http --> "
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {p1}, Lokhttp3/Request;->method()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
const-string v2, " "
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {p1}, Lokhttp3/Request;->url()Lokhttp3/HttpUrl;
move-result-object v2
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
move-result-object v1
const-string v2, "\n"
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {p1}, Lokhttp3/Request;->headers()Lokhttp3/Headers;
move-result-object v2
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
move-result-object v1
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
.line 88
return-void
.end method
尼玛方法体里就一行代码结果生成这么多code,当然我们通过smali代码可以看到用+拼接被转换成了StringBuilder.append()