【困难】 猿人学web第一届 第14题 备而后动-勿使有变

news2024/11/13 10:21:24

调试干扰

进入题目 打开开发者工具会进入一个无限 debugger;

向上查看堆栈,可以找到生成 debugger 的代码段在这里插入图片描述

手动解混淆后可以知道 debugger 生成的方式在这里插入图片描述

(function () {
    // 函数内的代码是不需要的,因为里面的代码不会执行
}['constructor']('debugger')['call']('action'));

是利用 Function.prototype.constructor 函数生成的 debugger
因为 (function(){}[‘constructor’]) === Function.prototype.constructor;
在这里插入图片描述

Hook 代码

_Function = Function.prototype.constructor;
Function.prototype.constructor = function (val) {
    if(val.indexOf('debugger') !== -1){
        return _Function.call(this, '')
    }
    return _Function.call(this, val)
}

请求流程

数据接口 https://match.yuanrenxue.cn/api/match/14在这里插入图片描述
请求参数为 对应的页码在这里插入图片描述
cookie 参数需要携带 m,mz 字段
mz 字段是一样的
m 字段是动态的
在这里插入图片描述
在这里插入图片描述

每次请求数据前,都会先请求 m文件
m 文件是动态的,返回的是 js 代码在这里插入图片描述> 在这里插入图片描述

Hook Cookie

请求数据时需要携带 cookie 中 m 和 mz 参数

// Hook Function
_Function = Function.prototype.constructor;
Function.prototype.constructor = function (val) {
    if(val.indexOf('debugger') !== -1){
        return _Function.call(this, '')
    }
    return _Function.call(this, val)
};
// Hook Cookie
(function(){
    const cookieSet = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')
    Object.defineProperty(document, 'cookie', {
        get(){
            return cookieSet.get.call(this);
        },
        set(val){
            debugger
            return cookieSet.set.call(this, val);
        }
    })
})()

勾选脚本断点 --> 刷新页面 --> 注入 Hook 代码 --> 取消勾选脚本断点 --> 放开断点
在这里插入图片描述
在这里插入图片描述
生成 cookie 的 m.js 文件是经过混淆的,给 m.js 安排一下 AST

AST 还原 m.js文件

先保存一份 m.js 文件到本地

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语法树


// 这里插入解析规则 ==============================================================================================================================================================================

// unicode, 十六进制数值
traverse(ast, {
    StringLiteral(path) {
        delete path.node.extra.raw;
    },
    NumericLiteral(path) {
        delete path.node.extra.raw;
    }
})


// 字符串相加
function addStr(path) {
    if (path.get('left').isStringLiteral() && path.get('right').isStringLiteral()) {
        let left = path.node.left.value;
        let right = path.node.right.value;
        let result = left + right
        path.replaceWith(types.stringLiteral(result))
    } else if (path.get('left').isBinaryExpression() && path.get('right').isStringLiteral()) {
        path.traverse({
            BinaryExpression(path_) {
                addStr(path_)
            }
        })
    }
}

for (let i = 0; i < 2; i++) {
    traverse(ast, {
        BinaryExpression(path) {
            addStr(path)
        }
    })
}

// 逗号表达式
traverse(ast, {
    VariableDeclaration(path) {
        if (path.get('declarations').length > 1) {
            let kind = path.node.kind
            let declarations = path.node.declarations
            let nodeList = []
            for (const idx in declarations) {
                let newNode = types.variableDeclaration(kind, [declarations[idx]])
                nodeList.push(newNode)
            }
            path.replaceWithMultiple(nodeList)
        }
    },
    SequenceExpression(path) {
        if (path.get('expressions').length > 1) {
            let expressions = path.node.expressions;
            let nodeList = [];
            for (const idx in expressions) {
                nodeList.push(expressions[idx])
            }
            path.replaceWithMultiple(nodeList)
            path.skip()
        }
    },
    ReturnStatement(path) {
        if (path.node.argument && path.get('argument.expressions').length > 1) {
            let expressions = path.node.argument.expressions;
            let nodeList = expressions.slice(0, -1);
            let retNOde = types.returnStatement(expressions[expressions.length - 1])
            nodeList.push(retNOde)
            path.replaceWithMultiple(nodeList)
        }
    }
})

js_code = generator(ast, {
    compact: false,  // 是否压缩,默认 false
}).code

ast = parser.parse(js_code);
function addObj(path, newObj) {
    let name = path.node.id.name;
    let binding = path.scope.getBinding(name);
    if (binding) {
        let refPath = binding.referencePaths;
        for (const idx in refPath) {
            let grandPath = refPath[idx].parentPath.parentPath;
            if(grandPath.isAssignmentExpression() && grandPath.get('left').isMemberExpression() && grandPath.get('left.property').isStringLiteral()){
                let key = grandPath.node.left.property.value;
                newObj[key] = grandPath.get('right');
            }else if(grandPath.isVariableDeclaration()){
                repObj(grandPath, newObj)
            }
        }
    }
}
function repObj(path, newObj) {
    let name = path.node.declarations[0].id.name;
    let binding = path.scope.getBinding(name);
    if(binding){
        let refPath = binding.referencePaths.reverse();
        for(const idx in refPath){
            let parPath = refPath[idx].parentPath;
            if(parPath.isMemberExpression() && parPath.get('property').isStringLiteral()){
                let key = parPath.node.property.value;
                if(newObj[key].isStringLiteral()){
                    parPath.replaceWith(newObj[key].node);
                }else if (newObj[key].isFunctionExpression() && newObj[key].get('body.body').length === 1){
                    let returnStatement = newObj[key].get('body.body')[0].get('argument');
                    let grandPath = parPath.parentPath;
                    if(returnStatement.isBinaryExpression() || returnStatement.isLogicalExpression()){
                        let operator = returnStatement.node.operator;
                        let callArg = grandPath.node.arguments;
                        let newNode = returnStatement.isBinaryExpression()
                            ? types.binaryExpression(operator, callArg[0], callArg[1])
                            : types.logicalExpression(operator, callArg[0], callArg[1]) ;
                        grandPath.replaceWith(newNode);
                    }else if(returnStatement.isCallExpression()){
                        let callArg = grandPath.node.arguments;
                        let newNode = types.CallExpression(callArg[0], callArg.slice(1))
                        grandPath.replaceWith(newNode);
                    }
                }
            }
        }
    }
}
// 花指令
traverse(ast, {
    VariableDeclarator(path) {
        if (path.get('init').isObjectExpression()) {
            let newObj = {};
            addObj(path, newObj)
        }
    }
})

// 字符串相加
for (let i = 0; i < 2; i++) {
    traverse(ast, {
        BinaryExpression(path) {
            addStr(path)
        }
    })
}

js_code = generator(ast, {
    compact: false,  // 是否压缩,默认 false
}).code
ast = parser.parse(js_code);

// switch
traverse(ast, {
    WhileStatement(path){
        if(path.inList && path.get('test').isUnaryExpression()){
            let idxArray = path.getSibling(path.key - 2).node.declarations[0].init.callee.object.value.split('|')
            let cases = path.get('body.body')[0].get('cases')
            let idxObj = {}
            for (const idx in cases){
                let key = cases[idx].get('test').node.value;
                idxObj[key] = cases[idx].get('consequent')
            }

            let nodeArr = []
            idxArray.forEach((objkey) => {
                for (const arrIdx in idxObj[objkey]){
                    if(!idxObj[objkey][arrIdx].isContinueStatement()){
                        nodeArr.push(idxObj[objkey][arrIdx].node)
                    }
                }
            })

            for (let i=0; i<=path.key; i++){
                path.getSibling(0).remove()
            }
            path.replaceWithMultiple(nodeArr)
        }
    }
})

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

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

将 m.js 内容替换成还原后的继续 Hook cookie

Hook 到 cookie生成的位置后,向上查看堆栈在这里插入图片描述

mz 字段生成的位置在这里插入图片描述

m 字段生成的位置
在这里插入图片描述

加密流程

cookie mz 字段

Hook Cookie 后首先看到的是 mz 字段
在这里插入图片描述

向上查看堆栈,查看生成 cookie mz 字段的代码段
在这里插入图片描述
b64_zw 通过 btoa(z) 生成 z为数组,环境值

mz 字段可以固定,不需要在本地生成,每个人的电脑环境不一样,生成的值也不一样,
同一台电脑的 mz 字段是一样的

cookie m 字段

在这里插入图片描述

向上查看堆栈
在这里插入图片描述

正常情况下 Object[“defineProperty”] 不传参数执行是会报错的
在这里插入图片描述
但在 14 题的页面中执行返回的是空字符串
在这里插入图片描述

因为在文件的开头 Object[“defineProperty”] 就被重写了
(所以 hook cookie 要在脚本执行前 hook才能 hook 到)
在这里插入图片描述

所以生成 m 字段 代码会执行 false 条件的代码段

document["cookie"] = "m=" + m5(gee(aa, bb, c, d, e, b64_zw)) + "|" + b + "|" + a + "|" + window["n"] + ";path=/";

在这里插入图片描述

现在 window[‘n’], window[‘v142’], window[‘v14’] 还不知道是怎么生成的

hook window 的 ‘n’, ‘v142’, ‘v14’ 属性

勾选脚本断点,在页面脚本开始执行前 hook

function HookFunc(obj, key) {
    let blockVar = obj[key];
    Object.defineProperty(obj, key, {
        get() {
            return blockVar
        },
        set(val) {
            console.log(key, val)
            debugger;
            blockVar = val;
        }
    })
}
['n', 'v142', 'v14'].forEach((value) => {HookFunc(window, value)})

window[‘n’]
在这里插入图片描述

window[‘v142’]
在这里插入图片描述
在这里插入图片描述

window[‘‘v14’’]
在这里插入图片描述
在这里插入图片描述

注意

m 文件是动态的,n值是固定的0,但 v14, v142 的值是动态变化的

生成 v14, v142 属性的代码段是在 eval 函数里生成的 Y 是请求
在这里插入图片描述
Y 是请求 “/api/match/14/m” 后返回的数据
在这里插入图片描述
在这里插入图片描述

将 “/api/match/14/m” 接口里的代码还原后进行替换
在这里插入图片描述

m 代码反混淆

先将将 m 文件替换
在这里插入图片描述
将代码保存到本地 demo.js

解密函数

前三列是解密函数和对应的依赖,还原时是需要用到的在这里插入图片描述
解密函数内部是有格式化检测的,这里将 REgExp.prototype.test 方法重写即可在这里插入图片描述

代码
// 安装 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语法树


// 这里插入解析规则 ==============================================================================================================================================================================
// unicode, 十六进制数值
traverse(ast, {
    StringLiteral(path) {
        delete path.node.extra.raw;
    },
    NumericLiteral(path) {
        delete path.node.extra.raw;
    }
})


RegExp.prototype.test = function(){return true}
var $_0x5109 = [解密函数数组];
(function (_0x3608d7, _0x510963) {
    // 自执行数组乱序
}($_0x5109, 0x147));
var $_0x5d3c = function (_0x3608d7, _0x510963) {
   // 解密函数
    return _0x5d3c4d;
};
// 解密函数还原字符串
traverse(ast, {
    CallExpression(path){
        if(path.get('callee').isIdentifier({name: $_0x5d3c.name})){
            let callArg = path.node.arguments;
            let result = $_0x5d3c(callArg[0].value, callArg[1].value);
            path.replaceWith(types.StringLiteral(result))
        }
    }
})


// 字符串相加
function addStr(path) {
    if (path.get('left').isStringLiteral() && path.get('right').isStringLiteral()) {
        let left = path.node.left.value;
        let right = path.node.right.value;
        let result = left + right
        path.replaceWith(types.stringLiteral(result))
    } else if (path.get('left').isBinaryExpression() && path.get('right').isStringLiteral()) {
        path.traverse({
            BinaryExpression(path_) {
                addStr(path_)
            }
        })
    }
}
for (let i = 0; i < 2; i++) {
    traverse(ast, {
        BinaryExpression(path) {
            addStr(path)
        }
    })
}

// 解决正则字符串报错
traverse(ast, {
    StringLiteral(path){
        let result = path.node.value;
        if(result.indexOf('"') !== -1 || result.indexOf("'") !== -1 || result.indexOf("\\") !== -1){
            path.replaceWith(types.templateLiteral(
                [types.templateElement({raw: result})],
                []
            ))
        }
    }
})

// 逗号表达式
traverse(ast, {
    VariableDeclaration(path) {
        if (path.get('declarations').length > 1) {
            let kind = path.node.kind
            let declarations = path.node.declarations
            let nodeList = []
            for (const idx in declarations) {
                let newNode = types.variableDeclaration(kind, [declarations[idx]])
                nodeList.push(newNode)
            }
            path.replaceWithMultiple(nodeList)
        }
    },
    SequenceExpression(path) {
        if (path.get('expressions').length > 1) {
            let expressions = path.node.expressions;
            let nodeList = [];
            for (const idx in expressions) {
                nodeList.push(expressions[idx])
            }
            path.replaceWithMultiple(nodeList)
            path.skip()
        }
    },
    ReturnStatement(path) {
        if (path.node.argument && path.get('argument.expressions').length > 1) {
            let expressions = path.node.argument.expressions;
            let nodeList = expressions.slice(0, -1);
            let retNOde = types.returnStatement(expressions[expressions.length - 1])
            nodeList.push(retNOde)
            path.replaceWithMultiple(nodeList)
        }
    }
})

js_code = generator(ast, {
    compact: false,  // 是否压缩,默认 false
}).code
ast = parser.parse(js_code);

// 花指令
function addObj(path, newObj) {
    let name = path.node.id.name;
    let binding = path.scope.getBinding(name);
    if (binding) {
        let refPath = binding.referencePaths;
        for (const idx in refPath) {
            let grandPath = refPath[idx].parentPath.parentPath;
            if(grandPath.isAssignmentExpression() && grandPath.get('left').isMemberExpression() && grandPath.get('left.property').isStringLiteral()){
                let key = grandPath.node.left.property.value;
                newObj[key] = grandPath.get('right');
            }else if(grandPath.isVariableDeclaration()){
                repObj(grandPath, newObj)
            }
        }
    }
}
function repObj(path, newObj) {
    let name = path.node.declarations[0].id.name;
    let binding = path.scope.getBinding(name);
    if(binding){
        let refPath = binding.referencePaths.reverse();
        for(const idx in refPath){
            let parPath = refPath[idx].parentPath;
            if(parPath.isMemberExpression() && parPath.get('property').isStringLiteral()){
                let key = parPath.node.property.value;
                if(newObj[key].isStringLiteral() || newObj[key].isTemplateLiteral()){
                    parPath.replaceWith(newObj[key].node);
                }else if (newObj[key].isFunctionExpression() && newObj[key].get('body.body').length === 1){
                    let returnStatement = newObj[key].get('body.body')[0].get('argument');
                    let grandPath = parPath.parentPath;
                    if(returnStatement.isBinaryExpression() || returnStatement.isLogicalExpression()){
                        let operator = returnStatement.node.operator;
                        let callArg = grandPath.node.arguments;
                        let newNode = returnStatement.isBinaryExpression()
                            ? types.binaryExpression(operator, callArg[0], callArg[1])
                            : types.logicalExpression(operator, callArg[0], callArg[1]) ;
                        grandPath.replaceWith(newNode);
                    }else if(returnStatement.isCallExpression()){
                        let callArg = grandPath.node.arguments;
                        let newNode = types.CallExpression(callArg[0], callArg.slice(1))
                        grandPath.replaceWith(newNode);
                    }
                }else{
                    console.log('未处理的类型', newObj[key].type)
                    console.log(newObj[key].toString())
                }
            }
        }
    }
}
traverse(ast, {
    VariableDeclarator(path) {
        if (path.get('init').isObjectExpression()) {
            let newObj = {};
            addObj(path, newObj)
        }
    }
})

// 字符串相加
for (let i = 0; i < 2; i++) {
    traverse(ast, {
        BinaryExpression(path) {
            addStr(path)
        }
    })
}

// switch
traverse(ast, {
    WhileStatement(path){
        if(path.inList && path.get('test').isUnaryExpression()){
            let idxArray = path.getSibling(path.key - 2).node.declarations[0].init.callee.object.value.split('|')
            let cases = path.get('body.body')[0].get('cases')
            let idxObj = {}
            for (const idx in cases){
                let key = cases[idx].get('test').node.value;
                idxObj[key] = cases[idx].get('consequent')
            }

            let nodeArr = []
            idxArray.forEach((objkey) => {
                for (const arrIdx in idxObj[objkey]){
                    if(!idxObj[objkey][arrIdx].isContinueStatement()){
                        nodeArr.push(idxObj[objkey][arrIdx].node)
                    }
                }
            })

            for (let i=0; i<=path.key; i++){
                path.getSibling(0).remove()
            }
            path.replaceWithMultiple(nodeArr)
        }
    }
})

// 无用 if
traverse(ast, {
    "IfStatement"(path){
        if(path.get('test').isStringLiteral()){
            let test = path.node.test.value;
            let ifStatement = path.node.consequent;
            let elseStatement = path.node.alternate;
            let result = Boolean(test);
            result ? path.replaceWith(ifStatement) : path.replaceWith(elseStatement)
        }
    }
})

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

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

全局搜索 test, 将对应的 Regexp 注释,将 test 改为 true (格式化检测)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

将 m 文件替换成还原后的代码
在这里插入图片描述

补环境

使用反混淆后的 m.js / m文件补环境会轻松的多(能看得到操作浏览器哪些对象的属性)

在本地执行文件,首先报错 window is not defined在这里插入图片描述
在文件头部声明 window = global;

在文件头部声明 document = {};
在文件尾部打印 console.log(document.cookie)
再次运行就没有报错了,document.cookie 打印出来的值是 undefined
在这里插入图片描述

观察浏览器对应的页面,是执行了 sp() 方法后才进入流程的,在本地也执行 sp() 方法
在这里插入图片描述
执行后报错了
在这里插入图片描述
看看这个代码段 和 cookie mz字段的生成有关系
在这里插入图片描述

这里拿的都是自己的环境值

Object.prototype.toString = function(){
  return `[object ${this.constructor.name}]`
}
function NetworkInformation(){}
function Geolocation(){}
function MediaCapabilities(){}
function MediaSession(){}
function MimeTypeArray(){}
function Permissions(){}
function PluginArray(){}
function UserActivation(){}
function DeprecatedStorageQuota(){}
navigator = {};
navigator["appCodeName"] = 拿你自己的;
navigator["appName"] = 拿你自己的;
navigator["appVersion"] = '拿你自己的
navigator["connection"] = new NetworkInformation();
navigator["cookieEnabled"] = true
navigator["doNotTrack"] = null
navigator["geolocation"] = new Geolocation();
navigator["hardwareConcurrency"] = 拿你自己的;
navigator["language"] = '拿你自己的';
navigator["languages"] = [拿你自己的];
navigator["maxTouchPoints"] = 0
navigator["mediaCapabilities"] = new MediaCapabilities();
navigator["mediaSession"] = new MediaSession();
navigator["mimeTypes"] = new MimeTypeArray();
navigator["onLine"] = true
navigator["permissions"] = new Permissions();
navigator["platform"] = 'Win32';
navigator["plugins"] = new PluginArray();
navigator["product"] = 'Gecko';
navigator["productSub"] = '20030107';
navigator["userActivation"] = new UserActivation();
navigator["userAgent"] = '拿你自己的';
navigator["vendor"] = '拿你自己的';
navigator["vendorSub"] = '';
navigator["webkitPersistentStorage"] = new DeprecatedStorageQuota();
navigator["webkitTemporaryStorage"] = new DeprecatedStorageQuota();


screen = {}
function ScreenOrientation(){}
screen["availHeight"] = 1040
screen["availLeft"] = 0
screen["availTop"] = 0
screen["availWidth"] = 1920
screen["colorDepth"] = 24
screen["height"] = 1080
screen["orientation"] = new ScreenOrientation();
screen["pixelDepth"] = 24
screen["width"] = 1920;

function DOMStringList(){}
document = {};
document["location"] = {};
document["location"]["ancestorOrigins"] = new DOMStringList();
document["location"]["hash"] = ''
document["location"]["host"] = 'match.yuanrenxue.cn'
document["location"]["hostname"] = 'match.yuanrenxue.cn'
document["location"]["href"] = 'https://match.yuanrenxue.cn/match/14'
document["location"]["origin"] = 'https://match.yuanrenxue.cn'
document["location"]["pathname"] = '/match/14'
document["location"]["port"] = ''
document["location"]["protocol"] = 'https:'
document["location"]["search"] = ''

document["location"]["assign"] = function assign(){}
document["location"]["assign"].toString = function (){return 'function assign() { [native code] }'}

document["location"]["reload"] = function reload(){}
document["location"]["reload"].toString = function (){return 'function reload() { [native code] }'}

document["location"]["replace"] = function replace(){}
document["location"]["replace"].toString = function (){return 'function replace() { [native code] }'}

document["location"]["toString"] = function toString(){}
document["location"]["toString"].toString = function (){return 'function toString() { [native code] }'}

document["location"]["valueOf"] =  function valueOf(){}
document["location"]["valueOf"].toString = function (){return 'function valueOf() { [native code] }'}

再次执行后报错 $ is not defined
在这里插入图片描述
看看这段代码
在这里插入图片描述
再看看浏览器,浏览器里是执行了 success 方法,并且用 eval 执行了接口返回的代码
k 是接口返回的内容
在这里插入图片描述
将这个方法补上

$ = {
  'ajax': function(){
    // 替换成 eval 内的代码段
    }
}

继续执行后报错 ASN1 is not defined
在这里插入图片描述
ASN1 是有给 window 赋值的
在这里插入图片描述
单独调用 ASN1 会报错 undefined
在这里插入图片描述
因为 window 并不是全局变量 global 才是
如果赋值的代码为 global[‘ASN1’] = … 再单独调用 ASN1 是找得到值的
设置 window 的 属性的描述符

// 全局对象有两个,globalTHis, global
// 可以通过 globalThis 查看 global(globalThis.global)
// 可以通过 global 查看 globalTHis(global.globalThis)
Object.defineProperty(globalThis, 'window', {
  get(){
    return globalThis;
  }
})

在这里插入图片描述

调试 调用 ASN1 就可以找到了
在这里插入图片描述

继续执行后进入死循环(这个代码段如果按照前面的方法做了,其实已经被删除了)
在这里插入图片描述
条件判断的代码
if (m5"toString"“indexOf” != -(552 + 71 * -103 + -156 * -53 + -(4814 + -2 * -3371 + -11245) * -(-6316 + -8443 * 1 + -1055 * -14) + -(-1333 + 1468 + 2 * 2396))) while (!![]) {
在这里插入图片描述
判断通过后会进入死循环
这行代码可以直接删掉,里面没有业务逻辑(调试的时候 格式化的代码会被检测到)

继续执行会报错 alert is not defined
在这里插入图片描述

这是在一个 try catch 块中的代码
调试看看 try 块中的代码报了什么错(或者可以将 try catch 块删除只保留框选的那一段代码)
只用执行 框选的那一句,因为 definedProperty 被重写了 执行后只返回 空字符串
在这里插入图片描述
报错 undefined(reading ‘length’) undefined 无法读取 ‘length’ 属性
逐个看 gee() 方法传入进去的参数 aa, bb, c, d, e, b64_zw
c 和 e 为 defined, c 和 e 各自为 window.v14, window.v142 属性的值
在这里插入图片描述
window.v14, window.v142 是在 m接口返回的代码段设置的
m接口 的代码是通过 ajax success 方法执行的
在这里插入图片描述
将 ajax 方法重写
在这里插入图片描述

$ = {
    'ajax': function(){
        // 替换成还原好的 m 的代码
    }
}

再次运行 代码会一直阻塞,不打印结果
将 setTimeout, setInterval 置空
setTimeout = function(){}
setInterval = function(){}

成功运行结束了,但是没有输出结果在这里插入图片描述
console.log 被重写了在这里插入图片描述

在文件开头声明一个变量 接收console.log 方法
_log = console.log;
顺利输出了在这里插入图片描述

验证结果的时候,加密出来的值不一致在这里插入图片描述
将浏览器和本地加密的值都写死,一起单步调试,排查问题在这里插入图片描述

不报错的环境检测

搜索 eval 这 4 个操作对浏览器是无效的,这两个内置对象不能被删除,不能被设置值
在这里插入图片描述
在本地修改这两个对象的属性描述符,设置为不可删除,不可修改

// window
Object.defineProperty(globalThis, 'window', {
  get(){
    return globalThis;
  },
  configurable: false,  // 对象不可删除
})

// navigator
Object.defineProperty(globalThis, 'navigator', {
  configurable: false,  // 不可删除
  writable: false  // 不可修改
})

// document
Object.defineProperty(globalThis, 'document', {
  configurable: false,  // 不可删除
  writable: false  // 不可修改
})

全局搜索 try

补 CanvasCaptureMediaStreamTrack 方法
在这里插入图片描述

CanvasCaptureMediaStreamTrack = function CanvasCaptureMediaStreamTrack(){};

浏览器中查看 gloabl 会报错,nodejs不会,设置 nodejs 中 global 的属性描述符在这里插入图片描述

Object.defineProperty(globalThis, 'global', {
  get(){
    // 只要一访问 global 就会报错
    throw Error('')
  },
})

Python 代码

js 模板

还有一个坑
如果页码为 1 那么 m字段是加密一次生成的
如果页码为 2 那么 m字段是加密两次生成的
所以模板最后应该改为
for(let i=1; i<=// 页码; i++){
sp()
}

Object.defineProperty(globalThis, 'global', {
  get(){
    throw Error('')
  },
})
_log = console.log;
window = {}
Object.defineProperty(globalThis, 'window', {
  get(){
    return globalThis;
  },
  configurable: false,  // 对象不可删除
})
setTimeout = function setTimeout(){};
setInterval = function setInterval(){};
CanvasCaptureMediaStreamTrack = function CanvasCaptureMediaStreamTrack(){};
Object.prototype.toString = function(){
  return `[object ${this.constructor.name}]`
}
function NetworkInformation(){}
function Geolocation(){}
function MediaCapabilities(){}
function MediaSession(){}
function MimeTypeArray(){}
function Permissions(){}
function PluginArray(){}
function UserActivation(){}
function DeprecatedStorageQuota(){}
navigator = {};
Object.defineProperty(globalThis, 'navigator', {
  configurable: false,  // 不可删除
  writable: false  // 不可修改
})
navigator["appCodeName"] = 'Mozilla';
navigator["appName"] = 'Netscape';
navigator["appVersion"] = '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
navigator["connection"] = new NetworkInformation();
navigator["cookieEnabled"] = true
navigator["doNotTrack"] = null
navigator["geolocation"] = new Geolocation();
navigator["hardwareConcurrency"] = 12;
navigator["language"] = 'zh-CN';
navigator["languages"] = ['zh-CN', 'zh'];
navigator["maxTouchPoints"] = 0
navigator["mediaCapabilities"] = new MediaCapabilities();
navigator["mediaSession"] = new MediaSession();
navigator["mimeTypes"] = new MimeTypeArray();
navigator["onLine"] = true
navigator["permissions"] = new Permissions();
navigator["platform"] = 'Win32';
navigator["plugins"] = new PluginArray();
navigator["product"] = 'Gecko';
navigator["productSub"] = '20030107';
navigator["userActivation"] = new UserActivation();
navigator["userAgent"] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36';
navigator["vendor"] = 'Google Inc.';
navigator["vendorSub"] = '';
navigator["webkitPersistentStorage"] = new DeprecatedStorageQuota();
navigator["webkitTemporaryStorage"] = new DeprecatedStorageQuota();

screen = {}
function ScreenOrientation(){}
screen["availHeight"] = 1040
screen["availLeft"] = 0
screen["availTop"] = 0
screen["availWidth"] = 1920
screen["colorDepth"] = 24
screen["height"] = 1080
screen["orientation"] = new ScreenOrientation();
screen["pixelDepth"] = 24
screen["width"] = 1920;

function DOMStringList(){}
document = {};
Object.defineProperty(globalThis, 'document', {
  configurable: false,  // 不可删除
  writable: false  // 不可修改
})
document["location"] = {};
document["location"]["ancestorOrigins"] = new DOMStringList();
document["location"]["hash"] = ''
document["location"]["host"] = 'match.yuanrenxue.cn'
document["location"]["hostname"] = 'match.yuanrenxue.cn'
document["location"]["href"] = 'https://match.yuanrenxue.cn/match/14'
document["location"]["origin"] = 'https://match.yuanrenxue.cn'
document["location"]["pathname"] = '/match/14'
document["location"]["port"] = ''
document["location"]["protocol"] = 'https:'
document["location"]["search"] = ''

document["location"]["assign"] = function assign(){}
document["location"]["assign"].toString = function (){return 'function assign() { [native code] }'}

document["location"]["reload"] = function reload(){}
document["location"]["reload"].toString = function (){return 'function reload() { [native code] }'}

document["location"]["replace"] = function replace(){}
document["location"]["replace"].toString = function (){return 'function replace() { [native code] }'}

document["location"]["toString"] = function toString(){}
document["location"]["toString"].toString = function (){return 'function toString() { [native code] }'}

document["location"]["valueOf"] =  function valueOf(){}
document["location"]["valueOf"].toString = function (){return 'function valueOf() { [native code] }'}

$ = {
  'ajax': function() {
    // 替换成还原好的 m的代码
  }
}

// m.js 代码

for(let i=1; i<=// 页码; i++){
    sp()
}
_log(document.cookie)

页面执行流程

第一次请求 m.js --> m --> 数据接口
在这里插入图片描述
后续请求 m --> 数据接口
在这里插入图片描述

python 代码

替换 m.js

首先请求 m.js 代码,替换到 js模板代码内

def get_mJs():
    url = 'https://match.yuanrenxue.cn/static/match/match14/m.js'
    response = requests.get(url, headers=headers, cookies=cookies)
    with open('14.js', mode='r', encoding='utf-8') as f:
        js_demo = f.read()
    js_demo = js_demo.replace('// m.js 代码', response.text)
    return js_demo

替换 m 接口代码

请求接口前都会请求 m 接口的代码(设置 window 的 v12 v142 属性值 后再给 cookie m字段赋值

def get_m():
    url = 'https://match.yuanrenxue.cn/api/match/14/m'
    response = requests.get(url, headers=headers, cookies=cookies)
    return response.text

请求接口前会先设置 cookie m的字段
mz 字段可以写死,同一台电脑的环境值就是固定的

def get_cookie(js_demo, page_):
    js_demo = js_demo.replace('// 替换成还原好的 m的代码', get_m())
    js_demo = js_demo.replace('// 页码', str(page_))
    with open('new_14.js', mode='w', encoding='utf-8') as f:
        f.write(js_demo)
    output = subprocess.check_output("node new_14.js")
    return output.strip().split('=')[1].split(';')[0]

完整的 python 代码

import subprocess
import requests

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 = {
    'mz': '你浏览器生成的 mz 值,是可以固定的',
    "sessionid": "你的SessionId",
}


def get_mJs():
    url = 'https://match.yuanrenxue.cn/static/match/match14/m.js'
    response = requests.get(url, headers=headers, cookies=cookies)
    with open('14.js', mode='r', encoding='utf-8') as f:
        js_demo = f.read()
    js_demo = js_demo.replace('// m.js 代码', response.text)
    return js_demo


def get_m():
    url = 'https://match.yuanrenxue.cn/api/match/14/m'
    response = requests.get(url, headers=headers, cookies=cookies)
    return response.text


def get_cookie(js_demo, page_):
    js_demo = js_demo.replace('// 替换成还原好的 m的代码', get_m())
    js_demo = js_demo.replace('// 页码', str(page_))
    with open('new_14.js', mode='w', encoding='utf-8') as f:
        f.write(js_demo)
    output = subprocess.check_output("node new_14.js")
    return output.strip().split('=')[1].split(';')[0]


def get_match14(js_demo, page_):
    url = "https://match.yuanrenxue.cn/api/match/14"
    params = {
        'page': f'{page_}'
    }

    cookies['m'] = get_cookie(js_demo, page_)[0:-1] + f'{page_}'
    print(cookies['m'])
    response = requests.get(url, headers=headers, cookies=cookies, params=params)
    print(response.json())
    return response.json()['data']


if __name__ == '__main__':
    js_code = get_mJs()  # m.js 文件
    nums = 0
    for page in range(1, 6):
        nums_list = get_match14(js_code, page)
        for num in nums_list:
            nums += num['value']
        print('page: ', page, 'nums: ', nums)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2095604.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java并发编程面试必备:如何创建线程池、线程池拒绝策略

一、线程池 1. 线程池使用 1.1 如何配置线程池大小 如何配置线程池大小要看业务系统执行的任务更多的是计算密集型任务&#xff0c;还是I/O密集型任务。大家可以从这两个方面来回答面试官。 &#xff08;1&#xff09;如果是计算密集型任务&#xff0c;通常情况下&#xff…

模型 ACT心理灵活六边形

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。接纳现实&#xff0c;灵活行动&#xff0c;追求价值。 1 ACT心理灵活六边形的应用 1.1 应对工作压力 背景&#xff1a; 在高压的工作环境中&#xff0c;员工经常面临巨大的工作压力&#xff0c;这可…

在VScode中使用Git将本地已有文件夹提交到Github仓库以便于使用版本控制进行项目开发

前置软件 VScode、Git。 Linux系统中安装Git工具请自行百度。可以通过git --version查看对应Git版本号。 Github创建空白仓库 一定要注意创建空白仓库&#xff0c;不要包含任何文件&#xff0c;包括Readme.md文件也不能有。 上面的仓库名&#xff08;Repository name&#xff…

Kaggle克隆github项目+文件操作+Kaggle常见操作问题解决方案——一文搞定,以openpose姿态估计项目为例

文章目录 前言一、Kaggle克隆仓库1、克隆项目2、查看目录 二、安装依赖三、文件的上传、复制、转移操作1.上传.pth文件到input目录2、将权重文件从input目录转移到工作目录 三、修改工作目录里的文件内容1、修改demo_camera.py内容 四、运行&#xff01; 前言 想跑一些深度学习…

【网络安全】条件竞争绕过电子邮件验证

未经许可,不得转载。 文章目录 正文正文 目标:xxx.com 使用电子邮件注册该网站并登录。接着,进入帐户设置,进入更改电子邮件功能: 请求包如下: 接着,发送两个相同的请求包到repeater,第一个中添加攻击者邮件: 第二个中添加正常的邮件: 创建组,以便能够同时发送两个…

手把手教你如果安装激活CleanMyMac X 4.15.6中文破解版

CleanMyMac X 4.15.6中文破解版可以为Mac腾出空间&#xff0c;软件已经更新到CleanMyMac X 4.15.6中文版支持最新版Macos 10.14系统。CleanMyMac X 4.15.6中文破解版具有一系列巧妙的新功能&#xff0c;可让您安全&#xff0c;智能地扫描和清理整个系统&#xff0c;删除大量未使…

NeRF: Representing Scenes asNeural Radiance Fields for View Synthesis 论文解读

目录 一、导言 二、NeRF 1、渲染和反渲染 2、NeRF的基本原理 3、采样点 4、位置编码 5、NeRF网络结构 6、体渲染 三、分层采样 1、均匀采样 2、基于σ的采样 四、损失函数 一、导言 该论文来自于ECCV2020&#xff0c;主要提到一种NeRF的方法来合成复杂场景下的新视…

创建 AD9361 的 vivado 工程,纯FPGA配置,不使用ARM程序

前言 AD9361 的配置程序&#xff0c;如果使用官方的&#xff0c;就必须用ps进行配置&#xff0c;复杂不好使&#xff0c;如果直接使用FPGA配置&#xff0c;将会特别的简单。 配置软件 创建一份完整的寄存器配置表 //*******************************************************…

续:docker 仓库数据传输加密

上一个实验&#xff1a;非加密的形式在企业中是不被允许的。 示例&#xff1a;【为Registry 提供加密传输】 因为传输也是https&#xff0c;所以与ssh一样的加密。 ## 这种方式就不用写这个了。 [rootdocker ~]# cat /etc/docker/daemon.json #{ # "insecure-registrie…

GoodSync Business - 企业级服务器同步与备份工具

现在越来越多公司会搭建服务器&#xff0c;或自建文件共享中心。那么如何才能实现对这些终端的高效管理、安全备份&#xff0c;以保障企业数据的安全呢&#xff1f; GoodSync Business 就是一款企业服务器同步与备份工具&#xff0c;适用于 Win / Mac 工作站&#xff0c;以及 …

C语言程序设计

日落有个小商店&#xff0c;贩卖着橘黄色的温柔。 7.关系操作符 > > < < ! (用于测试“不相等”) &#xff08;用于测试“相等”&#xff0c;但是不是所有的对象都可以用该符号来比较相不相等&#xff09; eg. int main ( ) { if ("abc"&q…

【AI大模型】基于docker部署向量数据库Milvus和可视化工具Attu详解步骤

&#x1f680; 作者 &#xff1a;“大数据小禅” &#x1f680; 文章简介 &#xff1a;本专栏后续将持续更新大模型相关文章&#xff0c;从开发到微调到应用&#xff0c;需要下载好的模型包可私。 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 目…

【王树森】Few-Shot Learning (2/3): Siamese Network 孪生网络(个人向笔记)

Learning Pairwise Similarity Scores Training Data 训练集有很多个类别的图片&#xff0c;每个类别的图片都有标注 Positive Sample&#xff1a;我们需要正样本来告诉神经网路什么东西是同一类 Negative Sample&#xff1a;负样本可以告诉神经网路事物之间的区别 我们用…

【笔记】数据结构04

文章目录 稀疏矩阵压缩存储三元组表示稀疏矩阵转三元组 栈的应用前缀表达式前缀表达式求值 中缀表达式后缀表达式 稀疏矩阵内容参考 强连通文章 稀疏矩阵压缩存储三元组表示 将非零元素所在的行、列以及它的值构成一个三元组&#xff08;i,j,v&#xff09;&#xff0c;然后再…

推荐 3 个好用的桌面管理工具,实用强大,不要错过

BitDock BitDock是一款运行在Windows系统中的桌面停靠栏工具&#xff0c;也被称为比特工具栏。这款软件模仿了Mac系统的Dock栏设计&#xff0c;旨在为用户提供一个简洁、高效且极具美感的桌面环境。BitDock不仅具有个性化的外观&#xff0c;还内置了多种实用功能&#xff0c;如…

Java后端 - 常见BUG及其处理策略(持续更新中~)

Bug 收集与总结 本文记录的是 本人SpringBoot 后端项目使用和运行代码时所遇到的各种问题&#xff0c;全部都已解决&#xff0c;欢迎在评论区补充你遇到的 Bug 哦&#xff01;仅以本文记录学习社区项目时&#xff0c;所遇到的奇奇怪怪的 bug&#xff0c;以及一些很愚蠢的错误&…

从马斯洛需求层次理论谈职场激励

马斯洛需求层次理论是一个广为人知的心理学概念&#xff0c;它是由美国心理学家亚伯拉罕马斯洛&#xff08;Abraham Maslow&#xff09;于1943年提出&#xff0c;常被描述为一个5层的金字塔模型&#xff0c;反映了人类不同需求层级和依赖关系。马斯洛认为人类只有在低层级需求得…

在 VS Code 中使用 Git 源代码管理【Mac 版】

文章目录 一、Git 使用文档二、使用示例1、复制远程仓库地址2、查看当前所在的分支2.1、界面查看2.2、终端查看 3、修改/新增文件4、显示增改的详细内容5、添加暂存区6、查看/取消暂存的更改7、提交本地代码库8、待提交文件9、推送到远程仓库10、验证11、查看推送记录11.1、关于…

六. 部署分类器-trt-engine-explorer

目录 前言0. 简述1. 案例运行2. 补充说明3. engine分析结语下载链接参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习课程第六章—部署分类器&#xff0c;一起来学习 trt-engine…

Linux日志-secure日志

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux进阶部分又分了很多小的部分,我们刚讲完了Linux基础软件&#xff0c;下面是Linux日志。Linux 系统中的日志是记录系统活…