ast.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. const fs = require('fs')
  2. const parser = require('@babel/parser') // 解析 JavaScript 代码
  3. const traverse = require('@babel/traverse').default // 遍历 AST
  4. const generator = require('@babel/generator').default // 生成代码
  5. const t = require('@babel/types')
  6. // 定义文件路径
  7. const input_js = './encode.js'
  8. const output_js = './decode.js'
  9. // 读取文件内容并解析成 AST
  10. const js_code = fs.readFileSync(input_js, {encoding: 'utf-8'})
  11. const ast = parser.parse(js_code) // 解析代码为 AST
  12. // 字面量访问器 -------------------------------
  13. const varPool = new Map(); // 存储(第一个函数)计算出的变量值
  14. const varPool2 = new Map(); // 存储(第二个函数)计算出的变量值
  15. const visitor_literal = {
  16. // 第一阶段:处理 QxN 函数
  17. FunctionDeclaration(path) {
  18. let {id} = path.node
  19. let bodyPath = path.get('body')
  20. if (!t.isIdentifier(id, {name: 'QxN'})) return;
  21. bodyPath.traverse({
  22. AssignmentExpression(path) {
  23. const rightPath = path.get('right'); // 获取右侧表达式的路径(左边是变量名)
  24. const var_name = path.node.left.name // 获取左侧的变量名
  25. // evaluate() 方法是路径对象(Path)提供的方法,而非节点(Node)本身的方法。你需要通过路径来调用该方法
  26. const evaluated = rightPath.evaluate(); // 调用evaluate()
  27. if (evaluated.confident) {
  28. let value = evaluated.value
  29. varPool.set(var_name, value); // 存储变量值
  30. console.log(rightPath.toString(), '=>', value); // 输出确定的值
  31. rightPath.replaceWith(t.valueToNode(value)) // 替换为字面量
  32. } else {
  33. console.log('无法静态求值');
  34. }
  35. }
  36. })
  37. },
  38. Program: {
  39. exit(path) {
  40. // 第二阶段:在所有节点处理完成后处理 ShN 函数
  41. path.traverse({
  42. FunctionDeclaration(path) {
  43. let {id} = path.node
  44. let bodyPath = path.get('body')
  45. if (!t.isIdentifier(id, {name: 'ShN'})) return;
  46. bodyPath.traverse({
  47. AssignmentExpression(path) {
  48. const rightPath = path.get('right');
  49. const var_name = path.node.left.name // 获取左侧的变量名
  50. // evaluate() 方法是路径对象(Path)提供的方法,而非节点(Node)本身的方法。你需要通过路径来调用该方法
  51. // 继续遍历rightPath下的节点,替换已知变量引用为字面量
  52. rightPath.traverse({
  53. // subPath表示子路径,定位子路径下的标识符
  54. Identifier(subPath) {
  55. if (varPool.has(subPath.node.name)) {
  56. subPath.replaceWith(
  57. t.valueToNode(varPool.get(subPath.node.name))
  58. )
  59. }
  60. }
  61. });
  62. // 再次尝试计算表达式
  63. const evaluated = rightPath.evaluate();
  64. if (evaluated.confident) {
  65. let value = evaluated.value
  66. varPool2.set(var_name, value)
  67. console.log(rightPath.toString(), '=>', evaluated.value); // 输出确定的值
  68. rightPath.replaceWith(t.valueToNode(evaluated.value));
  69. }
  70. }
  71. })
  72. }
  73. });
  74. }
  75. }
  76. };
  77. // 定位 return j2.call(this, xL);
  78. const visitor_ = {
  79. CallExpression(path) {
  80. let {callee} = path.node
  81. if (!t.isFunctionExpression(callee)) return;
  82. path.traverse({
  83. ReturnStatement(path) {
  84. let {argument} = path.node
  85. if (!t.isCallExpression(argument)) return;
  86. let {callee: {property,}, arguments: args} = argument
  87. if (args.length !== 2 || !t.isIdentifier(property, {name: 'call'})) return;
  88. console.log(path.toString())
  89. }
  90. })
  91. },
  92. }
  93. // 控制流平坦化访问器 -------------------------------
  94. function return_num(varStr) {
  95. // 根据变量字符串,返回对应变量值
  96. if (varPool.has(varStr) || varPool2.has(varStr)) {
  97. return varPool[varStr] || varPool2[varStr]
  98. }
  99. console.warn(`${varStr}未找到`)
  100. }
  101. const visitor_for = {
  102. ForStatement(path) {
  103. const {test, body} = path.node; // 解构循环条件和循环体
  104. // let {} = test // 从循环条件取出具体值,在变量值map中查找,方便下面循环处理
  105. // 初始状态变量值
  106. let init_name = 'HO'; // 状态变量名
  107. let init_value = 3; // 初始状态值
  108. const switch_body = body.body[0]; // 提取循环体内的switch语句
  109. // 验证是否为 Switch 语句,否则终止处理
  110. if (!t.isSwitchStatement(switch_body)) return;
  111. const {discriminant, cases} = switch_body; // 解构 Switch 的条件和分支列表
  112. // 验证 Switch 条件是否为指定状态变量
  113. if (!t.isIdentifier(discriminant, {name: init_name})) return;
  114. const ret_body = []; // 存储最终生成的代码块集合
  115. let end_flag = false; // 终止循环处理标志
  116. while (init_value !== 662) { // 循环处理所有状态分支
  117. if (end_flag) break; // 检测终止条件
  118. for (const each_case of cases) { // 遍历 Switch 的所有 case 分支
  119. const {test, consequent} = each_case; // 从case分支中取出条件和对应代码块
  120. if (init_value !== test.name) continue; // 跳过非当前状态的 case 分支
  121. }
  122. }
  123. }
  124. }
  125. const visitor_while = {
  126. VariableDeclarator(path) {
  127. let {id, init} = path.node
  128. if (!t.isIdentifier(id, {name: 'j2'})) return
  129. path.traverse(visitor_for)
  130. // console.log(id.name)
  131. }
  132. }
  133. traverse(ast, visitor_literal); // 还原初始化2个变量赋值函数
  134. // traverse(ast, visitor_);
  135. // traverse(ast, visitor_while);
  136. console.log(varPool2)
  137. // 使用 Babel 生成新的代码
  138. let {code} = generator(ast)
  139. // 将生成的代码写入指定的文件
  140. // fs.writeFile(output_js, code, (err) => {
  141. // })