猿人学第十四题(备而后动-勿使有变)

前言最近学习了一下ast,使用ast还原了m文件,分享一下并记录一下

 

 

 里面包含了两个重要参数window['v14']和window['v142'],这两个参数在生成cookie中的m时要用

m文件代码里有格式化检测,定时器,直接运行不能获取window['v14']和window['v142'],刚开始在做这道题的时候我是用re正则匹配要用的js代码,分别是大数组,自执行还原大数组,解密函数,和两个window参数,贴上一张示例代码,下面代码,要补个window和一个调用函数

 之前用正则匹配时代码

response = session.get('https://match.yuanrenxue.cn/api/match/14/m', cookies=cookies, headers=headers)
res=response.text
'''re正则表达式'''
#大数组
big_array=re.findall(r'(var .*?);',res)[0]+';'
#函数一
def_1=re.findall('(\(function.*?\)\));var \$',res)[0]
res=res.replace(big_array,'').replace(def_1,'').replace(';;','')
#函数二
def_2=re.findall(r'(var .*?);var \$',res)[0]
v14=re.findall('(window\[.*\]=.*?;)window',res)[0].split(';')[0]+';'
res=res.replace(v14,'')
v142=re.findall('(window\[.*\]=.*?;)',res)[0].split(';')[0]+';'
with open('m2.js','w',encoding='utf-8')as fo:
    fo.write('window=global;\n'+big_array+'\n'+def_1+'\n'+def_2+'\n'+v14+'\n'+v142+'\n')
    fo.write('function get_v(){return {v14:window.v14,v142:window.v142}}'+'\n'+'module.exports={get_v}')
js_code=execjs.compile(open('m2.js','r',encoding='utf-8').read()).call('get_v')

这样就能获取window['v14']和window['v142']

ast还原

const parser = require("@babel/parser");
const {default: generate} = require("@babel/generator");
function get_v(code){
    let window = {};
    const ast = parser.parse(code)
    var sojson=[]
    var big_array=ast.program.body[0];
    var zizhixing=ast.program.body[1];
    var jiemi=ast.program.body[2];
    sojson.push(big_array,zizhixing,jiemi)
    for(var ii=0;ii<ast.program.body.length;ii++){
        try{
            if (ast.program.body[ii].expression.left.object.name=="window"){
                sojson.push(ast.program.body[ii])
            }
        }catch (error){}

    }
    const generatedCode = sojson.map((node) => generate(node,{compact: "preserve"}).code).join("\n");
    eval(generatedCode); // 执行代码
    return window
}

这样也能获取window['v14']和window['v142'],code传入的是response.text

用了这两种方法去获取参数后我发现ast相较于re正则简单

接下m参数的生成就不仔细讲了主要是为了分享ast还原,网上也有很多教程

最后分享一下最终版,里面有些算法是从vjstool中扣出来,最后还原成就剩两行代码

const parser = require("@babel/parser");
const generator = require("@babel/generator").default
const traverse = require("@babel/traverse").default
const types = require("@babel/types")
const fs = require("fs");
function get_sojson_enc(ast) {
    var first_idx = 0
    for (var i = 0; i < ast.program.body.length; i++) {
        if (ast.program.body[i].type != 'EmptyStatement') {
            first_idx = i;
            break
        }
    }
    var decrypt_code = ast.program.body.slice(first_idx, first_idx + 3)
    var rest_code = ast.program.body.slice(first_idx + 3)
    ast.program.body = decrypt_code
    var {code} = generator(ast, {
        compact: true
    })
    global_code = code
    decryptStr = decrypt_code[2].declarations[0].id.name
    ast.program.body = rest_code
    return ast
}
function pas_sojson_enc(ast) {
    eval(global_code)
    traverse(ast, {
        CallExpression: funToStr,
        StringLiteral: delExtra,
        NumericLiteral: delExtra,
    })
    return ast;
    function funToStr(path) {
        var node = path.node;
        if (!types.isIdentifier(node.callee, {
            name: decryptStr
        }))
            return;
        let value = eval(path.toString())
        // console.log("还原前:" + path.toString(), "还原后:" + value);
        path.replaceWith(types.valueToNode(value));
    }
    function delExtra(path) {
        delete path.node.extra;
    }
}
function calcBinary(path) {
    var tps = ['StringLiteral', 'BooleanLiteral', 'NumericLiteral']
    var nod = path.node
    function judge(e) {
        return (tps.indexOf(e.type) != -1) || (e.type == 'UnaryExpression' && tps.indexOf(e.argument.type) != -1)
    }
    function make_rep(e) {
        if (typeof e == 'number') {
            return t.NumericLiteral(e)
        }
        if (typeof e == 'string') {
            return types.StringLiteral(e)
        }
        if (typeof e == 'boolean') {
            return types.BooleanLiteral(e)
        }
        throw Error('unknown type' + typeof e)
    }
    // && and  || or
    if (judge(nod.left) && judge(nod.right)) {
        path.replaceWith(make_rep(eval(path + '')))
    }
}
function muti_process_sojsondefusion(jscode) {
    var ast = parser.parse(jscode);

    if (ast.program.body.length == 1) {
        ast.program.body = ast.program.body[0].expression.callee.body.body
    }

    // ob 解混淆处理部分
    ast = get_sojson_enc(ast)
    ast = pas_sojson_enc(ast)
    traverse(ast, {
        BinaryExpression: {
            exit: calcBinary
        }
    })
    var {code} = generator(ast, {
        jsescOption: {
            minimal: true,
        }
    });
    return code;
}
function get_v(code){
    let window = {};
    const ast = parser.parse(code)
    var sojson=[]
    var big_array=ast.program.body[0];
    var zizhixing=ast.program.body[1];
    var jiemi=ast.program.body[2];
    sojson.push(big_array,zizhixing,jiemi)
    for(var ii=0;ii<ast.program.body.length;ii++){
        try{
            if (ast.program.body[ii].expression.left.object.name=="window"){
                sojson.push(ast.program.body[ii])
            }
        }catch (error){}

    }
    const generatedCode = sojson.map((node) => generator(node,{compact: "preserve"}).code).join("\n");
    eval(muti_process_sojsondefusion(generatedCode)); // 执行代码
    console.log(muti_process_sojsondefusion(generatedCode))
    return window
}
const code =fs.readFileSync("m.js", {encoding: "utf-8"});
get_v(code)

结果

 

最后到这也差不多了

如有侵权请联系我及时删除,谢谢

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值