记一次B站投稿工具逆向

1. 动机

之前写了一个工具,可以自动录制直播平台并且自动上传B站。上传部分用的是comwrg大佬的bilibiliupload包。但是从2020年三月左右开始,B站官方把网页投稿多P的api关了,由于bilibiliupload包是基于网页投稿的,所以3月就开始没法传多P的视频了。我一直在等B站重新开放,但是都快到6月了也没开放。所以无奈之下只好开始逆向投稿工具(pc投稿工具和手机端可以传多P视频)。

2. 工具

x64dbg调试器

fiddler抓包验证

Cheat Engine扫内存(x64dbg内置扫内存不给力)。

3. 开搞

之前写程序的时候有抓过B站登录和上传的包。

image01

所有的请求都有一个sign作为验证。Sign已经有很多人研究过了,就是把所有参数按照key排序,加上一个和appkey相对应的appsecret然后做md5。

Appkey明文就在请求里,麻烦的在于appsecret的值是多少,这就是逆向的目的。

那么首先把投稿工具加载到调试器里,启动。

image02

发现有一大堆线程。一个一个的试着把进程结束掉看是否可以正常发送带有sign的请求,从而确定sign逻辑在哪里。

结果:

结束掉RequestConnectionNetworkIO线程会导致http发不出去,但是可以用CE扫出sign,排除RequestConnectionNetworkIO

其他线程结束掉会不定时导致程序崩溃,但sign还是可以用CE扫出来。

所以最终确定:sign逻辑在主线程BiliBiliMain里。

image03

由于已知是用MD5做hash,所以在所有MD5相关的库函数下断点。下完断点运行发现带有sign请求还是正常发出。

我觉得有点奇怪所以把所有的加密/解密/哈希库函数都下了断点又试了一次,发现登录逻辑的第一个请求B站RSA公钥的请求正常发出,用RSA公钥加密用户密码的逻辑断下来了。

于是乎,我认为投稿工具在做sign的MD5操作时并没有用任何库,可能是自己写了个MD5逻辑。

第一个思路:从socket函数下断点,一层一层找调用,确认sign逻辑位置。

image04

tcpip6_wshopensocket2 <- socket <- bilibili_secret.dll 但是最终无果,堆栈回溯卡在了SEH链上。由于对SEH没有太深的了解,放弃了这个思路。

第二个思路是:既然已经确定在主线程中,那么先找消息处理函数,然后通过登录按钮的点击慢慢找sign。

结束掉其他线程很可能会导致消息循环里面出现内存访问错误,所以试了几次确定了疑似消息处理函数的位置。

image05

image06

一次偶然的内存错误的时候我发现有个地方栈内有sign要加密的内容,于是标记了下来

image07

在这里断下来,用CE搜,刚好搜不到sign,确认了这里也许是sign逻辑前的地方。

再多跑几次,发现确实运行到这里时内存搜不到sign。Continue几次之后sign就能搜到了。 所以确认了sign逻辑大概的位置(狗屎运?)。

image08

然后慢慢步进,发现了一个疑似给哈希算法输入的地方。

对于7863DB13这条跳转语句执行的时候,not taken的时候有寄存器会指向“appkey=xxx&platform=pc&ts=xxx”这个字符串里的一个个字符,等寄存器指到最后的时候跳转成功。

已知sign是对请求参数+appsecret做md5,那么接下来就是要找添加appsecret的地方。我认为B站应该不会把appsecret明文写在程序里读出来,应该是用一些指令把它生成出来,于是开始留意对内存写值的地方。

image09

往后步进,找到一些疑似写固定值到某内存位置的指令,感觉和加密函数很近了。

一边步进一边用CE搜索,发现步进的时候有时会往参数后面加字符。

image10 image11 image12

这不就是appsecret吗!!!

慢慢继续跟,发现长度加到64字节就停了,MD5的block正好是64字节。

好消息是appsecret的前15位应该就是它了,坏消息是后17位还要继续跟。

试了好多次,把后17位从附近的内存中找出来了(用的方法比较笨)。

最后把appsecret15+17拼到一起,python写个请求验证下,成功。

image13

image14

image15

4. 后记:

其实这次是我第一次成功的逆向。感觉自己并没有用太高超的技巧..在库函数断点里卡了两天才想到可能是自己实现的md5算法。后面找合适的断点感觉全凭运气hhhh

总结的时候思路清晰但是做的时候真的是一头雾水。。可能我还需要继续积累经验吧。

有了appsecret,python写自动上传就很快了,只需要抓包,模拟请求即可,后面自动上传开发就轻松了

AppSecret: af125a0d5279fd576c1b4418a3e8276d