欢迎访问我的个人网站:https://coderyuan.com
文章目录
先讲讲怎么回事
不知道怎么的,大概是从19年双十一前,我在家里刷淘宝(天猫、闲鱼等)的时候,图片经常加载的特别慢,家里是北京电信的100M宽带,另外还有一张电信的手机卡,无论宽带还是4G,图片都刷的很慢,网速正常,SpeedTest测试速度都是正常的,其他App也都OK
部分家里使用电信宽带的同事也遇到了类似的问题,但都以为是家里网速的问题,所以也没有向淘宝进行反馈,只是在需要的时候,切成4G使用罢了
今年5月宽带到期,由于淘宝的问题,差点就换了联通的,但由于联通略贵(500M,166/月),电信(200M,600+/年),而且疫情期间,懒得折腾了,直接续费吧
于是就想着怎么解决一下淘宝图片的问题
不能抓包
作为一名Android码农,首先想到的办法就是开Charles/Fiddler去抓包看看,但是在挂上代理以后,会发现抓不到大部分的淘宝图片请求,于是猜测是淘宝使用了自己的网络库,或者是做了防抓包处理,所以看来不能直接通过抓包来判断问题所在
后来在反编译淘宝代码的时候,也验证了这一问题,其底层采用的并非OKHttp或者HttpURLConnection的方法去实现连接,而是使用了基于NDK实现的连接层(后面会讲到)
初步判断是DNS或IPv6问题(其实不是)
-
DNS:这种问题非常让人首先怀疑DNS出了问题,毕竟这种大厂,都会根据当地网络和服务器负载的实际情况,动态解析域名,选择最优的CDN
-
IPv6:另外就是回想起19年双十一前,貌似家里网络对IPv6支持进行了升级,会不会是淘宝的CDN对IPv6兼容有问题
于是保证试试看的心态,改了一下路由器的DNS,尝试过的DNS有:百度DNS(180.76.76.76)、阿里云DNS(223.5.5.5)、114(114.114.114.114)
然而发现并没有什么卵用,还是一样的慢……
想想也有道理,这种大厂App一般都会集成HttpDNS能力,随你怎么改DNS,都不会影响人家的解析
然后就是关掉了IPv6功能,发现还是没用,由于无意间通过Charles抓到几张图片的URL,ping了一下域名,发现其实淘宝的CDN还没有支持IPv6……
所以图片问题,和DNS、IPv6,根本没有任何关系!!!
反馈
-
首先是给淘宝客服反馈:
不知道其他路径能不能有效,反正淘宝App里面的反馈界面就跟摆设一样,没有任何作用!!
-
反馈给在阿里工作的同学:
问我要了一些信息以后,然后说给相关人员反馈一下,后来也没有动静了,据说很难推动去解决。。。
另外,我觉得,对于这种比较诡异的技术问题,还是得有一些有力的证据,可能才好推
被逼无奈,只好搞逆向
既然通过抓包、调试网络环境,以及正规渠道都无法解决问题,那我只好自己排查了
于是准备好这些工具,准备开干:apktool、dex2jar、VSCode、Android Studio、Xposed,另外就是需要一台ROOT后的Android手机,最好是Nexus或者Pixel
当然,也可以考虑使用VirtualXposed(https://github.com/android-hacker/VirtualXposed),这个工具的优点是不需要ROOT就可以使用Xposed的功能,且每次更新Hook不需要重启手机,但是部分场景不太稳定,个人还是喜欢用ROOT以后的手机去装原版的Xposed,不过需要Android 8.1及以下的系统
上述工具的使用,我就不再多说了,直接寻找突破口
利用LayoutInspector找到ImageView
在一台ROOT后的手机上,是可以利用LayoutInspector抓取任何一个App的View的
因为经常刷微淘,而且图片也比较多,加载比较慢,这里以淘宝的微淘模块为例,看看它用的类名是什么
感谢淘宝没有做更深入的类名混淆,微信的部分场景,混淆就做的非常狠,几乎没法看了
于是可以发现这个用于图片显示的类就是TNodeImageView
探究一下TNodeImageView的源码
既然已经定位图片控件,那么可以直接搜Smali文件或者使用Android Studio,在加载使用dex2jar转换而来的Jar包以后,双击Shift搜索(和平时使用Android Studio搜索项目中的类一样)
个人建议首先使用Android Studio或IDEA看Jar包里的源码,如果发现不能被反编译,或者某些App做了防dex2jar转换,再考虑去看Smali,效率高的多,不太推荐用JD-GUI,不如IDEA系列IDE方便
使用VSCode直接搜索Smali文件:
如果使用Android Studio/IDEA,需要把jar包先引入到工程当中:
这里可以发现两个方法:
-
第一个是
setImageUrl
:很明显是一个外部调用,用来设置图片URL的方法,断定这里可以获取到图片的URL
-
第二个是
onImageLoaded
:其参数为一个
BitmapDrawable
对象,猜测是图片加载框架的回调方法,用来设置解码后的图片
尝试修改Smali——放弃
由于找到了图片路径的首个突破口,于是想着修改一下Smali,能够让淘宝直接打印图片URL,然后直接把apk装在手机上测试
经过apktool二次打包和jarsigner的一番折腾,apk是可以装上了
但是发现,很多页面出现白屏,登录也无法使用,并且Logcat会打出一下Security相关的Log
这就说明淘宝做了签名校验,这个方法不可行……
编写Xposed插件,抓取图片URL
由于以上修改源码的办法行不通,那么只能考虑Hook的办法,目前最流行的Hook技术无非就是Xposed了
关于Xposed,我就不再多说了,自行搜索即可,不过自我推荐一下自己写的一个小工具,可以简化Xposed Hook的开发,https://github.com/yuanguozheng/coderyuan-xposed-hook,如有需要,可以自行拿去使用
以下代码即为利用coderyuan-xposed-hook实现对淘宝App「微淘」模块图片组件(TNodeImageView)的setImageUrl方法Hook
@XPHook(
pkgName = "com.taobao.taobao",
applicationName = "com.taobao.tao.TaobaoApplication",
isUseMultiDex = true
)
class TaobaoHookImpl {
@HookMethod(
className = "com.taobao.tao.flexbox.layoutmanager.view.TNodeImageView",
methodName = "setImageUrl",
isHookBefore = false,
paramsCls = [String::class]
)
fun hookTNodeImageView(param: XC_MethodHook.MethodHookParam?) {
param?.args?.forEach {
if (it != null && it is String) {
log("TNodeUrl", it.toString())
}
}
}
}
跑起来以后,可以在Logcat中看到下面这些URL