前言最近学习了一下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)
结果
最后到这也差不多了