android 爬虫 协议分析,安卓逆向:分析抖音登录协议

发布于:2023-05-22 ⋅ 阅读:(571) ⋅ 点赞:(0)

新版D音由于插入了过多破坏性代码,已经无法由jadx反编译成功了,太多地方都解析失败。我尝试用MT管理器换引擎反编译,也都是一样的结果。这里如果想分析,需要jadx结合smali代码硬啃。我对着smali啃了一个参数,有些蛋疼。。于是还是用豌豆荚下了历史版本,反编译看java了。

抓包

首先还是登录抓包:

b2ed3fb1fe84?utm_campaign=haruki

b2ed3fb1fe84?utm_campaign=haruki

首先是post请求,有query、body、cookie和另外的一些字段。换个手机号登录再抓一次作对比。参数太多,不方便看,切换到WebForms选项卡,对比参数,首先是query。第一次抓包:

b2ed3fb1fe84?utm_campaign=haruki

第二次抓包:

b2ed3fb1fe84?utm_campaign=haruki

可以看到变化的只有 ts 和 _rticket,很容易看出来,一个是10位时间戳,一个是13位时间戳。那么query方面可能没有我们太需要关注的地方。

然后body:

b2ed3fb1fe84?utm_campaign=haruki

手机号与密码经过了加密。再看下其他内容:

b2ed3fb1fe84?utm_campaign=haruki

b2ed3fb1fe84?utm_campaign=haruki

X-Khronos与X-SS-REQ-TICKET依然是时间戳,这里需要注意的参数是X-Gorgon、X-SS-STUB和x-tt-trace-id。对比两次请求,我们发现x-tt-trace-id里中间有一部分与末尾部分是相同的,猜测与cookie或是一些本地配置参数有关。cookie重新打开了几次,也没有发生变化,暂时也不看。这个cookie的生成盲猜要比登录协议复杂得多。

那么确定下来需要找的参数:body中的password、mobile、header中的X-Gorgon、X-SS-STUB和x-tt-trace-id。

分析

还是惯例,jadx全局先搜一波url呗。

b2ed3fb1fe84?utm_campaign=haruki

很容易的就找到这里。可以看到在将手机号与密码put进map之前,执行了StringUtils.encryptWithXor函数:

b2ed3fb1fe84?utm_campaign=haruki

比较简单,先转成bytes数组,逐位与5进行亦或,最后再转成16进制拼接为字符串。验证一下:

b2ed3fb1fe84?utm_campaign=haruki

b2ed3fb1fe84?utm_campaign=haruki

相同。密码同样。

然后分析header中的字段。搜索X-Gorgon,找到这个类:

b2ed3fb1fe84?utm_campaign=haruki

一个匿名类,我们hook一下a方法。这里夜神模拟器的firda又出问题了,换真机测试。。hook脚本与输入结果如下:

b2ed3fb1fe84?utm_campaign=haruki

b2ed3fb1fe84?utm_campaign=haruki

第一个参数str也就是完整的url,第二个参数map就是所有其他的headers参数,包括cookie、x-ss-req-ticket、user-agent、accept等参数。同时x-tt-trace-id与X-SS-STUB在此之前就已经赋值:

b2ed3fb1fe84?utm_campaign=haruki

回到代码分析,我们找到X-Gorgon的来源:a3,a3是通过调用上面的函数得到的。

b2ed3fb1fe84?utm_campaign=haruki

大概要找出来的参数有:i,a2,str4,str5,str6,那个currentTimeMillis是10位int类型的时间戳。

我们先hook最后的a.a方法,看看a2、str4、str5、str6是什么:

b2ed3fb1fe84?utm_campaign=haruki

几乎没任何参考价值。。还是一步一步看。

a2:

b2ed3fb1fe84?utm_campaign=haruki

由d.a(b2)得到,b2由tt.d(str)得到,str是url。看看tt.d做了什么:

b2ed3fb1fe84?utm_campaign=haruki

对url进行了切割,获取?到#的部分,也就是query部分。再看d.a():

b2ed3fb1fe84?utm_campaign=haruki

对query部分进行md5,解决一个。

str4:从Map中取X-SS-STUB,如果有则赋值,否则赋为32个0;

b2ed3fb1fe84?utm_campaign=haruki

str5和str6都在这里:

b2ed3fb1fe84?utm_campaign=haruki

首先是str5,对cookie进行md5。str6对cookie先调了tt.e():

b2ed3fb1fe84?utm_campaign=haruki

就是从cookie里取sessionid,然后再md5。以上4个参数如果为空,就赋32个0。最后是a.a:

b2ed3fb1fe84?utm_campaign=haruki

b2ed3fb1fe84?utm_campaign=haruki

各种位运算。懒得看了。接下来分析i:

b2ed3fb1fe84?utm_campaign=haruki

如果map中有“META-SHADOWMAZE”则为1,否则为-1。

然后是一个巨长无比的调用链:

b2ed3fb1fe84?utm_campaign=haruki

最外层的a:

b2ed3fb1fe84?utm_campaign=haruki

以及发现惊喜的leviathan,native!惊不惊喜意不意外!不往下看了🙈!

b2ed3fb1fe84?utm_campaign=haruki

上面还漏了两个大坑:x-tt-trace-id与X-SS-STUB。

全局搜索X-SS-STUB,定位到下面:

b2ed3fb1fe84?utm_campaign=haruki

跟进:

b2ed3fb1fe84?utm_campaign=haruki

接口+抽象方法。现在我们掌握的线索有,真实调用的类一定继承自TypedOutput,并且实现了md5Stub()方法。全局搜索String md5Stub():

b2ed3fb1fe84?utm_campaign=haruki

这里就不太好看了,尝试用frida打印调用栈,只要找到调用栈,我们不就知道到底走的哪条路线了吗。但是使用frida启动时遇到:

b2ed3fb1fe84?utm_campaign=haruki

这是由于activity没有指定被调用的Intent,我在Manifest.xml中加入后依然报错,遇到了知识盲区,暂时无法解决。那么换一个思路,可以选择去hook每一个方法,或者动态调试。对于自己来说目前可能还是hook比较顺手,而且这几个方法也比较简单,直接去hook就可以,看打印出哪个那就是了。最终确定,这里真实调用的是com.bytedance.retrofit2.mime.b类中的md5Stub()。

b2ed3fb1fe84?utm_campaign=haruki

查找md5Stub的用例却没有查找到。观察b中没有构造方法,其中的主要类变量f31162a是在a方法中初始化:

b2ed3fb1fe84?utm_campaign=haruki

追踪a的调用,一共有两处,我们来到了这里:

b2ed3fb1fe84?utm_campaign=haruki

继续找调用它的地方。

b2ed3fb1fe84?utm_campaign=haruki

有点眼熟啊,貌似是从Map里取了一些参数。Map很有可能是query、body、或者header中的某些部分。再回去看上面负责初始化f31132a的a方法,就是把传过来的参数一一组合,以&和=做连接。

既然我们已经知道b类中的md5Stub一定会被调用,而a又是初始化md5Stub中参数f311332a的唯一途径,那么可以按照如上的思路,编写hook代码,尝试还原最终拼接后的参数:

b2ed3fb1fe84?utm_campaign=haruki

b2ed3fb1fe84?utm_campaign=haruki

这不就是post的请求体吗?再回去看调用链:

b2ed3fb1fe84?utm_campaign=haruki

先对上面的字符串取md5,再对结果执行a方法:

b2ed3fb1fe84?utm_campaign=haruki

又是一些位运算,结果就是最终的X-SS-STUB。

总结

java层还是属于皮毛,真正难的地方在so层,D音so层加载Map足以让人绝望。这次在找x-ss-stub的时候,迟迟定位不到关键代码,全局搜索不出来,方法剖析和打印调用栈都GG的情况下,略有小懵。不过能用的方法还是太多了,总有一款适合你。。。

声明声明:本文分析过程仅供学习,并无任何个人以及商业或其他用途。如有不慎侵权,请联系我删除。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到