雪球网的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

物联沃分享整理
物联沃-IOTWORD物联网 » python JS逆向

发表回复