首页 > Python资料 博客日记
js逆向实战之烯牛数据请求参数加密和返回数据解密
2024-09-22 15:30:02Python资料围观31次
本篇文章分享js逆向实战之烯牛数据请求参数加密和返回数据解密,对你有帮助的话记得收藏一下,看Python资料网收获更多编程知识
声明:本篇文章仅用于知识分享
实战网址:https://www.xiniudata.com/industry/newest?from=data
请求参数加密
- 访问网址,往下翻翻,可以看到触发了如下的数据包,请求参数进行了加密。
- 全局搜索
list_industries_by_sort
地址,有四处,都位于同一个文件中。
随便点一个看看,可以看到有payload
关键字。
打断点,刷新界面触发断点,一步一步往下调试,可以看到payload
传给了j.a.fetch()
函数。
- 定位
j.a.fetch()
函数。
打断点,跳转进来。可以看到明显给payload
和sig
赋值的语句。
最关键的就是如下这行代码。
var f = Object(u.c)(Object(u.d)(JSON.stringify(s.payload))), p = Object(u.e)(f);
涉及到一个变量和三个函数,一个一个看。
(1)变量s.payload
:直接输出看即可。
(2)函数Object(u.c)
:控制台输出,定位。
(3)函数Object(u.d)
:控制台输出,定位。
(4)函数Object(u.e)
:控制台输出,定位。
上面三个函数的代码可以不用看,直接调用js代码就可以了。
4. 目前的js代码如下。
s = {
"payload": {
"sort": 1,
"start": 20,
"limit": 20
}
}
function e1(e) {
if (null == e)
return null;
for (var t, n, r, o, i, a, u, c = "", l = 0; l < e.length;)
o = (t = e.charCodeAt(l++)) >> 2,
i = (3 & t) << 4 | (n = e.charCodeAt(l++)) >> 4,
a = (15 & n) << 2 | (r = e.charCodeAt(l++)) >> 6,
u = 63 & r,
isNaN(n) ? a = u = 64 : isNaN(r) && (u = 64),
c = c + _keyStr.charAt(o) + _keyStr.charAt(i) + _keyStr.charAt(a) + _keyStr.charAt(u);
return c
}
function e2(e) {
if (null == (e = _u_e(e)))
return null;
for (var t = "", n = 0; n < e.length; n++) {
var r = _p.charCodeAt(n % _p.length);
t += String.fromCharCode(e.charCodeAt(n) ^ r)
}
return t
}
function sig(e) {
return md5(e + _p).toUpperCase()
}
var f = e1(e2(JSON.stringify(s.payload)))
, p = sig(f);
console.log(f);
console.log(p);
运行提示_u_e is not defined
,去找一下补到代码中。
运行提示_p is not defined
,去找_p
。
运行提示md5 is not defined
,这里需要导入crypto-js
库,可以通过npm install crypto-js
命令下载。
const CryptoJS = require("crypto-js");
function sig(e) {
return CryptoJS.MD5(e + _p).toUpperCase()
}
运行提示CryptoJS.MD5(...).toUpperCase is not a function
,是因为在转换为大写之前需要先用toString
函数转为字符串。
完整代码如下:
// query_parameter_encrypt.js
const CryptoJS = require("crypto-js");
s = {
"payload": {
"sort": 1,
"start": 0,
"limit": 20
}
}
function _u_e(e) {
if (null == e)
return null;
e = e.replace(/\r\n/g, "\n");
for (var t = "", n = 0; n < e.length; n++) {
var r = e.charCodeAt(n);
r < 128 ? t += String.fromCharCode(r) : r > 127 && r < 2048 ? (t += String.fromCharCode(r >> 6 | 192),
t += String.fromCharCode(63 & r | 128)) : (t += String.fromCharCode(r >> 12 | 224),
t += String.fromCharCode(r >> 6 & 63 | 128),
t += String.fromCharCode(63 & r | 128))
}
return t
}
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
, _p = "W5D80NFZHAYB8EUI2T649RT2MNRMVE2O";
function e1(e) {
if (null == e)
return null;
for (var t, n, r, o, i, a, u, c = "", l = 0; l < e.length;)
o = (t = e.charCodeAt(l++)) >> 2,
i = (3 & t) << 4 | (n = e.charCodeAt(l++)) >> 4,
a = (15 & n) << 2 | (r = e.charCodeAt(l++)) >> 6,
u = 63 & r,
isNaN(n) ? a = u = 64 : isNaN(r) && (u = 64),
c = c + _keyStr.charAt(o) + _keyStr.charAt(i) + _keyStr.charAt(a) + _keyStr.charAt(u);
return c
}
function e2(e) {
if (null == (e = _u_e(e)))
return null;
for (var t = "", n = 0; n < e.length; n++) {
var r = _p.charCodeAt(n % _p.length);
t += String.fromCharCode(e.charCodeAt(n) ^ r)
}
return t
}
function sig(e) {
return CryptoJS.MD5(e + _p).toString().toUpperCase();
}
function generate(s) {
var payload = e1(e2(JSON.stringify(s.payload))), sign = sig(payload);
return [payload, sign];
}
console.log(generate(s));
运行结果如下。
成功,接下来就是编写python代码获取数据了。
import requests
import json
import execjs
url = "https://www.xiniudata.com/api2/service/x_service/person_industry_list/list_industries_by_sort"
# 这里面最重要的就是content-type参数,否则获取不到数据
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/129.0.0.0 Safari/537.36",
# "cookie": "btoken=82SLKQK1ESJ7A9NZ1C3ZAKREOC0I3AAC",
# "referer": "https://www.xiniudata.com/industry/newest?from=data",
# "origin": "https://www.xiniudata.com",
"content-type": "application/json"}
# 生成payload和sig
s = {
"payload": {
"sort": 1,
"start": 0,
"limit": 20
}
}
file = open("query_parameter_encrypt.js", mode="r")
exec_code = file.read()
exec_js = execjs.compile(exec_code)
payload, sig = exec_js.call("generate", s)
data = {
"payload": payload,
"sig": sig,
"v": 1
}
# 注意需要转换为json数据传输
resp = requests.post(url, headers=headers, data=json.dumps(data))
print(json.loads(resp.text))
运行结果如下。
返回数据解密
- 一般来说对于返回数据的解密,常规操作是搜索
interceptors
,但是很可惜不适用于该网站。那就得想其他的办法。
- 我们知道该数据包采用的是JSON格式数据,解密出来后肯定需要进行JSON解析,所以可以搜索
JSON.parse
关键字。
地方比较多,需要进行筛选。如果JSON.parse
是该函数的第一行代码就铁定不是,因为是需要先解密再进行JSON解析的。点击几个,发现了一处跟加密逻辑很像的代码。(其实一般情况下加密逻辑和解密逻辑是写在一起的)
- 打断点,一行一行调试。
可以看到s
的值就是返回的数据,说明我们没找错地方。
y
的值是明文了,所以解密逻辑肯定跟Object(u.a)
和Object(u.b)
相关。
找到这两个函数的定义。
- 接下来就跟加密逻辑一样了,把相关的js代码复制出来,把需要用到的变量和参数都补齐。
// response_data_decrypt.js
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
, _p = "W5D80NFZHAYB8EUI2T649RT2MNRMVE2O";
function d1(e) {
var t, n, r, o, i, a, u = "", c = 0;
for (e = e.replace(/[^A-Za-z0-9\+\/\=]/g, ""); c < e.length;)
t = _keyStr.indexOf(e.charAt(c++)) << 2 | (o = _keyStr.indexOf(e.charAt(c++))) >> 4,
n = (15 & o) << 4 | (i = _keyStr.indexOf(e.charAt(c++))) >> 2,
r = (3 & i) << 6 | (a = _keyStr.indexOf(e.charAt(c++))),
u += String.fromCharCode(t),
64 != i && (u += String.fromCharCode(n)),
64 != a && (u += String.fromCharCode(r));
return u
}
function _u_d(e) {
for (var t = "", n = 0, r = 0, o = 0, i = 0; n < e.length;)
(r = e.charCodeAt(n)) < 128 ? (t += String.fromCharCode(r),
n++) : r > 191 && r < 224 ? (o = e.charCodeAt(n + 1),
t += String.fromCharCode((31 & r) << 6 | 63 & o),
n += 2) : (o = e.charCodeAt(n + 1),
i = e.charCodeAt(n + 2),
t += String.fromCharCode((15 & r) << 12 | (63 & o) << 6 | 63 & i),
n += 3);
return t
}
function d2(e) {
for (var t = "", n = 0; n < e.length; n++) {
var r = _p.charCodeAt(n % _p.length);
t += String.fromCharCode(e.charCodeAt(n) ^ r)
}
return t = _u_d(t)
}
function decrypt(e){
return d2(d1(e));
}
e = '返回的加密数据';
// console.log(decrypt(e));
运行结果如下。
成功。
5. 写python代码,将加密逻辑和解密逻辑进行融合。
from functools import partial
import subprocess
subprocess.Popen = partial(subprocess.Popen, encoding="utf-8")
import requests
import json
import execjs
url = "https://www.xiniudata.com/api2/service/x_service/person_industry_list/list_industries_by_sort"
headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/129.0.0.0 Safari/537.36", # "cookie": "btoken=82SLKQK1ESJ7A9NZ1C3ZAKREOC0I3AAC",
# "referer": "https://www.xiniudata.com/industry/newest?from=data",
# "origin": "https://www.xiniudata.com",
"content-type": "application/json"}
# 生成payload和sig
s = {"payload": {"sort": 1, "start": 0, "limit": 20}}
file1 = open("query_parameter_encrypt.js", mode="r")
exec_code1 = file1.read()
exec_js1 = execjs.compile(exec_code1)
payload, sig = exec_js1.call("generate", s)
data = {"payload": payload, "sig": sig, "v": 1}
resp = requests.post(url, headers=headers, data=json.dumps(data))
# 得到返回的响应数据
response_data = json.loads(resp.text)['d']
# print(response_data)
# 调用解密逻辑
file2 = open("response_data_decrypt.js", mode="r")
exec_code2 = file2.read()
exec_js2 = execjs.compile(exec_code2)
ming_str = exec_js2.call('decrypt', response_data)
print(ming_str)
运行结果如下。
跟页面上显示的对应。
大功告成。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Python与PyTorch的版本对应
- Anaconda版本和Python版本对应关系(持续更新...)
- Python pyinstaller打包exe最完整教程
- Could not build wheels for llama-cpp-python, which is required to install pyproject.toml-based proj