修改smali插入代码

作者 zzzz 日期 2017-07-27
修改smali插入代码

前言

本来想抓取酷安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了,而且也可以打断点了,如何加断点调试下次再详细说明
debug运行成功

分析类名

因为代码混淆的缘故,仅通过文件名和一些目录很难找到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代码
Compile to 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()