看我如何让被封掉的微博秽土转生
2018年11月13日,我长期使用的微博(@LeadroyaL 时日不多了)被炸号了,但里面有不少有价值的东西,于是想办法dump出来,新注册微博并且重新发布一遍,不到1000条微博吧,作为一个逆向选手,趁闲暇时间,使用脚本实现了一下。(本文计划写于12月,但拖到了春节前)
先骂再说,傻逼微博!傻逼微博!傻逼微博!瞎 jb 封老子的号!炸老子的号!
全部代码和数据都在 github:https://github.com/LeadroyaL/weibo_repeater
一、前因
2018.11.13附近,流行微博转发抽奖,抽各种各样的锦鲤,但随着结果的公布,网友们渐渐发现中奖的都是女性角色,尤其是微博王思聪转发英雄联盟夺冠的抽奖,抽到的大都是和英雄联盟无关的女性用户,王校长非常生气,于是大家开始分析微博的抽奖结果。
有几个特征:性别为女,活跃,有原创内容,爱发图。于是我和一些朋友就把性别改为女,发一些图片假装自己是活跃用户。
在某天晚上,我发了一个普普通通的表情,没有任何政治隐喻,单纯的表达对领导人的敬佩,该表情是从微博上其他地方偷来的,所以认为是微博允许的表情。第二天上午,有位朋友说我为什么取关他了,我去看了一眼,发现我的号被炸了,是彻彻底底的炸号,自己可以访问,但别人访问不到,没有任何通知和解释,就说违反了规则。
描述一下炸号的表现:从别人的关注列表里消失,与别人的互动全部消失,别人访问来的时候是该用户不存在,登录后无法做出任何交互,全部是失败。
一开始以为是误封,申诉一下就 ok,然后发邮件、找客服、问原因、找 SRC,统统没有办法,最后说涉政永封,我他妈哪里涉政了?我一句坏话都没说,就单单发一个领导人访问民间的照片,网上到处都有,也说老子涉政?你他妈倒是告诉我怎么涉政了啊??
再次重申,微博傻逼!既然都这么对我了,我写这篇技术文章应该也没什么吧,互不相欠。怎么办呢,要不是微博上有一堆大佬和好看的妹子,我早就卸载这傻逼软件了,还能咋地,开始搞呗。
声明:如果因本脚本被封号或限制,请自行承担后果。
二、备份微博数据
这里感谢一下知名女黑客圈圈,多年前写的脚本现在还能用,稍微改改就可以了。说一下目标,我需要dump下来我的全部微博内容和全部的关注人,保留好其中重要的内容,便于将来重新发送。
有个神奇的站点,叫 https://m.weibo.cn
,可以用来爬自己的数据。
非常清晰,非常友好的 json 格式,看起来是按页分的,详情见github 里的content.py 吧。这里需要手动修改的,就是把请求抓下来,所有的参数统统换成浏览器抓下来的参数,缺一不可,因为是爬自己嘛,也没有频率控制的。
获取关注人列表,这里选择另一个站点,叫 http://weibo.cn/uid/follow?page=%d
,可以获取关注人列表,但这里返回是一段html,所以需要用正则把它拿出来,因为每个人肯定都是一个唯一的 uid,所以正则拿一下就好了,找那个取消关注的超链接就行,详情见github里的follow.py 。
这里有个小细节,关注人和粉丝,虽然每页都有10个容器,但有时显示的是不足10的,因为你关注的人被微博智能反垃圾系统给屏蔽了,换句话说,就是这个博主被炸号了!哈哈,没想到吧,傻逼微博!
三、解析数据
稍微看一下数据结构,用脚指头都能猜到大概的意思,对比一下各个微博的区别就能得到有用的信息,这里将微博分为以下几类:
- 无图的原创微博
- 有图的原创微博
- 转发的微博(一定无图)
对我来说,有时间、内容、被转发微博 id就够了,通过 json 内容猜就可以猜到了,因为里面东西非常冗余,详见content_parser.py 。
四、方案一,使用网页版发表微博
ok,先申请一个账号,用来复活之前的内容。
既然从网页版来,那就从网页版去,在我手动发出10条微博后,终于被屏蔽了,可能我手速太快,使用网页版无法发送新的微博,但使用 weibo.com 和 移动端是可以的。
在第二次被限制后,没办法,weibo.com和移动端二选一,我显然选后者,我不想在这种事情上花费太多时间。
五、方案二,使用 xposed 发表微博
由于我喜欢用微博国际版,于是就从微博国际版下手,进行逆向。不得不说,这玩意真的好用,主要的 API 连混淆都没有,类名方法名都不用猜,直接上就 ok。
经过逆向,发现发表微博和转发微博都是同一个 Activity,最后发送一个结构体出去,但结构体里面有很多的变量,我不知道哪些有用哪些没用,手动构造太麻烦了,主要思路如下。
- 初步进行逆向,猜测大概的发送流程
- 构造Intent,进入发送的Activity,而Intent里就存有即将被发送或者转发的数据包
- 构造数据包,修改其中重要的字段,继续之前的发送行为
ok,开始逆向,直接上图吧。
开始硬核内容!
先打开发送微博的页面,如图,看起来是一个普通的 Activity,com.weico.insternational.activity.compose.SeaComposeActivity 。
转发和原创都是这一个界面,而且显然是新建的 Activity、从其他 Activity 来的,所以数据一定是在 Intent 里传递,这里可以选择在合适时机将 Intent 给dump下来,例如下面的代码。
解析完数据后,初始化页面上大部分的布局,就等待用户编辑和确认,跟一下,发现了一个按钮触发的方法。
看起来挺像的,再往后追一下,有个叫uploadDraft ,参数是com.weico.international.model.weico.draft.Draft
,八九不离十就这个了。
所以第一步是,我们点击发送新微博、转发微博时,使用 xposed 记录下这两个Intent,存起来。
然后就是构造数据了,经过第三步的准备,我们已经获取了 【即将发送的文本】和【被转发微博的微博id】,这里使用了一个巧妙的办法。
新建微博比较简单,在拉起 Activity 后,拿到 EditText,对它进行设置文本即可,非常简单。
转发微博是这样的,由两部分组成,一部分是 EditText里的内容,可以进行直接设置,比较坑的是被转发的微博,也是一个巨大的结构体,而里面哪些是关键、哪些不是关键、是否会有校验是我们关心的,这里就需要经过测试了,最后发现有3个字符串与该微博的 id一致,都是 String,管他呢,都覆盖了再说。
经过测试,这样做确实可行,开始写代码,代码见Test.java,写的挺清楚的。
程序执行流程是:
- 在合适时机注册广播,用于从外界接收【即将发送的微博文本】和【即将被转发的微博 id】
- 在SeaComposeActivity.onCreate进行hook,用于收集标准格式的 Intent 内容;
- 点击新建微博、关掉;点击转发微博、关掉。此时在内存里存好了这两个 Intent;
- 外界根据需求(为了方便,我喜欢用adb来发送),发送广播,广播里进行startActivity拉起SeaComposeActivity;
- SeaComposeActivity 会解析Intent内容,填充到内存和文本框里;
- 稍微设置一下定时,之后把文本内容替换为我们即将发送的文本,之后触发send函数。
- 在send函数外,让Flag=false;send 函数里,这时设置一个 Flag=true,并且对 Draft 的获取属性方法放置 hook,当 True 的时候,将转发微博的微博 ID 替换为我们预期的微博 ID,在退出 send 函数时Flag=false;
- ok,此时一条微博就发送出去了,过一个小时再跳回第(4)步即可,因为频繁的话会被封号一周。
对于带图的微博,懒得弄了,总共也只有几十条,手动发一下就 ok 了。
谁来发送这个广播呢?我这里选择用adb操作,将文本用文件的方式传入手机,将其他参数作为 intent 的参数传给我们的接收器广播,见wrapper.py 。
六、进行批量关注
在我恢复完毕所有的微博内容后,我准备把我的关注人也恢复回来,经过深思熟虑和测试,使用 https://weibo.cn/attention/add 这个接口,方法同样,不断测试发送请求的 API 的参数,但这里有坑。
坑点在于,这玩意是有校验的,至少存在两个校验,一个是叫 st 的值,看起来是个随机数,短时间内不变,但偶尔也会变,捉摸不透,会提示失败。另一个校验是 http 请求头里的 referer,不能乱给,给错了就要输入验证码。原先准备使用 requests 直接日,后来每次都提示失败。
最后使用了很 trick 的方法,思路是尽可能模拟正常用户的行为:
- 打开 https://weibo.cn/u/%s ,打开个人主页,从而让 cookie 被初始化;
- 随便关注一个明星,拿一下 st ,写到脚本里;
- 重点来了,使用脚本来新建标签页,直接去访问 https://weibo.cn/attention/add 这个 API,是可以成功的,因为相当于在【进行关注】这个超链接使用了在新建标签页中打开,不违背参数传递的规则,刚好这是个 GET 方法,直接在后面拼接即可;
- 写个脚本,定时杀一下进程,拉起一下进程,sleep 一下防止频控,而且这个会触发验证码,手动输入一下就行,不会很频繁。
总结一下,这个操作可以绕过之前的校验,st 校验手工绕过,http 请求和正常情况完全一致,所以也可以过。
代码见 create_friend.py 。
七、总结
从技术上来讲,我觉得我的 xposed 脚本写的非常巧妙,用最小的代价替换掉了关键内容,减少猜协议、猜字段的工作量,只替换主要参数,让app 自己打包好内容发出去,这样效果最好。另外,使用 python 起浏览器的新建标签页,也非常巧妙,极大减小了构造请求的人力。
Q:为什么不去爬其他的接口?
A:因为懒,挑个软柿子捏就可以了。
坑点在于,不知道微博在哪里有频控,触发之后要等很久才会解除,先公布一下大概值吧:
发微博的话,大于45分钟发一条,不停的发是不会管的;绕过被频控到,是会管的,封号一周;
关注其他人的话,似乎一次可以关注100-150人,然后封号几个小时,就又可以关注了。
后果是,我在好看的微博评论区艾特其他人的时候,对方是收不到的,可能已经被拉入黑名单了,没办法,只能再创建一个号了,这个记事本就让他一直死着吧! 整个流程下来,感觉挺有意思的,和微博安全斗智斗勇,最后还是成功把内容备份出来了,开心~
本文成果在 https://weibo.com/u/6846051698 (@LeadroyaL大号被炸了)
欢迎关注:https://weibo.com/u/6881643437 @LeadroyaL会记得的。