写在前面
Python 课最后的大作业,跟大哥们一起写这个小玩意,因为学院好像很喜欢刷这些东西,总体来说挺简单的
分到我的模块刚刚好需要手机抓包,网页端易班登陆进去没有发动态的模块了,模块在维护 后续会更新其他人的板块并尝试做出来真正的模拟登陆(逆向app或者使用appium提取loginToken)
源码
# -*- coding: utf-8 -*- """ @Time : 2021/5/5 @Author : C1everF0x @File : dongtai @Description : """ import re import requests import urllib.parse def login(): ''' 登录模块其实没有真正实现,网页端登录已经能通过逆向分析 login.js 文件来获取易班对密码在前端的加密算法,可以真正实现模拟登录 app端无法通过抓包或分析接口地址来找到加密方式 第一次输入密码登陆过后,app会将 loginToken 嵌入到 app 里,下次打开会提取拼接到 autologin 接口的 url中 目前能想到的 app 端实现真正模拟登录两种方法: 1、app 端在登录时候对密码的加密是嵌在 app 的源码里,真要做可以通过逆向分析 app 源码,找到加密代码逆向破解 2、使用类似于 seleium 的 appium 来实现模拟真正的人进行登录,再从中提取出 loginToken 目前实现只能够是抓包拿 loginToken 来给到 autologin 接口进行伪造登录 2021.05.07 :return: ''' url = "https://mobile.yiban.cn/api/v3/passport/autologin?access_token=e3017321cf9cdae74e34061cf7adef4a" header = { 'User-Agent': 'YiBan/4.9.9 Mozilla/5.0 (Linux; Android 5.1.1; MI 9 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.136 Mobile Safari/537.36', 'Authorization': 'Bearer e3017321cf9cdae74e34061cf7adef4a', 'loginToken': 'e3017321cf9cdae74e34061cf7adef4a', 'AppVersion': '4.9.9', 'Content-Type': 'application/json', 'Accept-Encoding': 'gzip, deflate' } try: r = requests.get(url = url,headers = header) r.raise_for_status() # 判断异常 r.encoding = r.apparent_encoding # 设置编码 return '登录成功' except: return '登录失败' class DongTai: def __init__(self,token,neirong_dongtai,neirong_pinglun): # 初始化类里面的私密属性 self.__token = token self.neirong_dongtai = neirong_dongtai self.__dongtai_hao = None self.neirong_pinglun = neirong_pinglun def release(self,neirong_dongtai): ''' 自动发布动态,动态内容需要进行一次 url 编码 动态发布成功后会返回一个 json ,里面有每个动态专属的一个九位数的号码 之后对动态进行的点赞、评论操作,需要通过该号码定位是哪条动态 :return: ''' url = r'https://mobile.yiban.cn/api/v3/feeds/?access_token=' + self.__token + '&content=' + urllib.parse.quote(neirong_dongtai) + '&visibleScope=0&artwork=0&toUserIds=&address=&lat=&lng=&share=0&shareTitle=&shareUrl=&shareContent=&shareImage=&shareSource=&kind=1&hiddenAddress=0' header = { 'User-Agent': 'YiBan/4.9.9 Mozilla/5.0 (Linux; Android 5.1.1; MI 9 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.136 Mobile Safari/537.36', 'Authorization': 'Bearer e3017321cf9cdae74e34061cf7adef4a', 'loginToken': 'e3017321cf9cdae74e34061cf7adef4a', 'AppVersion': '4.9.9', 'Content-Type': 'application/x-www-form-urlencoded', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '0', } try: r = requests.post(url,headers = header) r.raise_for_status() r.encoding = r.apparent_encoding response_json = r.text re_response_json = re.findall(r'\d{9}',response_json) # 正则匹配提取动态号码 self.__dongtai_hao = ''.join(re_response_json) # 赋给私有变量 return '发布成功,该动态 id 为 {}'.format(self.__dongtai_hao) except: return '发布失败' # 返回 json 样例,feedId 是动态号码 # {"response": 100, "message": "\u8bf7\u6c42\u6210\u529f", # "data": {"feedId": 294594341, "feedCheckinReward": null}} def give_good(self): ''' 自动给动态点赞 :return: ''' url = r'https://mobile.yiban.cn/api/v3/feeds/' + self.__dongtai_hao + r'/ups?access_token=' + self.__token header = { 'User-Agent': 'YiBan/4.9.9 Mozilla/5.0 (Linux; Android 5.1.1; MI 9 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.136 Mobile Safari/537.36', 'Authorization': 'Bearer e3017321cf9cdae74e34061cf7adef4a', 'loginToken': 'e3017321cf9cdae74e34061cf7adef4a', 'AppVersion': '4.9.9', 'Content-Type': 'application/x-www-form-urlencoded', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '0', } try: r = requests.post(url, headers=header) r.raise_for_status() r.encoding = r.apparent_encoding return '点赞成功' except: return '点赞失败' def comments(self,neirong_pinglun): ''' 自动给动态评论,内容需要进行一次 url 编码,通过之前发布存入私有变量的动态号码来确定需要评论哪条动态 :return: ''' url = r'https://mobile.yiban.cn/api/v3/feeds/' + self.__dongtai_hao + '/comments?access_token=' + self.__token + r'&content=' + urllib.parse.quote(neirong_pinglun) + r'&toUserId=&toCommentId=' header = { 'User-Agent': 'YiBan/4.9.9 Mozilla/5.0 (Linux; Android 5.1.1; MI 9 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.136 Mobile Safari/537.36', 'Authorization': 'Bearer e3017321cf9cdae74e34061cf7adef4a', 'loginToken': 'e3017321cf9cdae74e34061cf7adef4a', 'AppVersion': '4.9.9', 'Content-Type': 'application/x-www-form-urlencoded', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '0', } try: r = requests.post(url, headers=header) r.raise_for_status() r.encoding = r.apparent_encoding return '评论成功,评论内容为 {}'.format(neirong_pinglun) except: return '评论失败' if __name__ == "__main__": print(login()) token = 'e6262d37a192f6be11c159f4080326d9' neirong_dongtai = input('请输入动态内容:') neirong_pinglun = input('请输入评论内容:') dongtai = DongTai(token,neirong_dongtai,neirong_pinglun) # 实例化动态类,需要提供 loginToken,发布动态内容和评论内容 print(dongtai.release(neirong_dongtai)) print(dongtai.comments(neirong_pinglun)) print(dongtai.give_good())
最后结果如图:
整体流程
-
流程图如下
知识点
-
使用 requests 库编写爬虫程序,实现模拟真实用户进行发布动态、评论动态和点赞动态的功能
-
使用 re 库对发布动态成功后的返回包进行解析,提取发布成功的动态的动态号码
-
搭建安卓虚拟机 + xposed 框架 + justTrustMe 模块,因为 app 可以自己检验 SSL 握手时服务器返回的证书是否合法,“SSL pinning” 技术指在 app 中只信任固定的证书和公钥,安卓 7.0 以上把证书分为系统证书和用户证书,有些 app 只信任系统证书,真实手机抓包会提示手机没网,所以需要使用 xposed 框架 + justTrustMe 模块,来 hook 掉本地证书强校验的逻辑,同时导入 burp 的证书,使其流量通过 burp,实现手机抓包
Xposed 框架是一款开源框架,其功能是可以在不修改 APK 的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作
JustTrustMe 一个用来禁用、绕过 SSL 证书检查的基于 Xposed 模块。简单来说,JustTrustMe 是将 APK 中所有用于校验 SSL 证书的 API 都进行了 Hook,从而绕过证书检查的
-
抓包分析各个功能对 api 请求的 url 构造格式和 http 请求头的伪造方法
-
使用面向对象编程,将三个功能封装成类,方便团队进行最后的代码拼接
模拟登录
模拟登录模块其实没有真正实现,网页端登录已经能通过逆向分析 login.js 文件来获取易班对密码在前端的加密算法,可以真正实现模拟登录 app 端无法通过抓包或分析接口地址来找到加密方式 在 app 里第一次输入密码成功登陆后,app 会将 loginToken 嵌入到 app 里,下次打开会提取拼接到请求 autologin api 接口的 url 中 目前能想到的 app 端实现真正模拟登录两种方法: 1、app 端在登录时候对密码的加密是嵌在 app 的源码里,真要做可以通过逆向分析 app 源码,找到加密代码逆向破解 2、使用类似于 seleium 的 appium 来实现模拟真正的人进行登录,再从中提取出 loginToken 目前实现只能够是抓包拿 loginToken 来给到 autologin 接口进行伪造登录
抓取 loginToken
- 假设已经配置好了安卓虚拟机环境,在安卓虚拟机上打开易班,同时用 burp 抓包
-
保存下来复制到代码里面,替换掉所有需要用到的地方
自动发布动态
自动发布动态,动态内容需要进行一次 url 编码 动态发布成功后会返回一个 json ,里面有每个动态专属的一个九位数的号码 之后对动态进行的点赞、评论操作,需要通过该号码定位是哪条动态
抓包分析
- 发布动态时需要在 url 中添加 access_token 参数,内容为之前抓取到的 loginToken,在 http 请求头里面还存在两个需要用到 loginToken 的头
自动评论动态
自动给动态评论,评论内容需要进行一次 url 编码,通过之前发布存入私有变量的动态号码来确定需要评论哪条动态
自动点赞动态
拼接需要点赞的动态号进入请求点赞 api 的 url 中,请求即可完成点赞