记一次B站投稿工具逆向
1. 动机
之前写了一个工具,可以自动录制直播平台并且自动上传B站。上传部分用的是comwrg大佬的bilibiliupload包。但是从2020年三月左右开始,B站官方把网页投稿多P的api关了,由于bilibiliupload包是基于网页投稿的,所以3月就开始没法传多P的视频了。我一直在等B站重新开放,但是都快到6月了也没开放。所以无奈之下只好开始逆向投稿工具(pc投稿工具和手机端可以传多P视频)。
2. 工具
x64dbg调试器
fiddler抓包验证
Cheat Engine扫内存(x64dbg内置扫内存不给力)。
3. 开搞
之前写程序的时候有抓过B站登录和上传的包。
所有的请求都有一个sign作为验证。Sign已经有很多人研究过了,就是把所有参数按照key排序,加上一个和appkey相对应的appsecret然后做md5。
Appkey明文就在请求里,麻烦的在于appsecret的值是多少,这就是逆向的目的。
那么首先把投稿工具加载到调试器里,启动。
发现有一大堆线程。一个一个的试着把进程结束掉看是否可以正常发送带有sign的请求,从而确定sign逻辑在哪里。
结果:
结束掉RequestConnectionNetworkIO线程会导致http发不出去,但是可以用CE扫出sign,排除RequestConnectionNetworkIO
其他线程结束掉会不定时导致程序崩溃,但sign还是可以用CE扫出来。
所以最终确定:sign逻辑在主线程BiliBiliMain里。
由于已知是用MD5做hash,所以在所有MD5相关的库函数下断点。下完断点运行发现带有sign请求还是正常发出。
我觉得有点奇怪所以把所有的加密/解密/哈希库函数都下了断点又试了一次,发现登录逻辑的第一个请求B站RSA公钥的请求正常发出,用RSA公钥加密用户密码的逻辑断下来了。
于是乎,我认为投稿工具在做sign的MD5操作时并没有用任何库,可能是自己写了个MD5逻辑。
第一个思路:从socket函数下断点,一层一层找调用,确认sign逻辑位置。
tcpip6_wshopensocket2 <- socket <- bilibili_secret.dll 但是最终无果,堆栈回溯卡在了SEH链上。由于对SEH没有太深的了解,放弃了这个思路。
第二个思路是:既然已经确定在主线程中,那么先找消息处理函数,然后通过登录按钮的点击慢慢找sign。
结束掉其他线程很可能会导致消息循环里面出现内存访问错误,所以试了几次确定了疑似消息处理函数的位置。
一次偶然的内存错误的时候我发现有个地方栈内有sign要加密的内容,于是标记了下来
在这里断下来,用CE搜,刚好搜不到sign,确认了这里也许是sign逻辑前的地方。
再多跑几次,发现确实运行到这里时内存搜不到sign。Continue几次之后sign就能搜到了。 所以确认了sign逻辑大概的位置(狗屎运?)。
然后慢慢步进,发现了一个疑似给哈希算法输入的地方。
对于7863DB13这条跳转语句执行的时候,not taken的时候有寄存器会指向“appkey=xxx&platform=pc&ts=xxx”这个字符串里的一个个字符,等寄存器指到最后的时候跳转成功。
已知sign是对请求参数+appsecret做md5,那么接下来就是要找添加appsecret的地方。我认为B站应该不会把appsecret明文写在程序里读出来,应该是用一些指令把它生成出来,于是开始留意对内存写值的地方。
往后步进,找到一些疑似写固定值到某内存位置的指令,感觉和加密函数很近了。
一边步进一边用CE搜索,发现步进的时候有时会往参数后面加字符。
这不就是appsecret吗!!!
慢慢继续跟,发现长度加到64字节就停了,MD5的block正好是64字节。
好消息是appsecret的前15位应该就是它了,坏消息是后17位还要继续跟。
试了好多次,把后17位从附近的内存中找出来了(用的方法比较笨)。
最后把appsecret15+17拼到一起,python写个请求验证下,成功。
4. 后记:
其实这次是我第一次成功的逆向。感觉自己并没有用太高超的技巧..在库函数断点里卡了两天才想到可能是自己实现的md5算法。后面找合适的断点感觉全凭运气hhhh
总结的时候思路清晰但是做的时候真的是一头雾水。。可能我还需要继续积累经验吧。
有了appsecret,python写自动上传就很快了,只需要抓包,模拟请求即可,后面自动上传开发就轻松了
AppSecret: af125a0d5279fd576c1b4418a3e8276d