请求流程
打开 调试工具,查看数据接口 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)