【中等】 猿人学web第一届 第5题 js混淆-乱码增强

请求流程

打开 调试工具,查看数据接口 https://match.yuanrenxue.cn/api/match/5

在这里插入图片描述

请求参数

请求参数携带了 page, m, f 3个字段,
page为页数,
m 为时间戳 像是 new Date().getTIme() 生成的
f 为时间戳 像是 Date.parse(new Date()) 生成的
在这里插入图片描述

cookie信息

请求的 cookie 携带了两个字段
RM4hZBv0dDon443M字段 和 m字段
在这里插入图片描述

加密参数定位

Hook Cookie

cookie 中有两个加密字段 m, RM4hZBv0dDon443M
Hook Cookie 找到生成这两个字段信息的关键代码

// Hook Cookie
(function () {
    let cookie_func = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
    Object.defineProperty(document, 'cookie', {
        get() {
            return cookie_func.get.call(this);
        },
        set(val) {
        	console.log(val);
        	debugger;
            return cookie_func.set.call(this, val);
        }
    })
})();

勾选事件监听断点中的脚本断点在这里插入图片描述并刷新页面
刷新页面之后将 脚本断点取消 将 Hook Cookie 的代码在控制台注入之后放开断点
在这里插入图片描述
断点断住之后查看对应生成 cookie 的位置,对应的 js 文件是做了混淆的
解个混淆先
在这里插入图片描述

这段代码是在 eval 函数里执行的,向上查看堆栈,是在 5.html 文件中生成的代码,然后放入 eval 函数中执行
在这里插入图片描述

这段代码是经过混淆的,解混淆以后会容易看很多

AST 还原混淆代码

解密函数还原字符串

文件开头定义了一个数组 _0x34bd
后定义了解密函数,解密函数依赖 _0x34bd
后又将解密函数 _0x34bd 赋值给了 _0x1383f7
调用方式就为 _0x1383f7(…)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

将解密函数和依赖一起放入 AST 文件中
遍历 CallExpression 节点
且 callee 类型为 Identifier name属性值为 _0x1383f7
arguments长度为1,且获取 arguments 参数中的 value 值

// 解密函数还原
var _0x34bd = ["_$zr", ...数组太长了,剩下的省略了];
var _0x54e9 = function (_0x1b88e5, _0x1abb3d) {
_0x1b88e5 = _0x1b88e5 - 229;
var _0x34bd3d = _0x34bd[_0x1b88e5];
return _0x34bd3d;
};
var _0x1383f7 = _0x54e9;
(function (_0x5340a0, _0x2aca3b) {
var _0x595372 = _0x54e9;
while (!![]) {
  try {
    var _0x133a0b = parseInt(_0x595372(572)) + parseInt(_0x595372(418)) * -parseInt(_0x595372(834)) + -parseInt(_0x595372(350)) * -parseInt(_0x595372(483)) + parseInt(_0x595372(823)) + -parseInt(_0x595372(744)) + parseInt(_0x595372(382)) * parseInt(_0x595372(710)) + -parseInt(_0x595372(847)) * -parseInt(_0x595372(496));
    if (_0x133a0b === _0x2aca3b) break;else _0x5340a0["push"](_0x5340a0["shift"]());
  } catch (_0x28ba71) {
    _0x5340a0["push"](_0x5340a0["shift"]());
  }
}
})(_0x34bd, 997352)
traverse(ast, {
    CallExpression(path){
        // callee 类型为 Identifier name属性值为 _0x1383f7
        // arguments长度为1,且获取 arguments 参数中的 value 值
        if(path.get('callee').isIdentifier({name: '_0x1383f7'}) && path.node.arguments.length === 1){

            console.log('解密函数还原前: ', path + '')
            let Arg = path.node.arguments[0].value;  // 获取参数值

            // 将节点替换
            path.replaceWith(types.valueToNode(_0x1383f7(Arg)))
            console.log('解密函数还原后: ', path + '')
            console.log('==============================')
        }
    }
})

还原数组引用

在这里插入图片描述
在这里插入图片描述
文件中有很多引用到 _0xceb4b2 数组的地方
可以看到 _0xceb4b2 数组是通过 _0xac9d20() 方法执行后生成的
在浏览器中 copy(_0xceb4b2 ) 数组拿到本地就可以
_$UH 的值也是 _0xceb4b2 在文件中也有很多引用到的地方

注意
_0xceb4b2 在 _0xac9d20() 方法执行后生成了大数组后又赋值给了 _$UH
$UH 在随后的又进行了一系列操作,导致数组又变化了
在这里插入图片描述在这里插入图片描述
copy() 大数组时在文件最后的 return 处 copy()
在这里插入图片描述
单单 copy() 是行不通的,
$UH 后续赋值了 内置对象 window,导致 copy 之后只得到一串字符串

copy 代码

_$UH_copy = []
for(const index in _$UH){
    if (window === _$UH[index]){
        _$UH_copy.push('window')
    }else{
        _$UH_copy.push(_$UH[index])
    }
}
copy(_$UH_copy)

将取值代码放入ast网站中
在这里插入图片描述
在这里插入图片描述
遍历 MemberExpression 节点
object 为 Identifier 类型 且 name 属性值为 _0xceb4b2

object 为 Identifier 类型 且 name 属性值为 _$UH
property 为 NumericLiteral 类型,后续拿到对应的 value 值

// 数组引用还原
let _0xceb4b2 = [
    "name",
    // ... 数组太长了剩下的省略了
];
traverse(ast, {
    MemberExpression(path) {
        // object 为 Identifier 类型 且 name 属性值为字符串 _0xceb4b2
        // property 为 NumericLiteral 类型
        if (path.get('object').isIdentifier({name: '_0xceb4b2'}) || path.get('object').isIdentifier({name: '_$UH'}) && path.get('property').isNumericLiteral()) {
            // 拿到 property 节点中的 value 值
            let value = path.node.property.value;

            // 节点替换
            console.log('数组引用还原前: ', path.parentPath + '');
            if (_0xceb4b2[value] === 'window') {
                path.replaceWith(types.identifier('window'));
            } else {
                path.replaceWith(types.valueToNode(_0xceb4b2[value]));
            }
            console.log('数组引用还原后: ', path.parentPath + '');
            console.log('==============================')
        }
    }
})

还原浏览器内置对象 / 变量值引用

文件中有很多类似这样的操作
将一个浏览器内置对象赋值给一个变量,后续操作这个变量赋值给下一个变量
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
遍历 VariableDeclarator 节点
init 节点中 name 属性值为对应的 浏览器内置对象的值
后续获取节点中 id 属性中对应的 name 值
拿到 name 值后 获取对应的引用,将 name 值替换成对应的浏览器内置对象

function reductionVar(init, name, type) {
    traverse(ast, {
        Identifier(identPath) {
            if (identPath.node.name === name) {
                // _0x4e96b4 = window 这样的节点是不需要修改的
                // _0x4e96b4['$_zw'] 需要修改这样的 MemberExpression 节点
                if (type === 'CallExpression' && identPath.parentPath.isCallExpression()) {
                    // identPath_.replaceWith(types.identifier(init))
                    console.log('内置对象引用还原前:  ', identPath.parentPath + '');
                    identPath.replaceWith(init);
                    console.log('内置对象引用还原后:  ', identPath.parentPath + '');
                    console.log('==============================')
                }
                if (type === 'MemberExpression' && identPath.parentPath.isMemberExpression()) {
                    // identPath_.replaceWith(types.identifier(init))
                    console.log('内置对象引用还原前:  ', identPath.parentPath + '');
                    identPath.replaceWith(types.identifier(init));
                    console.log('内置对象引用还原后:  ', identPath.parentPath + '');
                    console.log('==============================')
                }
            }
            identPath.skip()
        }
    })
}
// 浏览器内置对象引用
let nativeArray = [
    'window',
    'String',
    'Error',
    'Array',
    'Math',
    'parseInt',
    'Date',
    'document',
    'Object',
    'unescape',
    'encodeURIComponent',
    'Function',
    'CryptoJS'
].join('...') + '...';
traverse(ast, {
    VariableDeclarator(path) {
        let init = path.get('init').isIdentifier() && path.node.init.name;
        if (init && nativeArray.indexOf(init + '...') !== -1) {
            let name = path.get('id').isIdentifier() && path.node.id.name;
            reductionVar(init, name, 'MemberExpression')
        }
    },
    AssignmentExpression(path) {
        if (path.get('left').isIdentifier() && path.get('right').isIdentifier()) {
            let init = path.node.right.name;
            if (init && nativeArray.indexOf(init + '...') !== -1) {
                let name = path.node.left.name;
                reductionVar(init, name, 'MemberExpression')
            }
        }
    }
})
// 变量值引用
traverse(ast, {
    VariableDeclarator(path) {
        if (path.get('id').isIdentifier() && path.get('init').isMemberExpression()) {
            let init = path.node.init;
            let init_name = path.node.init.object;
            for (let i=0; i < 10; i++) {
                if (types.isIdentifier(init_name)) {
                    init_name = init_name.name;
                }
                if (types.isMemberExpression(init_name)) {
                    init_name = init_name.object;
                }
            }
            let name = path.node.id.name;
            if (init && nativeArray.indexOf(init_name + '...') !== -1) {
                console.log('内置对象: ', generator(init).code, ' 引用对象:  ', name);
                reductionVar(init, name, 'CallExpression')
            }
        }
    }
})

还原逗号表达式

在这里插入图片描述
在这里插入图片描述
遍历 VariableDeclaration 节点,且改节点中 declarations 的长度大于 1
获取 declarations 数组,declarations数组中每个元素都创建新的 VariableDeclaration 节点
将当前节点替换成新创建的 VariableDeclaration 节点

在这里插入图片描述
在这里插入图片描述
遍历 SequenceExpression 节点,且 expressions 数组的元素大于1
获取 expressions 数组
将数组中的每个元素都创建为新的 ExpressionStatement 节点
将当前节点替换成新创建的 ExpressionStatement 节点

// 还原逗号表达式
// 逗号表达式
traverse(ast, {
    VariableDeclaration(path) {
        if (path.get('declarations').length > 1) {
            // 例如: var a, b, c

            // 拿到声明符号 var
            let kind = path.node.kind;

            // 拿到 a, b, c 变量
            let Arg = path.get('declarations')

            // 创建的节点元素
            let nodeList = []
            for (const index in Arg) {
                // 创建一个新的 VariableDeclaration 节点
                // var a
                // var b
                // var c
                let varTionNode = types.variableDeclaration(kind, [Arg[index].node]);
                nodeList.push(varTionNode);
                console.log('逗号表达式:  ', generator(varTionNode).code.slice(0, 50).replaceAll('\n', ''));
                console.log('============================================================');
            }

            // 替换当前节点
            path.replaceWithMultiple(nodeList);
        }
    },
    SequenceExpression(path) {
        if (path.get('expressions').length > 1) {
            let Arg = path.get('expressions');
            let nodeList = []
            for (const index in Arg) {
                // 创建新的 ExpressionStatement 节点
                let experNode = types.expressionStatement(Arg[index].node);
                nodeList.push(experNode)
                console.log('逗号表达式:  ', generator(experNode).code.slice(0, 50).replaceAll('\n', ''));
                console.log('============================================================');
            }
            // 替换当前节点
            path.replaceWithMultiple(nodeList);
            path.skip();
        }
    }
})

还原 unicode, 16进制数值

// 还原 unicode, 16进制数值
traverse(ast, {
    "StringLiteral|NumericLiteral"(path) {
        if(path.node.extra){
            console.log('数值,unicode还原前:  ', path.node.extra.raw);
            delete path.node.extra.raw;
            console.log('数值,unicode还原后:  ', path.node.extra.rawValue);
            console.log('==============================')
        }
    }
});

字符串相加

// 字符串相加
function strConcat(path) {
    for (let i = 0; i <= 2; i++) {
        let node = path.node
        // left 节点为 StringLiteral 类型
        // right 节点为 StringLiteral 类型
        // operator 操作符属性为字符串 +
        if (types.isStringLiteral(node.left) && types.isStringLiteral(node.right) && node.operator === '+') {
            // 例 'e' + 'f'
            console.log('字符串相加前: ', path + '');

            // 例 'e' + 'f'
            let result = path.node.left.value + path.node.right.value;

            // 例: 'e' + 'f'
            // 替换成: 'ef'
            path.replaceWith(types.valueToNode(result));
            console.log('字符串相加后:  ', path + '');
            console.log('============================================================');
        } else {
            // 递归是针对多个字符串相加的
            // 例当前遍历到的节点: 'a' + 'b' + 'c' + 'd'
            // 这个节点在上面是不会处理的
            // path 对象的 traverse 方法是从当前节点继续遍历
            // 传入 strConcat 方法的节点就为:  'a' + 'b' + 'c' + 'd'
            // 调用过后还是会再次进入到 path.traverse 因为还是会有多个字符串相加
            // 上一次传入的节点被处理过了
            // 所以这一次传入的节点代码就为 'ab' + 'c' + 'd'
            // 一直递归到节点为 'abc' + 'd' 就会停止递归
            // 'abc' + 'd' 在 for 循环中会二次处理 (可以试着for循环只遍历一次看看效果
            path.traverse({
                BinaryExpression(path_) {
                    strConcat(path_)
                }
            })
        }
    }
}
traverse(ast, {
    BinaryExpression(path) {  // 遍历 BinaryExpression 节点
        strConcat(path)
    }
})

AST 解混淆完整代码

// 安装 babel 库:  npm install @babel/core
const fs = require('fs');

const traverse = require('@babel/traverse').default; // 用于遍历 AST 节点
const types = require('@babel/types');  // 用于判断, 生成 AST 节点

const parser = require('@babel/parser');  // 将js代码解析成ast节点
const generator = require('@babel/generator').default;  // 将ast节点转换成js代码

// 读取(路径记得改)
const ast_code = fs.readFileSync('demo.js', {
    encoding: 'utf-8'
});

let ast = parser.parse(ast_code);  // 将js代码解析成ast语法树


// 这里插入解析规则
///
// 解密函数还原
var _0x34bd = ["_$zr", "_$d5", ..];
var _0x54e9 = function (_0x1b88e5, _0x1abb3d) {
    _0x1b88e5 = _0x1b88e5 - 229;
    var _0x34bd3d = _0x34bd[_0x1b88e5];
    return _0x34bd3d;
};
var _0x1383f7 = _0x54e9;
(function (_0x5340a0, _0x2aca3b) {
    var _0x595372 = _0x54e9;
    while (!![]) {
        try {
            var _0x133a0b = parseInt(_0x595372(572)) + parseInt(_0x595372(418)) * -parseInt(_0x595372(834)) + -parseInt(_0x595372(350)) * -parseInt(_0x595372(483)) + parseInt(_0x595372(823)) + -parseInt(_0x595372(744)) + parseInt(_0x595372(382)) * parseInt(_0x595372(710)) + -parseInt(_0x595372(847)) * -parseInt(_0x595372(496));
            if (_0x133a0b === _0x2aca3b) break; else _0x5340a0["push"](_0x5340a0["shift"]());
        } catch (_0x28ba71) {
            _0x5340a0["push"](_0x5340a0["shift"]());
        }
    }
})(_0x34bd, 997352);
traverse(ast, {
    CallExpression(path) {
        // callee 类型为 Identifier name属性值为 _0x1383f7
        // arguments长度为1,且获取 arguments 参数中的 value 值
        if (path.get('callee').isIdentifier({name: '_0x1383f7'}) && path.node.arguments.length === 1) {

            console.log('解密函数还原前: ', path + '')
            let Arg = path.node.arguments[0].value;  // 获取参数值

            // 将节点替换
            path.replaceWith(types.valueToNode(_0x1383f7(Arg)))
            console.log('解密函数还原后: ', path + '')
            console.log('==============================')
        }
    }
});


// 数组引用还原
let _0xceb4b2 = [
    "name",
    "setAttribute",
    ...
];
traverse(ast, {
    MemberExpression(path) {
        // object 为 Identifier 类型 且 name 属性值为字符串 _0xceb4b2
        // property 为 NumericLiteral 类型
        if (path.get('object').isIdentifier({name: '_0xceb4b2'}) || path.get('object').isIdentifier({name: '_$UH'}) && path.get('property').isNumericLiteral()) {
            // 拿到 property 节点中的 value 值
            let value = path.node.property.value;

            // 节点替换
            console.log('数组引用还原前: ', path.parentPath + '');
            if (_0xceb4b2[value] === 'window') {
                path.replaceWith(types.identifier('window'));
            } else {
                path.replaceWith(types.valueToNode(_0xceb4b2[value]));
            }
            console.log('数组引用还原后: ', path.parentPath + '');
            console.log('==============================')
        }
    }
})


function reductionVar(init, name, type) {
    traverse(ast, {
        Identifier(identPath) {
            if (identPath.node.name === name) {
                // _0x4e96b4 = window 这样的节点是不需要修改的
                // _0x4e96b4['$_zw'] 需要修改这样的 MemberExpression 节点
                if (type === 'CallExpression' && identPath.parentPath.isCallExpression()) {
                    // identPath_.replaceWith(types.identifier(init))
                    console.log('内置对象引用还原前:  ', identPath.parentPath + '');
                    identPath.replaceWith(init);
                    console.log('内置对象引用还原后:  ', identPath.parentPath + '');
                    console.log('==============================')
                }
                if (type === 'MemberExpression' && identPath.parentPath.isMemberExpression()) {
                    // identPath_.replaceWith(types.identifier(init))
                    console.log('内置对象引用还原前:  ', identPath.parentPath + '');
                    identPath.replaceWith(types.identifier(init));
                    console.log('内置对象引用还原后:  ', identPath.parentPath + '');
                    console.log('==============================')
                }
            }
            identPath.skip()
        }
    })
}
// 浏览器内置对象引用
let nativeArray = [
    'window',
    'String',
    'Error',
    'Array',
    'Math',
    'parseInt',
    'Date',
    'document',
    'Object',
    'unescape',
    'encodeURIComponent',
    'Function',
    'CryptoJS'
].join('...') + '...';
traverse(ast, {
    VariableDeclarator(path) {
        let init = path.get('init').isIdentifier() && path.node.init.name;
        if (init && nativeArray.indexOf(init + '...') !== -1) {
            let name = path.get('id').isIdentifier() && path.node.id.name;
            reductionVar(init, name, 'MemberExpression')
        }
    },
    AssignmentExpression(path) {
        if (path.get('left').isIdentifier() && path.get('right').isIdentifier()) {
            let init = path.node.right.name;
            if (init && nativeArray.indexOf(init + '...') !== -1) {
                let name = path.node.left.name;
                reductionVar(init, name, 'MemberExpression')
            }
        }
    }
})
// 变量值引用
traverse(ast, {
    VariableDeclarator(path) {
        if (path.get('id').isIdentifier() && path.get('init').isMemberExpression()) {
            let init = path.node.init;
            let init_name = path.node.init.object;
            for (let i=0; i < 10; i++) {
                if (types.isIdentifier(init_name)) {
                    init_name = init_name.name;
                }
                if (types.isMemberExpression(init_name)) {
                    init_name = init_name.object;
                }
            }
            let name = path.node.id.name;
            if (init && nativeArray.indexOf(init_name + '...') !== -1) {
                console.log('内置对象: ', generator(init).code, ' 引用对象:  ', name);
                reductionVar(init, name, 'CallExpression')
            }
        }
    }
})


// 逗号表达式
traverse(ast, {
    VariableDeclaration(path) {
        if (path.get('declarations').length > 1) {
            // 例如: var a, b, c

            // 拿到声明符号 var
            let kind = path.node.kind;

            // 拿到 a, b, c 变量
            let Arg = path.get('declarations')

            // 创建的节点元素
            let nodeList = []
            for (const index in Arg) {
                // 创建一个新的 VariableDeclaration 节点
                // var a
                // var b
                // var c
                let varTionNode = types.variableDeclaration(kind, [Arg[index].node]);
                nodeList.push(varTionNode);
                console.log('逗号表达式:  ', generator(varTionNode).code.slice(0, 50).replaceAll('\n', ''));
                console.log('============================================================');
            }

            // 替换当前节点
            path.replaceWithMultiple(nodeList);
        }
    },
    SequenceExpression(path) {
        if (path.get('expressions').length > 1) {
            let Arg = path.get('expressions');
            let nodeList = []
            for (const index in Arg) {
                // 创建新的 ExpressionStatement 节点
                let experNode = types.expressionStatement(Arg[index].node);
                nodeList.push(experNode)
                console.log('逗号表达式:  ', generator(experNode).code.slice(0, 50).replaceAll('\n', ''));
                console.log('============================================================');
            }
            // 替换当前节点
            path.replaceWithMultiple(nodeList);
            path.skip();
        }
    }
})


// 还原 unicode, 16进制数值
traverse(ast, {
    "StringLiteral|NumericLiteral|DirectiveLiteral"(path) {
        if(path.node.extra){
            console.log('数值,unicode还原前:  ', path.node.extra.raw);
            delete path.node.extra.raw;
            console.log('数值,unicode还原后:  ', path.node.extra.rawValue);
            console.log('==============================')
        }
    }
});

// 字符串相加
function strConcat(path) {
    for (let i = 0; i <= 2; i++) {
        let node = path.node
        // left 节点为 StringLiteral 类型
        // right 节点为 StringLiteral 类型
        // operator 操作符属性为字符串 +
        if (types.isStringLiteral(node.left) && types.isStringLiteral(node.right) && node.operator === '+') {
            // 例 'e' + 'f'
            console.log('字符串相加前: ', path + '');

            // 例 'e' + 'f'
            let result = path.node.left.value + path.node.right.value;

            // 例: 'e' + 'f'
            // 替换成: 'ef'
            path.replaceWith(types.valueToNode(result));
            console.log('字符串相加后:  ', path + '');
            console.log('============================================================');
        } else {
            // 递归是针对多个字符串相加的
            // 例当前遍历到的节点: 'a' + 'b' + 'c' + 'd'
            // 这个节点在上面是不会处理的
            // path 对象的 traverse 方法是从当前节点继续遍历
            // 传入 strConcat 方法的节点就为:  'a' + 'b' + 'c' + 'd'
            // 调用过后还是会再次进入到 path.traverse 因为还是会有多个字符串相加
            // 上一次传入的节点被处理过了
            // 所以这一次传入的节点代码就为 'ab' + 'c' + 'd'
            // 一直递归到节点为 'abc' + 'd' 就会停止递归
            // 'abc' + 'd' 在 for 循环中会二次处理 (可以试着for循环只遍历一次看看效果
            path.traverse({
                BinaryExpression(path_) {
                    strConcat(path_)
                }
            })
        }
    }
}
traverse(ast, {
    BinaryExpression(path) {  // 遍历 BinaryExpression 节点
        strConcat(path)
    }
})
///

let js_code = generator(ast, {
    compact: true,  // 是否压缩,默认 false
}).code  // 将ast节点转换成js代码

// 写入(路径记得改)
fs.writeFileSync('New_demo.js', js_code, {
    encoding: 'utf-8',
})

加密参数还原

将 5.html 文件开启替换,并将解混淆后的 js 代码替换到对应的 Script 标签
全局搜索 function _$KS() {
将这个函数内的代码替换成 解混淆后的js代码
在这里插入图片描述
在这里插入图片描述

开启脚本断点
刷新页面 Hook Cookie 后取消勾选脚本断点,开始调试

Hook Cookie

(function () {
    let cookie_func = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
    Object.defineProperty(document, 'cookie', {
        get() {
            return cookie_func.get.call(this);
        },
        set(val) {
            if (val.indexOf('m') !== -1 || val.indexOf('RM4hZBv0dDon443M') !== -1){
                debugger
                console.log(val);
            }
            return cookie_func.set.call(this, val);
        }
    })
})();

在 m 字段设置第 5 次之后 RM4 才会赋值
在这里插入图片描述

cookie m字段

m字段一共会生成 5 次

前 4 次生成的位置

_$Wa = _0x12eaf3();  // _0x12eaf3() 是 Date["parse"](new Date())
document[_$Fe] = "m=" + _0x474032(_$Wa) + "; path=/";
window["_$pr"]["push"](_0x474032(_$Wa));  // _$pr 刚开始是空数组
/*
_$tT 和 _$Jy 初始的定义为
window["_$tT"] = -172015004;
window["_$Jy"] = 461512024;
*/
delete window["_$Jy"];
delete window["_$tT"];
window["_$Jy"] = _0x2d5f5b();  // new Date()["valueOf"]()
window["_$tT"] = _0x2d5f5b() - _0x12eaf3();  // new Date()["valueOf"]() - Date["parse"](new Date())

_0x474032() 方法时只需要扣 return 最后一个方法,因为传进去的参数始终就只有一个

function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
    return _0x37614a(_0x233f82);
}

_0x11a7a2() 方法里有检测

try {
	// window["XMLHttpRequest"]["prototype"]["DONE"] 的值始终为 4
    var _0x42fb36 = window["XMLHttpRequest"]["prototype"]["DONE"] * 4;
} catch (_0x1b1b35) {
    var _0x42fb36 = 1;
}
// 改写为
var _0x42fb36 = 4 * 4;
try {
    window["$_z2"][0] = "Q";
} catch (_0x4c574d) {
    try {
    	// window["$_zw"]["length"] 的值为 27
        op = window["$_zw"]["length"];
    } catch (_0x58af26) {
        var _0x3b7935 = 0;
        for (var _0x1badc3 = 0; _0x1badc3 < 1000000; _0x1badc3++) {
            _0x3b7935 = _0x3b7935 + _0x1badc3["toString"]();
            history["pushState"](0, 0, _0x3b7935);
        }
    }
    if (op > 20) {
    	// 执行后 b64pad 的值为 1
        eval("b64pad = _0x4e96b4['$_zw'][9]['length'];");
    } else if (op < 10) {
        window["$_zw"] = [1, 8, 2, 4, 23, 45, 8, 15, 81, 68, 13, 72, 70];
    }
}
// 改写
op = 27;
b64pad = 1;
var _0x3e0c38 = _0x1171c8;
var _0xdb4d2c = _0x4dae05;
var _0x1724c5 = _0x183a1d;
var _0x257ec6 = _0xcfa373;
// 全局搜索, _0x1171c8 可以找到定义位置
// 定义在文件开头处
var _0x1171c8 = 1732584193;
var _0x4dae05 = -271733879;
var _0x183a1d = -1732584194;
var _0xcfa373 = 271733878;
try {
    if (window["_$6_"]) {} else {
        window["_$6_"] = 8821003647;
    }
} catch (_0x15bf3f) {
    window["_$6_"] = 37885443;
}
// 控制台查看对应的值为 8821003647
// 改写
window["_$6_"] = 8821003647;

第 5 次生成的位置

_$yw = _0x2d5f5b()["toString"]();  // new Date()["valueOf"]();
document[_$Fe] = "m=" + _0x474032(_$yw) + "; path=/";
window["_$is"] = _$yw;  // 这个在后面加密 rm4 字段时有用
window["_$pr"]["push"](_0x474032(_$yw));

m字段坑点

加密时依赖的几个变量

这几个变量都需要在  _0x11a7a2() 方法中用到
window["_$Jy"], window["_$tT"], _0x42fb36
b64pad, _0x1171c8, _0x4dae05, _0x183a1d, _0xcfa373, window["_$6_"]

其实只要关注 
window["_$Jy"], window["_$tT"], window["_$6_"]

在 _0x11a7a2() 方法中插上条件断点

console.log(
    "_$Jy  ", window["_$Jy"], '\n',
    "_$tT  ", window["_$tT"], '\n',
    "_$6_  ", window["_$6_"], '\n',
)

for (_0x1badc3 = 0; 处在这里插入图片描述

重新 hook Cookie 直到 RM4hZBv0dDon443M 字段有值为止
第 1-4 次
在这里插入图片描述
第 5 次(重点)
在这里插入图片描述
刷新页面第 5 次的值还是固定的

cookie RM4hZBv0dDon443M 字段

开启脚本断点,刷新页面注入 Hook 代码
在 Hook 到 RM4 字段并且有值的时候查看上一层堆栈
(前2次的值是 undefined 不用理)
(后两次的值是一样的)
在这里插入图片描述

RM4 生成位置

// _$Fe 是 ’cookie‘
document[_$Fe] = "RM4hZBv0dDon443M=" + window["_$ss"] + "; path=/";

hook window[“_$ss”]

Hook 代码

// 老样子开启脚本断点,刷新页面,注入 Hook 代码 + Cookie 代码

// Hook Cookie
(function () {
    let cookie_func = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
    Object.defineProperty(document, 'cookie', {
        get() {
            return cookie_func.get.call(this);
        },
        set(val) {
        	console.log(val);
        	debugger;
            return cookie_func.set.call(this, val);
        }
    })
})();

// Hook window['_$ss']
(function () {
    let __$ss = window['_$ss'];
    Object.defineProperty(window, '_$ss', {
        get() {
            return __$ss
        },
        set(val) {
            debugger
            __$ss = val;
        }
    })
}
)()

在断点断住时查看上一层堆栈
_$ss 生成位置在这里插入图片描述

// window["_$pr"] 在前5次cookie生成的时候就有值了
_$Ww = CryptoJS["enc"]["Utf8"]["parse"](window["_$pr"]["toString"]());

// _0xc77418("0x6", "OCbs") 执行之后是 '_$qF' 
_0x29dd83 = CryptoJS["AES"]["encrypt"](_$Ww, window[_0xc77418("0x6", "OCbs")], {
    "mode": CryptoJS["mode"]["ECB"],
    "padding": CryptoJS["pad"]["Pkcs7"]
});

// _$ss 生成位置
window["_$" + "cs7"[1] + "cs7"[1]] = _0x29dd83["toString"]();

CryptoJS 在 nodejs 中直接导包就可以了 let CryptoJs = require(‘crypto-js’);
window[0xc77418(“0x6”, “OCbs”)] 也就是 window['$qF’] 生成的位置要找

Hook window[‘_$qF’]

// 和 Hook _$ss 的方式一样 开启脚本断点,注入代码后放开
// Hook Cookie
(function () {
    let cookie_func = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
    Object.defineProperty(document, 'cookie', {
        get() {
            return cookie_func.get.call(this);
        },
        set(val) {
        	console.log(val);
        	debugger;
            return cookie_func.set.call(this, val);
        }
    })
})();



// Hook window._$qF
(function () {
    let __$qF = window['_$qF'];
    Object.defineProperty(window, '_$qF', {
        get() {
            return __$qF
        },
        set(val) {
            debugger
            __$qF = val;
        }
    })
}
)()

_$qf 生成位置在这里插入图片描述

window["_$qF"] = CryptoJS["enc"]["Utf8"]["parse"](window["btoa"](window["_$is"])["slice"](0, 16));

// window["_$is"] 在 m 第五次生成的时候有赋值
// window["_$is"] = _$yw;

这段代码会执行很多次,插个日志断点查看值即可
在这里插入图片描述

console.log(window["_$is"])
// 全局搜索 _0x456805 < 213

在 m 生成的时候会给 _$yw 赋值,在赋值的位置也打上日志断点,确认是否引用了这个值
在这里插入图片描述

console.log(_$yw)
// 全局搜索
// _$aA["_$ji"] = _$aA[_$aA["_$ji"]](_0x2566fa, _0x56717d);

插好日志断点以后,还是刷新页面 Hook Cookie

第 5 次设置 m字段后 _$ym 有值了
在这里插入图片描述

window[“_$is”] 的值与 _$ym 一致
所以可以确定 $ym 就是 window["$is"]的值
在这里插入图片描述

请求参数

查看请求堆栈中 requests 栈
在这里插入图片描述
在这里插入图片描述

var list = {
     "page": window.page,
     "m": window._$is,  // window["_$is"] 在 cookie 设置第五次时就有赋值了
     "f": window.$_zw[23]
 };

全局搜索 $_zw[23]
在这里插入图片描述
let $_t1 = Date.parse(new Date());
在这里插入图片描述

验证
在这里插入图片描述

在这里插入图片描述

在整个代码逻辑中,$_t1 是最先赋值的 (let $_t1 = Date.parse(new Date());)
在 node 也是最先定义

请求代码

完整的 js 代码

window = global;
window["_$tT"] = -172015004;
window["_$Jy"] = 461512024;
window["_$pr"] = [];
var _0x1171c8 = 1732584193;
var _0x4dae05 = -271733879;
var _0x183a1d = -1732584194;
var _0xcfa373 = 271733878;
window["_$6_"] = 8821003647;

var CryptoJS = require('crypto-js');
var window = global;


function _0x3180ec(_0x401705, _0x240e6a, _0x56b131, _0x5a5c20, _0x1f2a72, _0x2bfc1, _0x19741a) {
    return _0xaaef84(_0x240e6a & _0x5a5c20 | _0x56b131 & ~_0x5a5c20, _0x401705, _0x240e6a, _0x1f2a72, _0x2bfc1, _0x19741a);
}
function _0x32032f(_0x520fdf, _0x13921d, _0x1af9d5, _0x4a2311, _0xb6d40a, _0x1d58da, _0x361df0) {
    return _0xaaef84(_0x13921d ^ _0x1af9d5 ^ _0x4a2311, _0x520fdf, _0x13921d, _0xb6d40a, _0x1d58da, _0x361df0);
}
function _0x4b459d(_0x8d8f2a, _0x406d34, _0x53e7d7, _0x26c827, _0xec41ea, _0x52dead, _0x3f66e7) {
    return _0xaaef84(_0x53e7d7 ^ (_0x406d34 | ~_0x26c827), _0x8d8f2a, _0x406d34, _0xec41ea, _0x52dead, _0x3f66e7);
}
function _0x3634fc(_0x5803ba, _0x1ce5b2) {
    return _0x5803ba << _0x1ce5b2 | _0x5803ba >>> 32 - _0x1ce5b2;
}
function _0x12e4a8(_0x7542c8, _0x5eada0) {
    var _0x41f81f = (65535 & _0x7542c8) + (65535 & _0x5eada0);
    return (_0x7542c8 >> 16) + (_0x5eada0 >> 16) + (_0x41f81f >> 16) << 16 | 65535 & _0x41f81f;
}
function _0xaaef84(_0xaf3112, _0x2a165a, _0x532fb4, _0x10aa40, _0x41c4e7, _0x1cb4da) {
    return _0x12e4a8(_0x3634fc(_0x12e4a8(_0x12e4a8(_0x2a165a, _0xaf3112), _0x12e4a8(_0x10aa40, _0x1cb4da)), _0x41c4e7), _0x532fb4);
}
function _0x48d200(_0x4b706e, _0x3c3a85, _0x111154, _0x311f9f, _0x5439cf, _0x38cac7, _0x26bd2e) {
    return _0xaaef84(_0x3c3a85 & _0x111154 | ~_0x3c3a85 & _0x311f9f, _0x4b706e, _0x3c3a85, _0x5439cf, _0x38cac7, _0x26bd2e);
}
function _0x35f5f2(_0x243853) {
    var _0x139b8b;
    var _0xa791a1 = [];
    for (_0xa791a1[(_0x243853["length"] >> 2) - 1] = void 0,
             _0x139b8b = 0; _0x139b8b < _0xa791a1["length"]; _0x139b8b += 1)
        _0xa791a1[_0x139b8b] = 0;
    var _0x41a533 = 8 * _0x243853["length"];
    for (_0x139b8b = 0; _0x139b8b < _0x41a533; _0x139b8b += 8)
        _0xa791a1[_0x139b8b >> 5] |= (255 & _0x243853["charCodeAt"](_0x139b8b / 8)) << _0x139b8b % 32;
    return _0xa791a1;
}
function _0x474032(_0x233f82, _0xe2ed33, _0x3229f9) {
    return _0x37614a(_0x233f82);
}
function _0x37614a(_0x32e7c1) {
    return _0x499969(_0x41873d(_0x32e7c1));
}
function _0x41873d(_0x5a6962) {
    return _0x1ee7ec(_0x2b8a17(_0x5a6962));
}
function _0x2b8a17(_0x36f847) {
    return unescape(encodeURIComponent(_0x36f847));
}
function _0x1ee7ec(_0x206333) {
    return _0x12b47d(_0x11a7a2(_0x35f5f2(_0x206333), 8 * _0x206333["length"]));
}
function _0x499969(_0x82fe7e) {
    var _0x5bdda4;
    var _0x322a73;
    var _0xd0b5cd = "0123456789abcdef";
    var _0x21f411 = "";
    for (_0x322a73 = 0; _0x322a73 < _0x82fe7e["length"]; _0x322a73 += 1) {
        _0x5bdda4 = _0x82fe7e["charCodeAt"](_0x322a73);
        _0x21f411 += _0xd0b5cd["charAt"](_0x5bdda4 >>> 4 & 15) + _0xd0b5cd["charAt"](15 & _0x5bdda4);
    }
    return _0x21f411;
}
function _0x12b47d(_0x149183) {
    var _0xabbcb3;
    var _0x1145c3 = "";
    var _0x4fce58 = 32 * _0x149183["length"];
    for (_0xabbcb3 = 0; _0xabbcb3 < _0x4fce58; _0xabbcb3 += 8)
        _0x1145c3 += String["fromCharCode"](_0x149183[_0xabbcb3 >> 5] >>> _0xabbcb3 % 32 & 255);
    return _0x1145c3;
}
function _0x11a7a2(_0x193f00, _0x1cfe89) {
    _0x193f00[_0x1cfe89 >> 5] |= 128 << _0x1cfe89 % 32;
    _0x193f00[14 + (_0x1cfe89 + 64 >>> 9 << 4)] = _0x1cfe89;
    var _0x42fb36 = 4 * 4;
    op = 27;
    b64pad = 1;
    var _0x1badc3;
    var _0x38ca59;
    var _0x431764;
    var _0x43f1b4;
    var _0x5722c0;
    var _0x3e0c38 = _0x1171c8;
    var _0xdb4d2c = _0x4dae05;
    var _0x1724c5 = _0x183a1d;
    var _0x257ec6 = _0xcfa373;
    for (_0x1badc3 = 0; _0x1badc3 < _0x193f00["length"]; _0x1badc3 += _0x42fb36) {
        _0x38ca59 = _0x3e0c38;
        _0x431764 = _0xdb4d2c;
        _0x43f1b4 = _0x1724c5;
        _0x5722c0 = _0x257ec6;
        _0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3], 7, 513548);
        _0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 1], 12, window["_$6_"]);
        _0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 2], 17, 606105819);
        _0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 3], 22, -1044525330);
        _0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 4], 7, -176418897);
        _0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 5], 12, 1200080426);
        _0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 6], 17, -1473231341);
        _0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 7], 22, -45705983);
        _0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 8], 7, 1770035416);
        _0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 9], 12, -1958414417);
        _0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 10], 17, -42063);
        _0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 11], 22, -1990404162);
        _0x3e0c38 = _0x48d200(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 12], 7, 1804603682);
        _0x257ec6 = _0x48d200(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 13], 12, -40341101);
        _0x1724c5 = _0x48d200(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 14], 17, -1502002290);
        _0xdb4d2c = _0x48d200(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 15], 22, 1236535329);
        _0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 1], 5, -165796510);
        _0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 6], 9, -1069501632);
        _0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 11], 14, 643717713);
        _0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3], 20, -373897302);
        _0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 5], 5, -701558691);
        _0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 10], 9, 38016083);
        _0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 15], 14, window["_$tT"]);
        _0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 4], 20, window["_$Jy"]);
        _0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 9], 5, 568446438);
        _0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 14], 9, -1019783690);
        _0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 3], 14, -187363961);
        _0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 8], 20, 1163531501);
        _0x3e0c38 = _0x3180ec(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 13], 5, -1554681467);
        _0x257ec6 = _0x3180ec(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 2], 9, -51403784);
        _0x1724c5 = _0x3180ec(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 7], 14, 1735328473);
        _0xdb4d2c = _0x3180ec(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 12], 20, -1926607734);
        _0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 5], 4, -37824558);
        _0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 8], 11, -2022574463);
        _0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 11], 16, 1839030562);
        _0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 14], 23, -35309556);
        _0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 1], 4, -1530992060 * b64pad);
        _0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 4], 11, 1272893353);
        _0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 7], 16, -155497632);
        _0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 10], 23, -1094730640);
        _0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 13], 4, 681279174);
        _0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3], 11, -358537222);
        _0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 3], 16, -722521979);
        _0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 6], 23, 760291289);
        _0x3e0c38 = _0x32032f(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 9], 4, -64036887);
        _0x257ec6 = _0x32032f(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 12], 11, -421815835);
        _0x1724c5 = _0x32032f(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 15], 16, 530742520);
        _0xdb4d2c = _0x32032f(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 2], 23, -995338651);
        _0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3], 6, -198630844);
        _0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 7], 10, 1126891415);
        _0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 14], 15, -1416354905);
        _0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 5], 21, -57434055);
        _0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 12], 6, 1700485571);
        _0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 3], 10, -1894746606);
        _0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 10], 15, -105181523);
        _0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 1], 21, -2054922799);
        _0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 8], 6, 1873313359);
        _0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 15], 10, -30611744);
        _0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 6], 15, -1560198380);
        _0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 13], 21, 1309151649);
        _0x3e0c38 = _0x4b459d(_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6, _0x193f00[_0x1badc3 + 4], 6, -145523070);
        _0x257ec6 = _0x4b459d(_0x257ec6, _0x3e0c38, _0xdb4d2c, _0x1724c5, _0x193f00[_0x1badc3 + 11], 10, -1120211379);
        _0x1724c5 = _0x4b459d(_0x1724c5, _0x257ec6, _0x3e0c38, _0xdb4d2c, _0x193f00[_0x1badc3 + 2], 15, 718787259);
        _0xdb4d2c = _0x4b459d(_0xdb4d2c, _0x1724c5, _0x257ec6, _0x3e0c38, _0x193f00[_0x1badc3 + 9], 21, -343485441);
        _0x3e0c38 = _0x12e4a8(_0x3e0c38, _0x38ca59);
        _0xdb4d2c = _0x12e4a8(_0xdb4d2c, _0x431764);
        _0x1724c5 = _0x12e4a8(_0x1724c5, _0x43f1b4);
        _0x257ec6 = _0x12e4a8(_0x257ec6, _0x5722c0);
    }
    return [_0x3e0c38, _0xdb4d2c, _0x1724c5, _0x257ec6];
}

function sdk() {
    let $_t1 = Date.parse(new Date());
    // cookie_m  1-4 次
    for (let i = 0; i < 4; i++) {
        let _$Wa = Date["parse"](new Date());
        cookie_m = _0x474032(_$Wa);
        window["_$pr"].push(_0x474032(_$Wa));
        delete window["_$Jy"];
        delete window["_$tT"];
        window["_$Jy"] = new Date()["valueOf"]();
        window["_$tT"] = new Date()["valueOf"]() - Date["parse"](new Date());
    }

    // cookie_m  第五次
    window["_$Jy"] = -405537848;
    window["_$tT"] = -660478335;
    window["_$6_"] = -389564586;
    let _$yw = new Date()["valueOf"]();
    cookie_m = _0x474032(_$yw);
    window["_$is"] = _$yw;
    window["_$pr"]["push"](_0x474032(_$yw));
    // console.log(cookie_m);
    // console.log(_$pr);

    window["_$qF"] = CryptoJS["enc"]["Utf8"]["parse"](window["btoa"](window["_$is"])["slice"](0, 16));
    let _$Ww = CryptoJS["enc"]["Utf8"]["parse"](window["_$pr"]["toString"]());
    let cookie_rm4 = CryptoJS["AES"]["encrypt"](_$Ww, window['_$qF'], {
        "mode": CryptoJS["mode"]["ECB"],
        "padding": CryptoJS["pad"]["Pkcs7"]
    }).toString();
    // console.log(cookie_m);
    // console.log(cookie_rm4);
    return {
        cookie_m,
        cookie_rm4,
        params_m: window["_$is"],
        params_f: $_t1
    }
}
// console.log(sdk());

完整的 python 代码

import requests
import execjs
import time

headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
}
cookies = {
    "sessionid": "你的sessionid",
    "m": "",
    "RM4hZBv0dDon443M": ""
}


def call_js(file_name, func_name, *args):
    with open(file_name, mode='r', encoding='utf-8') as f:
        js_code = execjs.compile(f.read())
    return js_code.call(func_name, *args)


def send_match5(page, param_dict):
    url = "https://match.yuanrenxue.cn/api/match/5"
    params = {
        "page": page,
        "m": param_dict['params_m'],
        "f": param_dict['params_f']
    }


    response = requests.get(url, headers=headers, cookies=cookies, params=params)
    cookies["m"] = param_dict['cookie_m']
    cookies["RM4hZBv0dDon443M"] = param_dict['cookie_rm4']
    print(params)
    print(cookies)
    print(response.json())
    print('==================================================')


if __name__ == '__main__':
    time_ = int(str(int(time.time() * 1000))[:10] + '000')
    send_params = call_js('5.js', 'sdk')  # params_m, cookie_m, cookie_rm4
    send_params['params_f'] = time_
    for page in range(1, 3):
        send_match5(page, send_params)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值