本文导火索:不靠某音吃饭,所以啥时候更新的咱也不知道,刚好有老板滴滴我,说帮看看明天就v我50,那就来吧!!!

那么接下来进入正题:
目标:视频详情接口:L2F3ZW1lL3YxL3dlYi9hd2VtZS9kZXRhaWwv
直接上XHR断点

还是熟悉的配方,上一篇文章已经知道了bdms是vmp文件,估计加密还是在这里面生成的,按道理应该在前一个堆栈打断点

但新版某音已经不管用了,这里按正常逻辑打日志断点:y.openArys啥啥啥的你只能看到已经加密好的结果,甚至你的每一次刷新页面,这个断点的位置都可能不是y.send。没错,堆栈会变
但是vmp加密也不可能一个断点一个断点去调试,毕竟人家的调用次数可能比我年薪(以块为单位)都多
这里我选择往前继续找合适的堆栈位置下断,再往下一层

这里有params,并且这个时候a_b还没有加入大部队,先从这里开始下断单步调试。条件断点:e.url === “自己去看url是啥”。刷新页面成功断住,咱先单步走,记住上一步执行到哪,以防随时跳转

前面走完并没有出现我们要找的,这里注意y.send§,在这个位置再次单步执行就直接apply,并且this中已经有了a_b
说明y.send§进入了全新的世界
重新刷新页面,再次断在了前面下断点的地方,这次我们直接在y.send§下断跳过来,然后进入(F11)。这里需要注意,前面说过了抖音每次刷新都可能走不同逻辑,这里就是其中一个点,有时候F11进入会直接进到vmp文件,当然不是说不行,这也可以是个入口,只是没那么好梳理。我进入的位置是这样:

我们继续单步执行,然后你就会发现,在执行完t.xhrAsyncSend ? Promise.resolve().then(n).catch((function()这行代码之后又直接跳到了apply结果已经生成的位置,说明这里又进了某个关键逻辑。再次刷新页面重复前面的步骤,这一次我们在t.xhrAsyncSend ? Promise.resolve().then(n).catch((function()的地方进去

这就没必要单步了,总共三行代码,后面两行是delete不用走了。直接F11进去

来,继续单步

到forEach这里再单步还是会结束,所以这里F11进去。走到这里不得不提一嘴

t.origin.apply(e, u)调用的是vmp文件,并且传入了没有a_b的url作为参数。这个url肯定是要作为加密值所需参数传入的,所以这里很可疑,感兴趣可疑进去调试一下。我已经走过了就不走了,直接告诉大家结果,这里并不是加密位置,进去再出来a_b也没有生成。然后这里面还有多个t.origin.apply(e, u),单步执行就能看到。而真正的加密入口在第四次进入forEach之后

也就是send条件中这个,e中包含了我们所需的所有东西。这里F11进去就会正式进入vmp文件

进来后这里有个d函数,这个函数也是我们一开始打xhr断点时堆栈中显示的关键函数,进入d就开始没法看了,看花眼的if else。没办法单步调试了,毕竟前面也说了这玩意执行次数比我年薪都多。那怎么办?vmp技巧:搜apply。而在这个函数中apply只有两个,并且只有一个是函数调用

这个也也是我们xhr断点显示的一处关键堆栈。终于可以开始日志断点了家人们。怎么打日志断点不用教了吧?我们把mnde都打印一下。
下好断点后先别打钩,不然一会日志太多容易卡死。选择前面的t.origin.apply(e, u)下条件断点(其它断点可以删掉了)。只保留这个,以及日志断点跟xhr断点。并且日志断点不打钩。

断住后再勾选日志断点,然后等走到xhr断点再取消日志断点。

然后看日志,可以看到a_b确实是这个位置出的,并且是由m值一个字符一个字符拼接的。不过这不是重点,毕竟我们不搞(搞不来)纯算,补环境不需要在意这个。只需要知道a_b在运行到某个环节的时候赋值给了e,而我们要做的就是给他加密所需参数,再拿回这个值就可以了。最好的位置当然就是在进入vmp文件的前一步,也就是t.origin.apply(e, u)。
vmp文件全部拷出,导出ab

怎么导出也教了哦
然后写程序主入口让其运行。

再就是补上所需环境了,补完就可以调用啦

顺利拿到结果
再提醒两点:1、日志断点的流程非常重要,补完环境记得浏览器联调,对比一下自己的跟网站的流程是否大差不差,如果出不来结果,那大概率就是环境缺失,那就认真去参照日志断点;2、拿到ab值后程序会报错throw l,毕竟我们没法真的去send,这里要么在导出ab后直接process.exit(1)结束进程,但是这样跟python交互比较麻烦不建议,要么就是在报错的位置try catch一下。
嗯,就这样。收工!
