提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
继上一篇博客,主要讲解了页面分析的思路,没有什么可以实操的代码,因此在此继续开启一篇代码实现的文章,具体实现思路,参考上一篇博客: QAX答题页面js逆向分析(一)即可
提示:以下是本篇文章正文内容,下面案例可供参考
一、通过前端js解密,获取答案
操作流程,通过抓包获取topicList参数,复制到data.json文件中,再运行demo.html 文件即可把解密后的正确答案,展示在页面中。
附上 简易的 dmeo.html 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<style>
p {
100%;
}
* { margin:0; padding:0;}
</style>
<body>
<div>
<h1 id = "h1">显示答案</h1>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/jsencrypt/3.0.0-beta.1/jsencrypt.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/2.3.1/jsencrypt.min.js" async></script>
<script type="text/javascript">
<!-- 私钥 -->
var publicKey = "密钥请自行获取";
data = $.getJSON("data.json", function (data) {
data.forEach(function (value, index) {
value = value['topic_value']
// 解密
let RSAEncrypt = new JSEncrypt();
RSAEncrypt.setPrivateKey(publicKey);
let encryptedPass = RSAEncrypt.decrypt(value);
$("#h1").append("<p>"+(index+1)+", 正确答案: "+encryptedPass+"</p>")
console.log(index+1, "正确答案: ", encryptedPass);
})
})
</script>
</body>
</html>
运行结果图
注意:建议使用第三方工具抓包,在谷歌浏览器中抓包页面尺寸变化,会强制刷新,不易操作,且容易导致请求覆盖(每次获取的题目id都会不同,会导致题目与解密的正确答案不匹配)。
二、通过Python,模拟请求完成自登录到答题的所有操作。
通过测试,可以发现该流程没有复杂的参数加密,几乎所有参数都是能够在请求中拿到的,因此在考虑用时最少的条件下,可以使用python模拟请求发送,实现自动答题的操作。
1.引入库
代码如下(示例):
import requests
import datetime as dt
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
2. 程序结构
附图
其中,各个实例方法都是通过抓包分析而构造的,简单介绍一下:
- sendCode : 通过手机号码获取短信验证码
- login : 根据手机号码和收到的验证码,实现登录
- findPaperInfo : 根据code(我的理解是这次活动的一个唯一标识)获取问卷信息,包含名称,id,创建人等
- findTopicList : 根据问卷id,用户id等,获取具体的题目,在这里就可以进行解密,获取正确答案
- verifyCruiseNum :检验用户身份以及答题次数等,经过这个请求,每天可用次数都会少1
- saveAnswer : 提交答案
- decryptMy : 根据私钥,对正确答案解密
初始化相关参数:
def __init__(self, score=100, is_comply='0'):
self.json_data = {
'user_id': '',
'user_name': '',
'user_phone': '',
'paper_id': '',
'all_socket': '',
'score': score, # 最终得分
'start_time': dt.datetime.now().strftime('%F %T'),
'end_time': dt.datetime.now(),
'pclassifyList': [],
'is_comply': is_comply, # 是否已完成,0是完成
}
self.Referer = ''
self.token = ''
这里只放其中一个核心实例方法,findTopicList 实例方法代码:
def findTopicList(self):
cookies = {
'JSESSIONID': '',
}
headers = {
'Pragma': 'no-cache',
'Sec-Fetch-Site': 'same-origin',
'Accept-Language': 'zh-CN,zh;q=0.9',
'User-Agent': '',
'Sec-Fetch-Mode': 'cors',
'content-type': 'application/json',
'Accept': '*/*',
'Cache-Control': 'no-cache',
'Referer': self.Referer,
'Connection': 'keep-alive',
'token': self.token,
}
params = {
'paper_id': self.json_data['paper_id'],
}
response = requests.get('.../devops/examport/index/findTopicList', params=params,
cookies=cookies, headers=headers).json()
topicList = response['data'][0]['topicList']
dd = {'A': 0, 'B': 1, "C": 2, "D": 3, "E": 4, "F": 5}
for topic in topicList:
# 这里调用解密方法,实现解密
answers = decryptMy(topic['topic_value'])
topic["userAnswer"] = ''
# 有可能会出现多选题,因此在这里以循环至结束,判断答案取完
for answer in answers.split(','):
answerId = topic['answerList'][dd[answer]]['id']
# print(answerId)
topic["userAnswer"] = topic["userAnswer"]+","+str(answerId) + ":" + answer
topic["userAnswer"] = topic["userAnswer"][1:]
topic['uscore'] = 5
topic['answer'] = answer
topic['is_right']= '0'
# 答题时间,以前一个题目完成时间+1.3秒为一个单位
self.json_data['end_time'] = self.json_data['end_time'] + dt.timedelta(seconds=1.3)
topic['answer_time'] = self.json_data['end_time'].strftime('%F %T')
self.json_data['topicList'] = topicList
3. python解密 JSEncrypt
通过查询相关资料,得知这是采用RSA 加密算法进行加密,这里科普一下
RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。RSA是被研究得最广泛的公钥算法,从提出到现今的三十多年里,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。RSA公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
多次尝试,最后得到以下代码块:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
def decryptMy(inputdata):
data = base64.b64decode(inputdata)
privateKey = "私钥"
privateKey = base64.b64decode(privateKey)
private_key = RSA.import_key(privateKey)
cipher_rsa = PKCS1_v1_5.new(private_key)
sentinel = None
ret = cipher_rsa.decrypt(data, sentinel)
return ret.decode()
附上参考链接:
pycryptodome 加密解密
爬虫常见加密解密算法
PyCryptodome官方文档
最后附个结果图
三、总结与反思
这次测试,基本能够达到了最初的答题满分的目的,也在一定程度上对自身掌握技术的重新认识,有了更好的前进方向。
不足之处:
- 对于常见数据加密方式认识不足,需要恶补
- 抓包工具使用不熟练,只局限普通的http请求,没能最大化发挥工具的作用