const fs = require('fs') const parser = require('@babel/parser') // 解析 JavaScript 代码 const traverse = require('@babel/traverse').default // 遍历 AST const generator = require('@babel/generator').default // 生成代码 const t = require('@babel/types') // 定义文件路径 const input_js = './encode.js' const output_js = './decode.js' // 读取文件内容并解析成 AST const js_code = fs.readFileSync(input_js, {encoding: 'utf-8'}) const ast = parser.parse(js_code) // 解析代码为 AST // 字面量访问器 ------------------------------- const varPool = new Map(); // 存储(第一个函数)计算出的变量值 const varPool2 = new Map(); // 存储(第二个函数)计算出的变量值 const visitor_literal = { // 第一阶段:处理 QxN 函数 FunctionDeclaration(path) { let {id} = path.node let bodyPath = path.get('body') if (!t.isIdentifier(id, {name: 'QxN'})) return; bodyPath.traverse({ AssignmentExpression(path) { const rightPath = path.get('right'); // 获取右侧表达式的路径(左边是变量名) const var_name = path.node.left.name // 获取左侧的变量名 // evaluate() 方法是路径对象(Path)提供的方法,而非节点(Node)本身的方法。你需要通过路径来调用该方法 const evaluated = rightPath.evaluate(); // 调用evaluate() if (evaluated.confident) { let value = evaluated.value varPool.set(var_name, value); // 存储变量值 console.log(rightPath.toString(), '=>', value); // 输出确定的值 rightPath.replaceWith(t.valueToNode(value)) // 替换为字面量 } else { console.log('无法静态求值'); } } }) }, Program: { exit(path) { // 第二阶段:在所有节点处理完成后处理 ShN 函数 path.traverse({ FunctionDeclaration(path) { let {id} = path.node let bodyPath = path.get('body') if (!t.isIdentifier(id, {name: 'ShN'})) return; bodyPath.traverse({ AssignmentExpression(path) { const rightPath = path.get('right'); const var_name = path.node.left.name // 获取左侧的变量名 // evaluate() 方法是路径对象(Path)提供的方法,而非节点(Node)本身的方法。你需要通过路径来调用该方法 // 继续遍历rightPath下的节点,替换已知变量引用为字面量 rightPath.traverse({ // subPath表示子路径,定位子路径下的标识符 Identifier(subPath) { if (varPool.has(subPath.node.name)) { subPath.replaceWith( t.valueToNode(varPool.get(subPath.node.name)) ) } } }); // 再次尝试计算表达式 const evaluated = rightPath.evaluate(); if (evaluated.confident) { let value = evaluated.value varPool2.set(var_name, value) console.log(rightPath.toString(), '=>', evaluated.value); // 输出确定的值 rightPath.replaceWith(t.valueToNode(evaluated.value)); } } }) } }); } } }; // 定位 return j2.call(this, xL); const visitor_ = { CallExpression(path) { let {callee} = path.node if (!t.isFunctionExpression(callee)) return; path.traverse({ ReturnStatement(path) { let {argument} = path.node if (!t.isCallExpression(argument)) return; let {callee: {property,}, arguments: args} = argument if (args.length !== 2 || !t.isIdentifier(property, {name: 'call'})) return; console.log(path.toString()) } }) }, } // 控制流平坦化访问器 ------------------------------- function return_num(varStr) { // 根据变量字符串,返回对应变量值 if (varPool.has(varStr) || varPool2.has(varStr)) { return varPool[varStr] || varPool2[varStr] } console.warn(`${varStr}未找到`) } const visitor_for = { ForStatement(path) { const {test, body} = path.node; // 解构循环条件和循环体 // let {} = test // 从循环条件取出具体值,在变量值map中查找,方便下面循环处理 // 初始状态变量值 let init_name = 'HO'; // 状态变量名 let init_value = 3; // 初始状态值 const switch_body = body.body[0]; // 提取循环体内的switch语句 // 验证是否为 Switch 语句,否则终止处理 if (!t.isSwitchStatement(switch_body)) return; const {discriminant, cases} = switch_body; // 解构 Switch 的条件和分支列表 // 验证 Switch 条件是否为指定状态变量 if (!t.isIdentifier(discriminant, {name: init_name})) return; const ret_body = []; // 存储最终生成的代码块集合 let end_flag = false; // 终止循环处理标志 while (init_value !== 662) { // 循环处理所有状态分支 if (end_flag) break; // 检测终止条件 for (const each_case of cases) { // 遍历 Switch 的所有 case 分支 const {test, consequent} = each_case; // 从case分支中取出条件和对应代码块 if (init_value !== test.name) continue; // 跳过非当前状态的 case 分支 } } } } const visitor_while = { VariableDeclarator(path) { let {id, init} = path.node if (!t.isIdentifier(id, {name: 'j2'})) return path.traverse(visitor_for) // console.log(id.name) } } traverse(ast, visitor_literal); // 还原初始化2个变量赋值函数 // traverse(ast, visitor_); // traverse(ast, visitor_while); console.log(varPool2) // 使用 Babel 生成新的代码 let {code} = generator(ast) // 将生成的代码写入指定的文件 // fs.writeFile(output_js, code, (err) => { // })