京东2023 618拆快递H5ST 4.1算法
本文最后更新于 2024-07-06,文章内容可能已经过时。
本来应该当天就搞出来的,结果因为上班感觉有点累,一直拖到现在。
算法和log验签差不多的,这次我分为了两个模块。
生成fingerprint
function q_() {
var u = 'uct6d0jhqw';
var c = V_(u, 6);
var l = W_();
var i = J_(u, c);
var p = {};
p.size = l, p.num = i;
var h = K_(p) + c + K_({
size: 9 - l,
num: i
}) + l;
var s = h.split("");
var d = s.slice(0, 14);
var a = s.slice(14);
var f = [];
for (; d.length > 0;) f.push((35 - parseInt(d.pop(), 36)).toString(36));
f = f.concat(a);
var v = f.join("");
return v;
}
function W_() {
return (Math.random() * 10) | 0
}
function V_(t, e) {
var o, i = [], a = t.length, u = U_(t);
try {
for (u.s(); !(o = u.n()).done;) {
var c = o.value;
if (((Math.random() * a) < e) && (i.push(c), 0 == --e)) break;
a--
}
} catch (t) {
u.e(t)
} finally {
u.f()
}
var s = "";
for (var l = 0; (l < i.length); l++) {
var d = ((Math.random() * (i.length - l)) | 0);
s += i[d], i[d] = i[((i.length - l) - 1)]
}
return s
}
function K_(t) {
var r = t.size, o = t.num;
for (var a = ""; r--;) a += o[((Math.random() * o.length) | 0)];
return a
}
function J_(t, e) {
for (var a = 0; a < e.length; a++) {
var u = t.indexOf(e[a]);
(u !== -1) && (t = t.replace(e[a], ""))
}
return t
}
function U_(t, e) {
var p;
if ((typeof Symbol === 'undefined') || null == t[Symbol.iterator]) {
if (Array.isArray(t) || (p = G_(t)) || (e && t) && (typeof t.length === 'number')) {
p && (t = p);
var f = 0, l = function () {
}, d = {};
return d.s = l, d.n = function () {
var e = {};
if (e.done = !0, f >= t.length) return e;
var r = {};
return r.done = !1, r.value = t[f++], r
}, d.e = function (t) {
throw t
}, d.f = l, d
}
throw new TypeError('Invalid attempt to iterate non-iterable instance.In order to be iterable, non-array objects must have a [Symbol.iterator]() method.')
}
var u, c = !0, s = !1;
return {
s: function () {
p = t[Symbol.iterator]()
}, n: function () {
var t = p.next();
return c = t.done, t
}, e: function (t) {
s = !0, u = t
}, f: function () {
try {
!c && (p.return != null) && p.return()
} finally {
if (s) throw u
}
}
};
}
module.exports.q_ = q_
生成H5ST并发送一个请求进行测试
const CryptoJS = require('crypto-js');
const promisify = require('util').promisify;
const request = promisify(require('request'));
const testFigerprint = require('./testFigerprint.js');
var _fingerprint = testFigerprint.q_();
var random = randomString(10, true);
var _version = '4.1';
var _token, __genKey, _isNormal = !1, _defaultToken = '';
var fv = 'v0.1.6';
// appId和main方法中的测试参数数组,应由用户自己传递进来
var _appId = "2a045";
async function getAlgoBody() {
var r = {
"ai": _appId,
"av": "5.0;appBuild/98730;ef/1;ep/%7B%22hdid%22%3A%22JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw%3D%22%2C%22ts%22%3A1684847465219%2C%22ridx%22%3A-1%2C%22cipher%22%3A%7B%22sv%22%3A%22CJO%3D%22%2C%22ad%22%3A%22DJdtZNdtZNY1DJYmCJDuCq%3D%3D%22%2C%22od%22%3A%22DwO5DJrtZwG5ZNCyDJu3ZK%3D%3D%22%2C%22ov%22%3A%22CzK%3D%22%2C%22ud%22%3A%22DJdtZNdtZNY1DJYmCJDuCq%3D%3D%22%7D%2C%22ciphertype%22%3A5%2C%22version%22%3A%221.2.0%22%2C%22appname%22%3A%22com.jingdong.app.mall%22%7D;jdSupportDarkMode/0;Mozilla/5.0 (Linux; Android 11; Redmi K20 Pro Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.77 Mobile Safari/537.36",
"fp": _fingerprint,
"h": 700,
"l": "zh-CN",
"ls": "zh-CN,zh",
"ml": 0,
// "og": "https://wbbny.m.jd.com",
"oh": 700,
"ow": 400,
"pf": undefined,
"pl": 0,
"pm": {
"ps": "prompt",
"np": "default"
},
// "pp": {
// "p3": pin
// },
"pp1": "",
"pr": "1",
"random": random,
"re": "",
"referer": "",
"sua": "Linux; Android 11; Redmi K20 Pro Build/RKQ1.200826.002; wv",
"ua": "jdapp;android;11.8.0;;;M/5.0;appBuild/98730;ef/1;ep/%7B%22hdid%22%3A%22JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw%3D%22%2C%22ts%22%3A1684847465219%2C%22ridx%22%3A-1%2C%22cipher%22%3A%7B%22sv%22%3A%22CJO%3D%22%2C%22ad%22%3A%22DJdtZNdtZNY1DJYmCJDuCq%3D%3D%22%2C%22od%22%3A%22DwO5DJrtZwG5ZNCyDJu3ZK%3D%3D%22%2C%22ov%22%3A%22CzK%3D%22%2C%22ud%22%3A%22DJdtZNdtZNY1DJYmCJDuCq%3D%3D%22%7D%2C%22ciphertype%22%3A5%2C%22version%22%3A%221.2.0%22%2C%22appname%22%3A%22com.jingdong.app.mall%22%7D;jdSupportDarkMode/0;Mozilla/5.0 (Linux; Android 11; Redmi K20 Pro Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.77 Mobile Safari/537.36",
// "url": "https://wbbny.m.jd.com/pb/014710620/mTPLZGkAcayB5UvZ6uZCtL3M6ca/index.html?from=home&babelChannel=jdfuceng&sid=43db4ecf1c01943617abc42910d3d0aw#/pages/home/index/index",
"v": fv,
"w": 400,
"wc": 0,
"wd": 0
}
let s = CryptoJS.AES.encrypt(JSON.stringify(r, null, 2), CryptoJS.enc.Utf8.parse('wm0!@w-s#ll1flo('), {
iv: CryptoJS.enc.Utf8.parse('0102030405060708'),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
}).ciphertext.toString();
var g = {
"fingerprint": _fingerprint,
"appId": _appId,
"version": _version,
"timeout": 5,
"env": s
};
return g;
}
async function __requestAlgorithm(body) {
var i = body.fingerprint,
a = body.appId,
u = body.version,
s = body.env;
let result = await request({
url: 'https://cactus.jd.com/request_algo',
method: 'POST',
json: true,
body: {
'version': u,
'fp': i,
'appId': a,
'timestamp': Date.now(),
'platform': 'web',
'expandParams': s,
'fv': fv
}
})
if (result.body.status === 200 && result.body.data && result.body.data.result) {
// console.log(`获取Algo成功:${JSON.stringify(result.body)}`)
var c = result.body.data.result,
s = c.algo,
p = c.tk,
h = c.fp;
if (s && p) {
var v = {
algo: s,
token: p,
fp: h
};
await tt(v)
} else {
throw new Error('data.result format error.');
}
return result.body;
}
// console.log(result)
throw new Error('获取Algo失败');
}
async function tt(t) {
var o = t.algo,
i = t.token;
await __parseAlgorithm(i, o);
}
async function __parseAlgorithm(t, n) {
if (_token = (t || ""), __genKey = n && new Function("return ".concat(n))() || null, _token && __genKey) {
_isNormal = !0;
}
}
async function __genDefaultKey() {
console.log('__genDefaultKey')
}
function yx() {
var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : Date.now(),
e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "yyyy-MM-dd", n = new Date(t),
r = e, o = {
"M+": n.getMonth() + 1,
"d+": n.getDate(),
"D+": n.getDate(),
"h+": n.getHours(),
"H+": n.getHours(),
"m+": n.getMinutes(),
"s+": n.getSeconds(),
"w+": n.getDay(),
"q+": Math.floor((n.getMonth() + 3) / 3),
"S+": n.getMilliseconds()
};
return /(y+)/i.test(r) && (r = r.replace(RegExp.$1, "".concat(n.getFullYear()).substr(4 - RegExp.$1.length))), Object.keys(o).forEach((function (t) {
if (new RegExp("(".concat(t, ")")).test(r)) {
var e = "S+" === t ? "000" : "00";
r = r.replace(RegExp.$1, 1 == RegExp.$1.length ? o[t] : "".concat(e).concat(o[t]).substr("".concat(o[t]).length))
}
})), r
}
function __genSign(t, n) {
var u = n.map((function (t) {
return t.key + ":" + t.value
})).join("&");
var s = CryptoJS.MD5(t + u + t).toString(CryptoJS.enc.Hex);
return s
}
function __genSignParams(t, e, n, r) {
return ["".concat(n), "".concat(_fingerprint), "".concat(_appId), "".concat(_isNormal ? _token : _defaultToken), "".concat(t), "".concat(_version), "".concat(e), "".concat(r)].join(";")
}
async function __makeSign(t, n) {
var v = "";
var _ = Date.now();
var s = yx(_, "yyyyMMddhhmmssSSS");
var h = s + "04";
var f = _token;
var l = _defaultToken;
var d = _fingerprint;
var p = _appId;
if (_isNormal) {
v = __genKey(f, d, h, p, CryptoJS).toString() || ""
} else {
if (l) {
v = __genDefaultKey(l, d, h, p)
} else {
_defaultToken = dE(_fingerprint);
v = __genDefaultKey(_defaultToken, d, h, p);
}
}
var k = {};
if (!v) {
if (f || l) {
// var g = {
// code: bx.GENERATE_SIGNATURE_FAILED,
// message: 'generate key failed'
// };
// this._onSign(g)
} else {
// var m = {
// code: bx.TOKEN_EMPTY,
// message: 'token is empty'
// };
// this._onSign(m)
}
return k
}
var x = __genSign(v, t);
var w = t.map((function (t) {
return t.key
})).join(",");
var S = 1;
var A = __genSignParams(x, _, s, n);
return {
_stk: w,
_ste: S,
h5st: A
};
}
async function __collect(t) {
var i, a;
var t = {
'fp': _fingerprint,
// 'pp':{
// 'p3': pin
// },
'random': random,
'referer': "",
'sua': "Linux; Android 11; Redmi K20 Pro Build/RKQ1.200826.002; wv",
'v': fv
}
t.fp = _fingerprint;
var i = JSON.stringify(t, null, 2);
var a = CryptoJS.AES.encrypt(i, CryptoJS.enc.Utf8.parse('HL4|FW#Chc3#q?0)'), {
iv: CryptoJS.enc.Utf8.parse('0102030405060708'),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return a.ciphertext.toString();
}
async function main() {
try {
var time = new Date().getTime();
var i = [{
"key": "appid",
"value": "signed_wh5"
}, {
"key": "body",
"value": CryptoJS.SHA256('{}').toString(CryptoJS.enc.Hex)
}, {
"key": "client",
"value": "wh5"
}, {
"key": "clientVersion",
"value": "1.0.0"
}, {
"key": "functionId",
"value": "promote_getHomeData"
}, {
"key": "t",
"value": time
}]
var algoBody = await getAlgoBody();
await __requestAlgorithm(algoBody);
var a = await __collect();
var u = await __makeSign(i, a);
console.log(`获取h5st: ${u.h5st}`)
await test(time, u.h5st);
} catch (e) {
console.error(e);
}
}
main()
/**
* 2023 618 拆快递 测试接口,不需要填写cookie,环境异常会直接提醒
* @param {*} time
* @param {*} h5st
*/
async function test(time, h5st) {
let result = await request({
url: `https://api.m.jd.com/`,
method: 'post',
headers: {
'cookie': '',
'user-agent': 'jdapp;android;11.8.0;;;M/5.0;appBuild/98730;ef/1;ep/%7B%22hdid%22%3A%22JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw%3D%22%2C%22ts%22%3A1684847465219%2C%22ridx%22%3A-1%2C%22cipher%22%3A%7B%22sv%22%3A%22CJO%3D%22%2C%22ad%22%3A%22DJdtZNdtZNY1DJYmCJDuCq%3D%3D%22%2C%22od%22%3A%22DwO5DJrtZwG5ZNCyDJu3ZK%3D%3D%22%2C%22ov%22%3A%22CzK%3D%22%2C%22ud%22%3A%22DJdtZNdtZNY1DJYmCJDuCq%3D%3D%22%7D%2C%22ciphertype%22%3A5%2C%22version%22%3A%221.2.0%22%2C%22appname%22%3A%22com.jingdong.app.mall%22%7D;jdSupportDarkMode/0;Mozilla/5.0 (Linux; Android 11; Redmi K20 Pro Build/RKQ1.200826.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/113.0.5672.77 Mobile Safari/537.36',
'origin': 'https://wbbny.m.jd.com'
},
form: {
'functionId': 'promote_getHomeData',
'body': '{}',
'appid': 'signed_wh5',
'client': 'wh5',
'clientVersion': '1.0.0',
'screen': '400*0',
'wqDefault': 'false',
't': time,
'h5st': h5st
}
})
console.log(result.body)
}
/**
* 2022 扎年兽扣的随机字符串, 2023 618拆快递不是这个方法,但是可以正常使用
* @param {*} t
* @param {*} e
* @returns
*/
function randomString(t, e) {
var a = "", u = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var s = 0; s < t; s++) {
var c = u;
if (s === 0 && e) {
c = u.slice(1);
}
var f = Math.round((Math.random() * (c.length - 1)));
a += c.substring(f, (f + 1))
}
return a
}
题外话,ChatGPT是真的好用啊,自己处理字符串混淆还原后,其实代码还是比较难看得懂,结果可以直接丢给GPT,如图,上面注释的是原代码,下面是GPT处理后的代码。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 舟涯
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果