吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5333|回复: 46
收起左侧

[Web逆向] 某东方-头部sign解密

  [复制链接]
LinCode 发表于 2023-12-27 12:54
爬虫逆向基础之sign加密破解目标网站:aHR0cHM6Ly9zb3VrZS54ZGYuY24vc2VhcmNoP2NpdHlDb2RlPTQ0MDEwMCZjYXRlZ29yeUNvZGU9MTIw网站分析打开F12,找到对应的网页数据,并选择response,查看网页源代码,是否在网页代码中存在目标数据。很遗憾,并没有发现目标数据,因此这必然是一个动态加载的数据,数据分类属于XHR。抓取动态数据首先清空刚刚的所有包,然后包的分类选择Fetch/XHR,选择后点击页面跳转,自然就会出现图上所框住的两条数据。
  • 数据分析
点击数据后发现确实如我所预料的,它是通过动态数据加载进页面的,那就好办了。
  • 分析查询参数
Query String Parameters指的是查询参数的意思。在上图一共有6个查询参数,分别是:1、appid:未知标识2、cityCode:城市编码(该网站设置的)3、t:时间戳(当前系统的时间,指的是由1970年1月1日开始所经过的秒数)4、PageIndex:页码5、pageSize:一个页面有多少个数据6、categoryCode:课程列别编码(该网站设置的)https://dsapi.xdf.cn/product/v2/class/search?appId=5053&cityCode=440100&t=1703562702537&pageIndex=2&pageSize=12&categoryCode=1200&order=0问号后面的就是查询参数。分析headers这个案例如果没有加密那我肯定就不会写了是不是?在请求头的位置出现了Sign值,意味着在对目标发起请求时需要携带Sign值去访问。但是经过测试sign值是不断变换的,我们可以来做一次测试。这里给大家介绍一个网站,可以自动生成代码https://curlconverter.com/操作步骤:1、选择目标数据接口——>右键——>copy——>copy all as cURL2、将复制的内容粘贴到目标网站即可。import requests
​
headers = {
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Content-Type': 'application/json',
    'Origin': 'https://souke.xdf.cn',
    'Pragma': 'no-cache',
    'Referer': 'https://souke.xdf.cn/search?cityCode=440100&categoryCode=120',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    'sec-ch-ua-mobile': '?0',
    'sec-ch-ua-platform': '"Windows"',
    'sign': '9790abf162133a24a9318d33b9957410',
}
​
params = {
    'appId': '5053',
    'cityCode': '440100',
    't': '1703566319153',
    'pageIndex': '1',
    'pageSize': '12',
    'categoryCode': '120',
    'order': '0',
}
​
response = requests.get('https://dsapi.xdf.cn/product/v2/class/search', params=params, headers=headers)
print(response.json())运行结果:{'status': 1, 'message': '操作成功', 'data': {'totalRecords': 445, 'maxRecords': 445, 'nearbyDistance': 3.0, 'classList': [{'schoolId': 1139, 'cityCode': '440100', 'code': 'AF24B202013', 'name': '【法语小班直播】B2(假期上午12月27日开课)', 'learnPlace': '详见课表', 'startDate': '2023-12-27 08:30:00', 'endDate': '2024-01-29 10:30:00', 'learnTime': '2023.12.27-2024.1.26周一二三四五08:30-12:30;2024.1.29周一08:30-10:30', 'lessonTimes': 23, 'realMinutes': 5400, 'maxNum': 20, 'currentNum': 3, 'price': 6000.0, 'isNet': True, 'classMode': '107', 'teachingMethod': '229', 'isReservation': False, 'isCanInsert': False, 'insertLessonNumber': None, 'insertLessonTimeText': None, 'insertLessonFee': None, 'isAllFeeInsert': False, 'relationCode': None, 'registrationState': 1, 'quarter': '1,2,3,4', 'distance': None, 'cityId': 31, 'classCapacityName': '25人', 'subjectName': None, 'teacherList': None, 'seasonName': '春,暑,秋,寒'}, ]}, 'code': '200'}上述结果我省略了一些内容。通过访问发现是正常的,但是这只是一页的结果,如果将pageIndex的值设置成2,来看看结果{'status': 0, 'message': '请求过期', 'code': '-2'}分析调用堆栈点击Initiator,并未发现下面的函数有0x开头的值,因此并不存在代码的混淆。那就好办了。断点测试向这类没有混淆的代码,我们可以直接通过断点url的路径。首先复制下划线的内容。按照上图所示的步骤将路径复制到XHR断点中。完成上述步骤后点击翻页操作。很好,点击翻页后就找到了sign的生成方式,打个断点看看对不对。得到的结果是一样的,进一步证明了我们找到的代码是正确的。接下来继续打下断点,看看ve是个什么东西。不难发现进去之后又是一串函数,而参数u则是刚刚一部分查询参数。接下来分析ve函数进来ve函数后,打上断点得到这个ve这个函数就是生成sign值的部分它是由t和Ke.b拼接而成的加密数据原数据:appId=5053&cityCode=440100&t=1703572500623&pageIndex=4&pageSize=12&categoryCode=120&order=0750F82C2-D8F6-49F6-878C-1E7EBEBC8DA2那它是怎么样转换成加密的呢?它的加密逻辑是什么?这里大家如果对js比较熟悉就不难发现这个是属于MD5加密。当然不熟也没有关系,大部分网站对sign值的加密都是MD5。那我们找个在线的MD5加密网站测试一下。与刚刚输出的结果一致。编写js代码// 需要在当前目录安装crypto-js
const CryptoJs = require('crypto-js')
t = (new Date).getTime()
encrypt1 = CryptoJs.MD5('appId=5053&cityCode=440100&t=1703572500623&pageIndex=4&pageSize=12&categoryCode=120&order=0750F82C2-D8F6-49F6-878C-1E7EBEBC8DA2').toString()
console.log(encrypt1)输出结果:16eb08631842bcb315ca7fc8ac164eae需要配置node,具体过程自行查找,另外vscode需要安装run code插件。最后在项目文件夹安装crypto-jsnpm install crypto-js使用python执行js代码pip install pyexecjs
pip install pyexecjs2首先安装第二版本的pyexecjs,现在网上你能找到的大部分教程都是以1版本为主,但是那个已经不再维护了。import execjs

with open('dome1.js', 'r', encoding='utf-8') as f:
    js = f.read()

ctx = execjs.compile(js)
sign = ctx.call('get_sign')
print(sign)运行结果16eb08631842bcb315ca7fc8ac164eae代码优化
  • 优化js代码
在js中有两部分的内容必然会更改,第一个是时间戳,第二个则是页面。function get_time(){
    t = (new Date).getTime()
    return t
}


function get_sign(pageIndex, t){
    const CryptoJs = require('crypto-js')
   
    console.log(t)
    encrypt1 = CryptoJs.MD5('appId=5053&cityCode=440100&t='+t+'&pageIndex='+pageIndex+'&pageSize=12&categoryCode=120&order=0750F82C2-D8F6-49F6-878C-1E7EBEBC8DA2').toString()
    return encrypt1
}
  • 优化python代码
import execjs

with open('dome1.js', 'r', encoding='utf-8') as f:
    js = f.read()
ctx = execjs.compile(js)
t = str(ctx.call('get_time'))
print(t)
pageIndex = 2
sign = ctx.call('get_sign', pageIndex, t)
print(sign)这样每次运行的结果都是不一样的了。sign值根据页码和时间进行变化。完整代码import requests

import execjs



with open('dome1.js', 'r', encoding='utf-8') as f:
    js = f.read()

for page in range(1, 39):

    ctx = execjs.compile(js)
    t = str(ctx.call('get_time'))
    pageIndex = page
    sign = ctx.call('get_sign', pageIndex, t)
    headers = {
        'Accept': '*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'Content-Type': 'application/json',
        'Origin': 'https://souke.xdf.cn',
        'Pragma': 'no-cache',
        'Referer': 'https://souke.xdf.cn/search?cityCode=440100&categoryCode=120',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'same-site',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
        'sign': sign,
    }

    params = {
        'appId': '5053',
        'cityCode': '440100',
        't': t,
        'pageIndex': str(pageIndex),
        'pageSize': '12',
        'categoryCode': '120',
        'order': '0',
    }

    response = requests.get('https://dsapi.xdf.cn/product/v2/class/search', params=params, headers=headers)
    print(response.json())代码持续优化正在努力加班中

免费评分

参与人数 10威望 +1 吾爱币 +29 热心值 +10 收起 理由
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
willgoon + 1 + 1 我很赞同!
涛之雨 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
soughing + 1 + 1 我很赞同!
janken + 1 + 1 热心回复!
moogmoog + 1 + 1 非常喜欢这种我能看得懂的哈哈哈,学习了!
撒旦の恶 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
yuwuzhe + 1 + 1 热心回复!
tomhex + 1 + 1 我很赞同!
yjycyan56 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

kll545012 发表于 2023-12-28 09:49
都知道是标准的MD5了,直接调用python的MD5库,把参数传入不就可以加密了吗?
Hmily 发表于 2023-12-27 17:48
格式太乱了,处理一下吧,图片也盗链了,无法显示,上传论坛本地吧。
漁滒 发表于 2023-12-27 17:52
诶!等等。既然你已经知道了是标准md5,那么调用execjs的意义是什么?

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
T4DNA + 1 + 1 我很赞同!

查看全部评分

 楼主| LinCode 发表于 2023-12-28 10:35
漁滒 发表于 2023-12-27 17:52
诶!等等。既然你已经知道了是标准md5,那么调用execjs的意义是什么?

主要我个人是初学逆向,刚刚学习完js的知识点。所以记录一下自己找到加密逻辑的js代码,然后试试通过自己找到的js去执行。本来可以调用Python的md5实现
zhangxiaosi 发表于 2023-12-27 18:59
感谢分享
xtz7723 发表于 2023-12-27 19:20
感谢分享
mafect 发表于 2023-12-27 21:00
牛 啊,太厉害了
Goven 发表于 2023-12-27 21:31
感谢分享!
imu798 发表于 2023-12-27 22:01
谢谢分享。
程咬金 发表于 2023-12-27 22:28
这个找出来之后能干嘛,有大佬说一下吗,可以不花钱学习啦?
darkreg 发表于 2023-12-27 22:58
本帖最后由 darkreg 于 2023-12-27 22:59 编辑

学习下大佬的分析思路
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-23 10:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表