python JS逆向
雪球网的md5__参数的生成, 最近在看雪球网的逆向发现, 别的帖子都是讲cookie的生成, 但是现在网站应该是改了, 也可能是我没有去看其他的接口吧, 本文根据网站热门贴的参数生成, 经过测试 对于行情也是能正常使用的
文章所涉及内容只做学习参考交流,不做除此之外的任何其它用途!!!
找到热门贴对应的接口
直接搜索就可以找到了
分析加密位置
点击这个文件跳转过去下一个断点
然后你就可以发现其实Jk就是对应的网址信息 并且已经生成了md5__参数,而且很明显Jk是进行了2次操作的, 所有很有可能md5_参数就是在那里生成的, 接下来直接在Jk那里下断点查看一下
这里可以看到在对Jk进行第一次赋值的时候是没有md5__的参数的, 点击这个按钮执行下一步
这里观察第二次对Jk进行赋值的时候已经生成了对应的md5__参数了, 接下来就是一步步进入函数分析真正生成的位置了, 这里直接进入Ja[Fh(bc.F)]这个函数就可以了
继续下断点进入J2[FA(bP.J)]函数, 后面就是重复的操作了 这里就不贴图片了, 最后是进到E函数里面
逆向扣代码
做到这里基本上分析的也就差不多了 但是其实还可以往下分析最后md5__参数是在uu里面生成的,但是需要前面执行得到一串数字还有时间戳 那串数字我没有具体分析是做了什么操作, 所有就从这里开始就扣代码了, 我感觉这个应该可以扣全代码 但是这代码看着太难看了 我也不想去看是怎么弄的就直接扣了代码
function get_param(Jd, JP) {
var JB = ['4', '3', '1', '2', '0']
, Jb = 0;
while (!![]) {
switch (JB[Jb++]) {
case '0':
return [add_(Jt_[modulo(JE, 9)], modulo(JE, 10000)), Ju]
case '1':
for (var JP = add_(add_(add_(add_(add_(JU_sig(Ju), '|'), 0), '|'), new Date()['getTime']()), '|1'), Ju = Jf_ua(JP, true), JE = 0, JL = 0; compare(JL, Jd['host']['length']); JL++)
JE += Jd['host'][JL]['charCodeAt']();
continue;
case '2':
JP = {};
continue;
case '3':
JP && (Ju += JP);
continue;
case '4':
var Ju = (0,
JF_p)(Jd, true);
continue;
}
break;
}
}
最终我是补成了这样, 然后还让gpt做了一个完整的优化版本, gpt的解释是使用了使用 LZW 算法压缩字符串, 下面就贴出代码中每个函数的解释, 这个是gpt优化后的框架, 具体代码就不贴了, 在扣代码的时候这些都会看到
// 定义了参数类型的前缀
const KEY_PREFIXES = ["type__", "refer__", "ipcity__", "md5__", "decode__", "encode__", "time__", "timestamp__", "type__"];
// 定义了编码时使用的字符表
const ENCODING_TABLE = 'DGi0YA7BemWnQjCl4+bR3f8SKIF9tUz/xhr2oEOgPpac=61ZqwTudLkM5vHyNXsVJ';
// 将两个数值相加
function add(a, b) {}
// 执行一个函数,并传入参数
function applyFunction(func, param) {}
// 将两个数值相减
function subtract(a, b) {}
// 将一个数值左移指定的位数
function shiftLeft(a, b) {}
// 判断第一个数值是否小于第二个数值
function isLessThan(a, b) {}
// 判断两个值是否相等
function isEqual(a, b) {}
// 对两个数值进行按位或运算
function bitwiseOr(a, b) {}
// 对两个数值进行按位与运算
function bitwiseAnd(a, b) {}
//对两个数值进行取模运算
function modulo(a, b) {}
// 根据URL对象构建完整的URL字符串
function buildUrl(urlObject, includeHash) {}
// 计算字符串的签名值
function calculateSignature(input) {}
// 使用 LZW 算法压缩字符串
function compressString(input, bitLength, charMapper) {}
// 根据是否使用自定义编码表对输入字符串进行编码
function encodeString(input, useCustomKey) {}
// 生成最终的参数数组
function generateParams(urlObject) {}
我补出来的框架, 如果只为了获取参数的话其实只需要 protocol, host, pathname,search, 这4个就可以了
const Jt_ = ["type__", "refer__", "ipcity__", "md5__", "decode__", "encode__", "time__", "timestamp__", "type__"],
temp_ = 'DGi0YA7BemWnQjCl4+bR3f8SKIF9tUz/xhr2oEOgPpac=61ZqwTudLkM5vHyNXsVJ';
function add_(J2, J3) {}
function method_with_param(J2, J3) {}
function sub_(J2, J3) {}
function shl(J2, J3) {}
function compare(J2, J3) {}
function is_equal(J2, J3) {}
function bitwiseOr(J2, J3) {}
function bitwiseAnd(J2, J3) {}
function notEqual(J2, J3) {}
function modulo(J2, J3) {}
function JF_p(JU, Js) {}
function JU_sig(Jd) {}
function JJ_uu(Jd, JP, JB) {}
function Jf_ua(Jd, JP) {}
function get_param(Jd, JP) {
var JB = ['4', '3', '1', '2', '0']
, Jb = 0;
while (!![]) {
switch (JB[Jb++]) {
case '0':
return [add_(Jt_[modulo(JE, 9)], modulo(JE, 10000)), Ju]
case '1':
for (var JP = add_(add_(add_(add_(add_(JU_sig(Ju), '|'), 0), '|'), new Date()['getTime']()), '|1'), Ju = Jf_ua(JP, true), JE = 0, JL = 0; compare(JL, Jd['host']['length']); JL++)
JE += Jd['host'][JL]['charCodeAt']();
continue;
case '2':
JP = {};
continue;
case '3':
JP && (Ju += JP);
continue;
case '4':
var Ju = (0,
JF_p)(Jd, true);
continue;
}
break;
}
}
te = {
"protocol": "https:",
"host": "xueqiu.com",
"hostname": "xueqiu.com",
"port": "",
"pathname": "/statuses/hot/listV3.json",
"search": "?source=hot&max_id=321523395&last_id=321523395&page=6&_=1737698507074",
"hash": "",
"D": "https://xueqiu.com/statuses/hot/listV3.json?source=hot&max_id=321523395&last_id=321523395&page=6&_=1737698507074"
}
console.log(get_param(te, null));
下面是最终加密的代码展示, 过程前面也贴了一些代码, 其他的也比较好补,就请读者自行去补了
function JJ_uu(Jd, JP, JB) {
if (is_equal(null, Jd))
return '';
for (var Jb, Ju, JE, JL, Jp = {}, Jv = {}, Jc = '', JD = 2, JG = 3, JN = 2, JO = [], Jw = 0, Ja = 0, Jg = 0; compare(Jg, Jd['length']); Jg += 1)
if (JE = Jd['charAt'](Jg),
Object['prototype']['hasOwnProperty']['call'](Jp, JE) || (Jp[JE] = JG++,
Jv[JE] = true),
JL = add_(Jc, JE),
Object['prototype']['hasOwnProperty']['call'](Jp, JL))
Jc = JL;
else {
if (Object['prototype']['hasOwnProperty']['call'](Jv, Jc)) {
if (compare(Jc['charCodeAt'](0), 256)) {
for (Jb = 0; compare(Jb, JN); Jb++)
Jw <<= 1,
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++;
for (Ju = Jc['charCodeAt'](0),
Jb = 0; compare(Jb, 8); Jb++)
Jw = bitwiseOr(shl(Jw, 1), bitwiseAnd(1, Ju)),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju >>= 1;
} else {
for (Ju = 1,
Jb = 0; compare(Jb, JN); Jb++)
Jw = bitwiseOr(shl(Jw, 1), Ju),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju = 0;
for (Ju = Jc['charCodeAt'](0),
Jb = 0; compare(Jb, 16); Jb++)
Jw = bitwiseOr(shl(Jw, 1), bitwiseAnd(1, Ju)),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju >>= 1;
}
is_equal(0, --JD) && (JD = Math['pow'](2, JN),
JN++),
delete Jv[Jc];
} else {
for (Ju = Jp[Jc],
Jb = 0; compare(Jb, JN); Jb++)
Jw = bitwiseOr(shl(Jw, 1), bitwiseAnd(1, Ju)),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju >>= 1;
}
is_equal(0, --JD) && (JD = Math['pow'](2, JN),
JN++),
Jp[JL] = JG++,
Jc = method_with_param(String, JE);
}
if (notEqual('', Jc)) {
if (Object['prototype']['hasOwnProperty']['call'](Jv, Jc)) {
if (compare(Jc['charCodeAt'](0), 256)) {
for (Jb = 0; compare(Jb, JN); Jb++)
Jw <<= 1,
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++;
for (Ju = Jc['charCodeAt'](0),
Jb = 0; compare(Jb, 8); Jb++)
Jw = bitwiseOr(shl(Jw, 1), bitwiseAnd(1, Ju)),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju >>= 1;
} else {
for (Ju = 1,
Jb = 0; compare(Jb, JN); Jb++)
Jw = bitwiseOr(shl(Jw, 1), Ju),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju = 0;
for (Ju = Jc['charCodeAt'](0),
Jb = 0; compare(Jb, 16); Jb++)
Jw = bitwiseOr(shl(Jw, 1), bitwiseAnd(1, Ju)),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju >>= 1;
}
is_equal(0, --JD) && (JD = Math['pow'](2, JN),
JN++),
delete Jv[Jc];
} else {
for (Ju = Jp[Jc],
Jb = 0; compare(Jb, JN); Jb++)
Jw = bitwiseOr(shl(Jw, 1), bitwiseAnd(1, Ju)),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju >>= 1;
}
is_equal(0, --JD) && (JD = Math['pow'](2, JN),
JN++);
}
for (Ju = 2,
Jb = 0; compare(Jb, JN); Jb++)
Jw = bitwiseOr(shl(Jw, 1), bitwiseAnd(1, Ju)),
is_equal(Ja, sub_(JP, 1)) ? (Ja = 0,
JO['push'](method_with_param(JB, Jw)),
Jw = 0) : Ja++,
Ju >>= 1;
for (; ;) {
if (Jw <<= 1,
is_equal(Ja, sub_(JP, 1))) {
JO['push'](method_with_param(JB, Jw));
break;
}
Ja++;
}
return JO['join']('');
}
验证结果
直接替换补好的代码的 new Date()['getTime']()
这个就是浏览器得到的值
最后是和python进行结合
作者:apricity12