本文主要讲解在短视频APP上逆向抓包遇到的坑,通过本文方法可以顺利使用抓包工具抓到数据包,也可以通过文中介绍的获取proto文件的方法,使用编程语言解析数据包中的内容。
文末还会提供编译好的proto类,可以直接解析response。
一般抓包都是采用中间人的方式,即在客户端用户与网站服务器中间,安插一个代理。所有客户端发送的包与服务器返回的包都经过这个中间人代理转发。
对于https的应用,需要伪造信任证书,对客户端充当服务器,对服务器充当客户端。
开始下载了5.0版的安卓模拟器,下载了比较旧的某音APP 17.3版本,发现是可以抓到包的,但是无法登陆,提示版本过低。所以只能升级APP版本,但升级到最新版发现之前的抓包工具无法抓到包了,提示 SSL Handshake Failed。
[SSL Pinning]分为两种:
在Android N(Android 7.0 API 24)及以后版本,由CA权威机构签发的证书,其根证书都内置在最新的[Android操作系统]中,因此默认情况下可不进行SSL证书锁定。因此该版本之前的安全性设置仍然需要使用证书锁定方法,即自建证书在客户端强制判断,以达到防止中间人攻击(MITM)的目的。
客户端在收到服务器的证书后,对该证书进行强校验,验证该证书是不是客户端承认的证书,如果不是,则直接断开连接。所以会出现 SSL Handshake Failed 的情况。想破解客户端证书锁定有以下几种方式:
如果是安卓7以上,因为有系统功能限制,可以尝试将mitm证书安装到系统目录。
系统证书的目录是:/system/etc/security/cacerts/
每个证书的命名规则为:
证书的 hash 值可以由命令计算出来,在终端输入 openssl x509 -subject_hash_old -in
,其中
抖音是使用自建证书,此方法无效
Xposed框架是一套开源的、在Android root模式下运行的框架,它可以在不修改APP源码的情况下通过Hook方式去影响程序的运行。
JustTrustMe 是一个用来禁用、绕过 SSL 证书检查的基于 Xposed 模块。JustTrustMe 是将 APK 中所有已知用于校验 SSL 证书的 API 都进行了 Hook,从而绕过证书检查。
安装xposed需要root手机,且安装繁琐,启动APP时需要同时启动该框架。
但是抖音是采用自建证书来实现,JustTrustMe内置方法无法匹配到关键函数名。
使用IDA PRO打开so文件,通过搜索cert等关键字,一顿搜索之后发现。看返回值是1,但是经过查阅发现 返回值为0的时候才是 ssl_verify_ok
所以我们动下小手给他改成0,然后apply patchs,将so文件保存。
然后把修改过的so复制到你的安卓手机上,这种方案,手机必须ROOT,因为我们要替换lib下面的libsscronet.so,修改一下文件权限重启APP即可抓包
联想模拟器:adb connect 127.0.0.1:11509
mumu模拟器:adb connect 127.0.0.1:7555
adb connect 127.0.0.1:11509
adb push ./libsscronet20.7.so /data/app/com.ss.android.ugc.aweme-1/lib/arm
adb shell
rm -rf /data/app/com.ss.android.ugc.aweme-1/lib/arm/libsscronet.so
mv /data/app/com.ss.android.ugc.aweme-1/lib/arm/libsscronet20.7.so /data/app/com.ss.android.ugc.aweme-1/lib/arm/libsscronet.so
chmod 777 /data/app/com.ss.android.ugc.aweme-1/lib/arm/libsscronet.so
拿到数据包之后发现里面文字显示都不正常,通过请求头发现,原来使用的谷歌的protobuf协议,类似json和xml用于两端数据传输,因为protobuf更节省空间,传输过程中将变量名省略,变量名都以文件的方式存储在服务器和客户端上,所以我们需要使用Python的
blackboxprotobuf库来解析。
import blackboxprotobuf
with open('./douyin_.txt', 'rb') as f:
print(blackboxprotobuf.protobuf_to_json(f.read()))
或者也可以使用官方protoc解析。需要先下载[protoc]
import subprocess
def decodes(data):
"""
如果上传到linux线上服务器,需要chmod+x protoc赋予权限。
"""
process = subprocess.Popen([r'protoc', '--decode_raw'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = error = None
try:
output, error = process.communicate(data)
except OSError as e:
pass
finally:
if process.poll() != 0:
process.wait()
return output
with open('./douyin_.txt', 'rb') as f:
data = str(decodes(f.read()), encoding='utf8')
print(data)
但是以上方法均不能拿到对应键值,取数据时比较麻烦。
方法来源于这个帖子[抖音直播间弹幕protocbuf分析]
首先用jadx反编译apk包。因为某音最新版(21.8)安装包较大。本人的16G机器hold不住。所以本人用的是低版本的apk包(之后借用了公司服务器,将反编译代码下载下来了,这里可以提供下载地址)。反编译后通过搜索抓包抓到的接口地址。
之后查看这个类,需要的字段以及类型都在这里了。13.9版本的proto文件都在这个文件夹里,提取会很方便 。
后来拥有了大内存的机器,又尝试反编译了一下21.8版本的,大概需要使用40g的内存才能反编译完成。可以搜索encodeWithTag来找到encode()函数,我们发现proto文件分散到各个文件夹中了。寻找起来可能有点麻烦,但是提取的方法还是一样,没有变化。
之后就是通过该proto文件生成对应语言的版本。我这里用的是Python,于是使用该命令生成Python文件
protoc ./Sajor.proto --python_out=./
然后使用该文件解析请求返回的数据。
import json
from google.protobuf.json_format import MessageToDict
from proto import sajor_pb2
with open('./douyin.txt', 'rb') as f:
a = f.read()
info = sajor_pb2.aweme_v2_feed_response()
info.ParseFromString(a)
print(json.dumps(MessageToDict(info, preserving_proto_field_name=True), ensure_ascii=False))
proto与blackboxprotobuf
blackboxprotobuf是个不错的开源库,但是解析的速度与可靠性有些问题,通过对同一个文件的解析,做个对比。
blackboxprotobuf
proto
那是因为 blackboxprotobuf 在内部是使用递归的方式,逐步猜测要解析数据的类型格式。一不小心就会陷入循环中。。
至此,可以成功采集并解析数据包了。