VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > python入门教程 >
  • 易班校内轻应用智慧学工JS逆向、模拟登陆、每日打卡

一、前言

  因为每天晚上十点钟要求在易班中的一个轻应用进行校区定位打卡,但是只有一个小时,这个时间点作为和舍友快乐五排的时间,总是忘记打卡。因此就想着做一个自动打卡的,挂载在云函数中,也不需要单独的服务器,每天定时运行,岂不是美滋滋。

二、发现问题

  首先,这个易班是一个手机APP,但是我在电脑网页端查看了易班官网,发现就算是登录后依然不能进行打卡相关操作,所以只能把目标再次转回到手机APP中,利用手机的HttpCanary对其进行了抓包。但是呢,因为高版本安卓手机的整数问题,打开抓包APP都不能登陆。轻应用在易班中呈现一种站内链接跳转的方式,因此,决定先关闭抓包,进入APP,在直接点击进入打卡的链接跳转,毕竟只用获取到用于post打卡信息的url即可,最后发现先进入所有打卡列表的页面,再进行抓包是可行的。

  通过抓包之后,获取到了post打卡信息的url,发现请求头中有一个Authorization的验证,是一个加密信息。

于是对authorization加密信息进行base64的解密,解密完发现这个东西由三部分组成,前两部分只进行了base64加密,第三部分应该是还有别的加密。base64解码后显示是乱码。

看来这条路是行不通的。但是,经过试验,发现了打卡的轻应用在“我的”页面中是可以点击退出登录的,就去点了一下,结果跳出了登录界面,通过复制链接,发现电脑是可以打开这个登陆页面的,因为平时这个都是app内应用,所以是没有登陆的,看不到登录页面。

  那么有了登陆页面就很简单了啊,通过浏览器登陆并抓包发现,登陆成功后,有一个Ajax请求的返回信息正好是携带了token,而且跟前面的请求头中的authorration格式是一样的。

发现这个就很简单了,只要先对这个Ajax发起post拿到token,在用这个token取进行打卡就行了。  

然后点到post表单,发现登陆的密码是加密的。查看后应该是一个MD5的加密,进行一个小小的逆向就可以拿到加密方法了。

  做完这一步骤以后,又发现打卡的时候post的url,后面携带了一个叫做ID的东西。

  最后返回去之后,抓包发现获取打卡列表的时候,响应值中打卡列表中每一个打卡都有一个对应的ID,就是打卡的时候post携带的ID。

  那么,做完以上的所有操作,就知道了代码实现的流程了,首先利用逆向出的加密方法进行模拟登陆,获取Ajax响应结果中的token,使用token请求获取打卡列表中对应今天的打卡ID,利用获取到的打卡ID进行打卡操作。

三、代码操作流程

  用到的库文件

1 import execjs
2 import requests
3 import time
4 from multiprocessing.dummy import Pool

  逆向过程就不贴出来了,一个简单的JS调试就可以拿到逆向方法啦。

  首先就是进行模拟登陆

复制代码
 1 # 利用逆向得到的js文件对明文密码进行加密,传入明文密码,返回加密密码
 2 def encrypted_password(cleartext_passwords):
 3     node = execjs.get()
 4     ctx = node.compile(open(file='./zhxgPasswordEncrypt.js', mode='r', encoding='utf-8').read())
 5     function_name = 'getpwd'
 6     encrypted_password = ctx.call(function_name, cleartext_passwords)
 7     return encrypted_password
 8 
 9 
10 # 模拟登陆获取token,传入用户名和加密密码,返回token
11 def get_token(UserName, encrypted_password):
12     url = ''
13     headers = {
14         'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Mobile Safari/537.36 Edg/96.0.1054.62',
15     }
16     data = {
17         'Password': encrypted_password,
18         'UserName': UserName,
19     }
20     response = requests.post(url=url, headers=headers, data=data).json()
21     data = response['data']
22     token = data['Token']
23     return token
复制代码

  第二步就是进行打卡ID的获取

复制代码
 1 # 获取当天需要打卡的签到ID,传入authorization需要的token,返回signID
 2 def get_signID(token):
 3     url = ''
 4     headers = {
 5         'User-Agent': 'Mozilla/5.0 (Linux; Android 10; YAL-AL00 Build/HUAWEIYAL-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36 yiban_android/5.0.7',
 6         'Authorization': token,
 7         'Platform': 'mobile',
 8     }
 9     response = requests.get(url=url, headers=headers).json()
10     data = response['data']
11     signID = data[0]['ID']
12     return signID
复制代码

  第三部当然就是进行打卡啦

复制代码
 1 # 进行签到操作,传入参数signID,token,返回签到信息
 2 def sign(signID, token, UserName):
 3     url = ''
 4     headers = {
 5         'Content-Type': 'application/x-www-form-urlencoded',
 6         'User-Agent': 'Mozilla/5.0 (Linux; Android 10; YAL-AL00 Build/HUAWEIYAL-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36 yiban_android/5.0.7',
 7         'Authorization': token,
 8         'Platform': 'mobile',
 9     }
10     timestamp = time.time()
11     format_time1 = time.strftime('%Y-%m-%d', time.localtime(timestamp))
12     format_time2 = time.strftime('%H:%M:%S', time.localtime(timestamp))
13     requests_body = {
14         'jwd': '',
15         'position': '',
16         'signtime': f'{format_time1}\n{format_time2}',
17         'id': signID,
18     }
19     response = requests.post(url=url, headers=headers, data=requests_body).json()
20     if '成功' in response['message']:
21         message = f'{UserName}晚间签到完成-->{format_time1}'
22     else:
23         message = f'{UserName}晚间签到失败-->{format_time1}'
24     return message
复制代码

  最后可以利用server酱进行一个wx推送的通知。

复制代码
1 # 微信推送,传入参数:要推送的信息,推送信息的key
2 def send_message(message, key):
3     url = 'https://sctapi.ftqq.com/' + key + '.send'
4     data = {
5         'title': message,
6         'desp': message,
7     }
8     requests.post(url=url, params=data)
复制代码

  那一个宿舍的,可以自动打卡总不能不带上舍友吧。所以就带上舍友们咯。再加一个线程池吧!

复制代码
 1 # 完成所有操作。传入用户名和明文密码。
 2 def finish(information_dic):
 3     UserName = information_dic['UserName']
 4     cleartext_passwords = information_dic['Password']
 5     key = information_dic['key']
 6     # 加密密码
 7     enPassword = encrypted_password(cleartext_passwords)
 8     # 获取token
 9     token = get_token(UserName, enPassword)
10     # 获取signID
11     signID = get_signID(token)
12     # 签到
13     message = sign(signID, token, UserName)
14     # 微信推送
15     send_message(message, key)
16 
17 
18 def main(*args):
19     pool = Pool(5)
20     pool.map(finish, information_list)
复制代码

  到此,所有的代码编写还有分析过程就结束了,最后测试没问题,直接挂到服务器或者云函数每天就不用自己动手签到了。

  最后把整体的代码也贴出来咯。感谢浏览,因为不是正统程序员出身,只是出于对编程的爱好学习的,因此如果代码中不规范的地方还请包涵,也可以提给我,我会虚心学习的。

复制代码
  1 # -*- coding: utf-8 -*-
  2 # @Time : 2022/1/6 21:44
  3 # @Author : 遠方
  4 # @QQ:2560389931
  5 # @File : main.py
  6 import execjs
  7 import requests
  8 import time
  9 from multiprocessing.dummy import Pool
 10 
 11 # 信息配置
 12 information_list = [
 13     # 自己
 14     {'UserName': '', 'Password': '', 'key': '', },
 15     # 张三
 16     {'UserName': '', 'Password': '', 'key': '', },
 17     # 李四
 18     {'UserName': '', 'Password': '', 'key': '', },
 19     # 王麻子
 20     {'UserName': '', 'Password': '', 'key': '', },
 21 ]
 22 
 23 
 24 # 利用逆向得到的js文件对明文密码进行加密,传入明文密码,返回加密密码
 25 def encrypted_password(cleartext_passwords):
 26     node = execjs.get()
 27     ctx = node.compile(open(file='./zhxgPasswordEncrypt.js', mode='r', encoding='utf-8').read())
 28     function_name = 'getpwd'
 29     encrypted_password = ctx.call(function_name, cleartext_passwords)
 30     return encrypted_password
 31 
 32 
 33 # 模拟登陆获取token,传入用户名和加密密码,返回token
 34 def get_token(UserName, encrypted_password):
 35     url = ''
 36     headers = {
 37         'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Mobile Safari/537.36 Edg/96.0.1054.62',
 38     }
 39     data = {
 40         'Password': encrypted_password,
 41         'UserName': UserName,
 42     }
 43     response = requests.post(url=url, headers=headers, data=data).json()
 44     data = response['data']
 45     token = data['Token']
 46     return token
 47 
 48 
 49 # 获取当天需要打卡的签到ID,传入authorization需要的token,返回signID
 50 def get_signID(token):
 51     url = ''
 52     headers = {
 53         'User-Agent': 'Mozilla/5.0 (Linux; Android 10; YAL-AL00 Build/HUAWEIYAL-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36 yiban_android/5.0.7',
 54         'Authorization': token,
 55         'Platform': 'mobile',
 56     }
 57     response = requests.get(url=url, headers=headers).json()
 58     data = response['data']
 59     signID = data[0]['ID']
 60     return signID
 61 
 62 
 63 # 进行签到操作,传入参数signID,token,返回签到信息
 64 def sign(signID, token, UserName):
 65     url = ''
 66     headers = {
 67         'Content-Type': 'application/x-www-form-urlencoded',
 68         'User-Agent': 'Mozilla/5.0 (Linux; Android 10; YAL-AL00 Build/HUAWEIYAL-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36 yiban_android/5.0.7',
 69         'Authorization': token,
 70         'Platform': 'mobile',
 71     }
 72     timestamp = time.time()
 73     format_time1 = time.strftime('%Y-%m-%d', time.localtime(timestamp))
 74     format_time2 = time.strftime('%H:%M:%S', time.localtime(timestamp))
 75     requests_body = {
 76         'jwd': '',
 77         'position': '',
 78         'signtime': f'{format_time1}\n{format_time2}',
 79         'id': signID,
 80     }
 81     response = requests.post(url=url, headers=headers, data=requests_body).json()
 82     if '成功' in response['message']:
 83         message = f'{UserName}晚间签到完成-->{format_time1}'
 84     else:
 85         message = f'{UserName}晚间签到失败-->{format_time1}'
 86     return message
 87 
 88 
 89 # 微信推送,传入参数:要推送的信息,推送信息的key
 90 def send_message(message, key):
 91     url = 'https://sctapi.ftqq.com/' + key + '.send'
 92     data = {
 93         'title': message,
 94         'desp': message,
 95     }
 96     requests.post(url=url, params=data)
 97 
 98 
 99 # 完成所有操作。传入用户名和明文密码。
100 def finish(information_dic):
101     UserName = information_dic['UserName']
102     cleartext_passwords = information_dic['Password']
103     key = information_dic['key']
104     # 加密密码
105     enPassword = encrypted_password(cleartext_passwords)
106     # 获取token
107     token = get_token(UserName, enPassword)
108     # 获取signID
109     signID = get_signID(token)
110     # 签到
111     message = sign(signID, token, UserName)
112     # 微信推送
113     send_message(message, key)
114 
115 
116 def main(*args):
117     pool = Pool(5)
118     pool.map(finish, information_list)
119 
120 
121 if __name__ == '__main__':
122     main()
复制代码
 
出处:https://www.cnblogs.com/yuanfang0w0/p/15776277.html


相关教程