逆向05 点点网站

#访问页面
#'aHR0cHM6Ly9hcHAuZGlhbmRpYW4uY29tLw==' # https://app.diandian.com/
#API
#'aHR0cHM6Ly9hcGkuZGthbmRpYW4uY29tL3BjL2FwcC92MS91c2VyL2Zhdm9yaXRlL2FwcA=='
# 'https://api.dkandian.com/pc/app/v1/user/favorite/app'
第一张

第二张:点击上图中的anonymous跳转到下面的图,途中的send函数其实就是我们想要的,但是但是但是,会有很多的请求都走这send,我们该如何找到目标请求呢,方法有很多,可以一步一步的倒,直到目标请求,还可以XHR,我们下面使用的是XHR

第三张:XHR


通过异步前面的步骤分析,前面的k都是已经加密的了,异步之后的步骤,我们猜测是一个拦截器,接下来我们分析一下是不是拦截器吧

分析拦截器



onRequest: function(t) {
this.interceptors.request.use((function(e) {
return t(e) || e // 这里有个t函数,我们进去看看
}
))
},


进去这个M函数

OK 接下来该扣js代码了

.........
// Object(y.a)其实就是一个封装 Object没有啥意义,直接看y.a就可以了
// 获取 r, path, {参数}, get等参数【打断点,悬浮就有了】
, o = Object(y.a)(r, path, {
s: n.s,
k: n.k,
l: n.l,
d: n.d,
sort: n.sort,
num: n.num
}, "get");
参数---放在自己写的函数中 这个与扣的代码就不会存在变量的冲突
function test(){
r = {
"app_id": "y21ulux1r7mwra1",
"country_id": 75,
"market_id": 1,
"device_id": 1,
"start_time": 1721577600,
"end_time": 1721664000,
"k": "SUtER2wAXV5aWkhKREdsAF5fWVxISkJFDWQcLD9eDzstJmtQPwIFJyo/EQMfd10POjoAMyYbFHcsPjwPND5MFRpLGx0nAQwrJQcXdyIQAkM9KzgWOgBYOSIGFzs4CQdTLiEOBTATOEITdRseJgRBSjIJGx4uAzRVNRIWQgtbBx86LUAdJQoTdyAoLzY3ACMUHXU9ASoUKhUxIy17JAMaHj8uIDcGYykiIz4tHDoJPXgjPzweNzhFRg5gIR4lGyIgNwk5QDg7PAU1HRY8PXMuCzUuEy8xB29zJCg0KjASTT4NZyI9OwIbOyI2Z2g+LB0hKUodARlkXTk/LR8ZIBwQZgwRWQkvPzwqHUlQITUWECs9FwdXKjgaCi8SMAUPYFVUFF5JDxkFJgAaXgAbChtEWHgXQVhdWk1CQUJpAFhBS0pRHhFYeBdBRhtdVw8GFSweDggbAwoTARVxUBgZ"
}
path = '/v1/user/favorite/app'
data = {
s: '36df3fb834976f662a885efe622d10f3',
k: '546eea8d15acbd96',
l: '6f5eb1db7cc41c15',
d: 0,
sort: 'dd',
num: 10
}
console.log(h(r, path, data, 'get')) // 下面的图的函数调用
}
test()
** 进去y.a**

console.log(h(r, path, data, 'get')) // 上面代码中对函数调用----哪里报错解决哪里
错误1:

定位分析1----其中的t是参数

定位分析1----其中的c()(t) 还是上一步的t参数,,也就是这个函数没有啥作用就是t参数而异

那么我们就直接可以将代码
var n = t; // 平替之后的
// var n = c()(t); // 源代码
错误2:

根据 if (!_()(n))我们知道肯定是一个布尔值啊
去验证

那么我们就直接可以将代码
// if (!_()(n)) {
if (true) {
错误3:

这里有个知识点【短路运算】
如果逻辑与运算符左边的值布尔转换后为false,那么返回左边的值
源码分析
m()(n[d])是个false所有后面的都不走

"post" === e是个false所有后面的都不走
那么我们就直接可以将代码
//直接去掉
for (var d in n)
//m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
//"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
r.push(n[d]);
错误4:

悬浮进去看看
function _(e, n, o) {
var d = "";
n = t.from(n, "utf8"),
o = t.from(o, "utf8");
var c = Object(r.createDecipheriv)("aes-128-cbc", n, o);
return d += c.update(e, "hex", "utf8"),
d += c.final("utf8")
}
有没有很熟悉---AES算法
那么我们就直接可以将代码copy改写
// n = 和 o= 就是AES的key和iv 所以我们不要
crypo = require("crypto")
function aes_crypt(e, n, o) {
var d = "";
var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
return d += c.update(e, "hex", "utf8"),
d += c.final("utf8")
}
Object(aes_crypt)(s, d, f), k);
// Object(l.b)(s, d, f), k);
错误5:

首县分析这个报错,应该就是base64转换啊
验证:

观察下面的值是不是一样呢

那么我们就直接可以将代码
return btoa(y)
//return t.from(y).toString("base64")
js代码总--不是最终版本
crypo = require("crypto")
function aes_crypt(e, n, o) {
var d = "";
var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
return d += c.update(e, "hex", "utf8"),
d += c.final("utf8")
}
function h(e, path, n, r) {
var s = n.s
, d = n.k
, f = n.l
, v = n.d
, h = n.sort
, k = n.num
, y = function(content, t, e) {
for (var a = Array.from(content), n = Array.from(t), r = a.length, o = n.length, d = String.fromCodePoint, i = 0; i < r; i++)
a[i] = d(a[i].codePointAt(0) ^ n[(i + e) % o].codePointAt(0));
return a.join("")
}(function(s, t, path, e) {
return [s, t, e, path].join("(&&)")
}(function(t, e) {
var n = t;
// var n = c()(t);
// if (!_()(n)) {
if (true) {
var r = [];
for (var d in n)
//m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
//"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
r.push(n[d]);
return r.sort(),
r.join("")
}
}(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(aes_crypt)(s, d, f), k);
// }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(l.b)(s, d, f), k);
return btoa(y)
}
// 测试代码
function test(){
r = {
"app_id": "y21ulux1r7mwra1",
"country_id": 75,
"market_id": 1,
"device_id": 1,
"start_time": 1721577600,
"end_time": 1721664000,
}
path = '/v1/user/favorite/app'
data = {
s: '36df3fb834976f662a885efe622d10f3',
k: '546eea8d15acbd96',
l: '6f5eb1db7cc41c15',
d: 0,
sort: 'dd',
num: 10
}
console.log(h(r, path, data, 'get'))
}
test()
// SUtER2wAXV5aWkhKREdsAF5fWVxISkJFJwNZHAEZAEsHRzNGGghcRF5cXEFuB11RWVlLQ0ZYeBdBDQlEXlxcXygARxweCQpVExEoXhoAGQlXGwUA
接下来使用python代码来实现
import requests
import execjs
import time
cookies = {
'deviceid': 'b9647b5f290aa89e8fbad94669e9e6f',
'_ga': 'GA1.1.1071716589.1721633816',
'Qs_lvt_404253': '1721633812%2C1721701819',
'_ga_GVCWL6PNZ2': 'GS1.1.1721720339.3.1.1721722286.0.0.0',
'Qs_pv_404253': '1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
}
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
# 'Cookie': 'deviceid=b9647b5f290aa89e8fbad94669e9e6f; _ga=GA1.1.1071716589.1721633816; Qs_lvt_404253=1721633812%2C1721701819; _ga_GVCWL6PNZ2=GS1.1.1721720339.3.1.1721722286.0.0.0; Qs_pv_404253=1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
'Origin': 'https://app.diandian.com',
'Referer': 'https://app.diandian.com/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-site',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
'language': 'zh',
'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
}
params = {
'app_id': 'y21ulux1r7mwra1',
'country_id': '75',
'market_id': '1',
'device_id': '1',
'start_time': int(time.time()), #'1721577600',
'end_time': int(time.time())+40000, #'1721664000',
#'k': 'SUtER2wAXV5aWkhKREdsAF5fWVxISkJFJwNZHAEZAEsHRzNGGghcRF5cXEFuB11RWVlMQkxYeBdBDQlEXlxcXygARxweCQpVExEoXhoAGQlXGwUA',
}
k = execjs.compile(open("05diandian.js").read()).call("test", params)
params['k'] = k
response = requests.get('https://api.diandian.com/pc/app/v1/user/favorite/app', params=params, cookies=cookies, headers=headers)
print(response.text)
crypo = require("crypto")
function aes_crypt(e, n, o) {
var d = "";
var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
return d += c.update(e, "hex", "utf8"),
d += c.final("utf8")
}
function h(e, path, n, r) {
var s = n.s
, d = n.k
, f = n.l
, v = n.d
, h = n.sort
, k = n.num
, y = function(content, t, e) {
for (var a = Array.from(content), n = Array.from(t), r = a.length, o = n.length, d = String.fromCodePoint, i = 0; i < r; i++)
a[i] = d(a[i].codePointAt(0) ^ n[(i + e) % o].codePointAt(0));
return a.join("")
}(function(s, t, path, e) {
return [s, t, e, path].join("(&&)")
}(function(t, e) {
var n = t;
// var n = c()(t);
// if (!_()(n)) {
if (true) {
var r = [];
for (var d in n)
//m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
//"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
r.push(n[d]);
return r.sort(),
r.join("")
}
}(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(aes_crypt)(s, d, f), k);
// }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(l.b)(s, d, f), k);
return btoa(y)
}
function test(r){
// r = {
// "app_id": "y21ulux1r7mwra1",
// "country_id": 75,
// "market_id": 1,
// "device_id": 1,
// "start_time": 1721577600,
// "end_time": 1721664000,
// // "k": "SUtER2wAXV5aWkhKREdsAF5fWVxISkJFDWQcLD9eDzstJmtQPwIFJyo/EQMfd10POjoAMyYbFHcsPjwPND5MFRpLGx0nAQwrJQcXdyIQAkM9KzgWOgBYOSIGFzs4CQdTLiEOBTATOEITdRseJgRBSjIJGx4uAzRVNRIWQgtbBx86LUAdJQoTdyAoLzY3ACMUHXU9ASoUKhUxIy17JAMaHj8uIDcGYykiIz4tHDoJPXgjPzweNzhFRg5gIR4lGyIgNwk5QDg7PAU1HRY8PXMuCzUuEy8xB29zJCg0KjASTT4NZyI9OwIbOyI2Z2g+LB0hKUodARlkXTk/LR8ZIBwQZgwRWQkvPzwqHUlQITUWECs9FwdXKjgaCi8SMAUPYFVUFF5JDxkFJgAaXgAbChtEWHgXQVhdWk1CQUJpAFhBS0pRHhFYeBdBRhtdVw8GFSweDggbAwoTARVxUBgZ"
// }
path = '/v1/user/favorite/app'
data = {
s: '36df3fb834976f662a885efe622d10f3',
k: '546eea8d15acbd96',
l: '6f5eb1db7cc41c15',
d: 0,
sort: 'dd',
num: 10
}
return h(r, path, data, 'get')
}
接下来-在js中有一些参数是写死的,我们需要把他写活,该怎么办呢
// 下面数据是只要刷新网页就会变化的
data = {
s: '7414336790206813ee0bcdc951079953',
k: '546eea8d15acbd96',
l: '6f5eb1db7cc41c15',
d: 0,
sort: 'dd',
num: 10
}
**思路一:简单版 **
我们拿到对应的数据在全局搜索--如果有,证明是有一个请求的返回值,我们就可以直接去拿了

# 获取数据
res = requests.get('https://app.diandian.com/', headers=headers, cookies=cookies)
repg = r"u:\{.*?\}"
match = re.search(repg, res.text).group()[2:-5] + "}"
match = match.replace('s:','"s":').replace('k:','"k":').replace('l:','"l":')
d = json.loads(match)
.......
# 传递数据
k = execjs.compile(open("05diandian.js").read()).call("test", params, d)
// 观察n 和赋值
function test(r, n){
path = '/v1/user/favorite/app'
data = {
s: n.s,
k: n.k,
l: n.l,
d: 0,
sort: 'dd',
num: 10
}
return h(r, path, data, 'get')
}
最终代码
python
import requests
import execjs
import time
import re
import json
cookies = {
'deviceid': 'b9647b5f290aa89e8fbad94669e9e6f',
'_ga': 'GA1.1.1071716589.1721633816',
'Qs_lvt_404253': '1721633812%2C1721701819',
'_ga_GVCWL6PNZ2': 'GS1.1.1721720339.3.1.1721722286.0.0.0',
'Qs_pv_404253': '1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
}
headers = {
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
# 'Cookie': 'deviceid=b9647b5f290aa89e8fbad94669e9e6f; _ga=GA1.1.1071716589.1721633816; Qs_lvt_404253=1721633812%2C1721701819; _ga_GVCWL6PNZ2=GS1.1.1721720339.3.1.1721722286.0.0.0; Qs_pv_404253=1105371036394839600%2C3638004215479430000%2C3884926680542474000%2C2658578851553454600%2C3205714941294544400',
'Origin': 'https://app.diandian.com',
'Referer': 'https://app.diandian.com/',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-site',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
'language': 'zh',
'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
}
res = requests.get('https://app.diandian.com/', headers=headers, cookies=cookies)
repg = r"u:\{.*?\}"
match = re.search(repg, res.text).group()[2:-5] + "}"
match = match.replace('s:','"s":').replace('k:','"k":').replace('l:','"l":')
d = json.loads(match)
params = {
'app_id': 'y21ulux1r7mwra1',
'country_id': '75',
'market_id': '1',
'device_id': '1',
'start_time': int(time.time()), #'1721577600',
'end_time': int(time.time())+40000, #'1721664000',
#'k': 'SUtER2wAXV5aWkhKREdsAF5fWVxISkJFJwNZHAEZAEsHRzNGGghcRF5cXEFuB11RWVlMQkxYeBdBDQlEXlxcXygARxweCQpVExEoXhoAGQlXGwUA',
}
k = execjs.compile(open("05diandian.js").read()).call("test", params, d)
params['k'] = k
response = requests.get('https://api.diandian.com/pc/app/v1/user/favorite/app', params=params, cookies=cookies, headers=headers)
print(response.text)
js
crypo = require("crypto")
function aes_crypt(e, n, o) {
var d = "";
var c = Object(crypo.createDecipheriv)("aes-128-cbc", n, o);
return d += c.update(e, "hex", "utf8"),
d += c.final("utf8")
}
function h(e, path, n, r) {
var s = n.s
, d = n.k
, f = n.l
, v = n.d
, h = n.sort
, k = n.num
, y = function(content, t, e) {
for (var a = Array.from(content), n = Array.from(t), r = a.length, o = n.length, d = String.fromCodePoint, i = 0; i < r; i++)
a[i] = d(a[i].codePointAt(0) ^ n[(i + e) % o].codePointAt(0));
return a.join("")
}(function(s, t, path, e) {
return [s, t, e, path].join("(&&)")
}(function(t, e) {
var n = t;
// var n = c()(t);
// if (!_()(n)) {
if (true) {
var r = [];
for (var d in n)
//m()(n[d]) && "get" === e && (n[d] = n[d].join("")),
//"post" === e && (m()(n[d]) || o()(n[d])) && (n[d] = JSON.stringify(n[d])),
r.push(n[d]);
return r.sort(),
r.join("")
}
}(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(aes_crypt)(s, d, f), k);
// }(e, r), parseInt((new Date).getTime() / 1e3) - 655876800 - v, path, h), Object(l.b)(s, d, f), k);
return btoa(y)
}
function test(r, n){
path = '/v1/user/favorite/app'
data = {
s: n.s,
k: n.k,
l: n.l,
d: 0,
sort: 'dd',
num: 10
}
return h(r, path, data, 'get')
}
思路二:是在思路一中搜索不到的话
按照图的顺序


在这里你可能会说 我咋知道这个 n 就是我要找的呢?

然后往回倒-哪里调用的M



接下来就看e.store 是哪里来的

倒完之后


最终找到了
window.__NUXT__ && window.__NUXT__.state && r.replaceState(window.__NUXT__.state),

搜索window.__NUXT__.在全局那个地方


看完之后一张图 又回到了思路一中,也就是说:我们思路一走不通的时候 就来直接走思路二

浙公网安备 33010602011771号