AST交互-if语句转switch语句

阅读时间:全文 621 字,预估用时 4 分钟
创作日期:2022-08-14
文章标签:
 
BEGIN

这两年前端代码加密进化很大,为了在逆向过程中不那么累,我们需要使用babel修改网站源码,改成我们调试不那么累的代码,如将if语句代码改成switch语句代码。

我们找到网站实际代码如下:

while (1) {
  _$a9 = _$kI[_$iW++];
  if (_$a9 < 12) {
    if (_$a9 < 4) {
      if (_$a9 === 0) {
        _$gP = window,
        _$$i = String,
        _$$_ = Array,
        _$_q = document,
        _$b8 = Math.random,
        _$g$ = Math.round,
        _$_W = Date;
      } else if (_$a9 === 1) {
        _$_s.lcd = _$ht;
      } else if (_$a9 === 2) {
        _$aW = !_$_W;
      } else {
        _$_s = _$gP['$_ts'];
      }
    } else if (_$a9 < 8) {
      if (_$a9 === 4) {
        _$_s = _$gP['$_ts'] = {};
      } else if (_$a9 === 5) {
        _$f2(69);
      } else if (_$a9 === 6) {
        _$iW += 2;
      } else {
        _$_0 = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
      }
    } else {
      if (_$a9 === 8) {
        !_$aW ? _$iW += 0 : 0;
      } else if (_$a9 === 9) {
        return;
      } else if (_$a9 === 10) {
        !_$aW ? _$iW += 2 : 0;
      } else {
        _$aW = _$_s;
      }
    }
  } else
  ;
}

处理后的代码如下:

while (1) {
  _$a9 = _$kI[_$iW++];
  switch (_$a9) {
    case 0:
      _$gP = window, _$$i = String, _$$_ = Array, _$_q = document, _$b8 = Math.random, _$g$ = Math.round, _$_W = Date;
      break;
    case 1:
      _$_s.lcd = _$ht;
      break;
    case 2:
      _$aW = !_$_W;
      break;
    case 3:
      _$_s = _$gP['$_ts'];
      break;
    case 4:
      _$_s = _$gP['$_ts'] = {};
      break;
    case 5:
      _$f2(69);
      break;
    case 6:
      _$iW += 2;
      break;
    case 7:
      _$_0 = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
      break;
    case 8:
      !_$aW ? _$iW += 0 : 0;
      break;
    case 9:
      return;
    case 10:
      !_$aW ? _$iW += 2 : 0;
      break;
    case 11:
      _$aW = _$_s;
      break;
  }
}

这里贴上处理代码(这段代码由博主个人原创,转载请注明出处)

const fs = require('fs');
const parser = require("@babel/parser");
const generate = require("@babel/generator").default
const traverse = require("@babel/traverse").default
const t = require('@babel/types');

const code = getCode()
const ast = parser.parse(code, { allowReturnOutsideFunction: true })

function valueHandle(operator, value) {
  switch(operator) {
    case '<':
      return value
    case '==':
    case '===':
      return value + 1
  }
}

function getIfTestValue(test) {
  if (!test) return false
  const { operator, left, right } = test
  if (!['<', '==', '==='].includes(operator)) return false
  if (!t.isIdentifier(left)) return false
  if (!t.isNumericLiteral(right)) return false
  return { name: left.name, value: valueHandle(operator, right.value) }
}

function getNode(node) {
  if (t.isIfStatement(node)) return [node]
  if (t.isBlockStatement(node)) return node.body
  console.error(`未知类型请检查: ${node.type}`)
  return [node]
}

function getIfNode(node, ans=[], opt = {}) {
  const testValue = getIfTestValue(node?.test)
  if (testValue === false) return
  if (!opt.name) { Object.assign(opt, testValue) }
  if (testValue.name !== opt.name) return
  ['alternate', 'consequent'].forEach((key, idx) => {
    const nextNode = getNode(node[key])
    ans[testValue.value - idx] = nextNode
    nextNode?.forEach(item => getIfNode(item, ans, opt))
  })
  return [opt.name, ans.filter(Boolean)]
}

const visitor = {
  IfStatement(path) {
    const [key, cases] = getIfNode(path.node) || []
    if (!key || cases.length <= 6) return
    const newNode = t.switchStatement(
      t.identifier(key),
      cases.map((mycase, idx) => {
        const otherCode = mycase.some(item => t.isReturnStatement(item)) ? [] : [t.breakStatement()]
        return t.switchCase(t.numericLiteral(idx), [ ...mycase, ...otherCode ])
      })
    )
    path.replaceInline(newNode)
    path.skip()
  }
}
traverse(ast, visitor)
const result = generate(ast, { minified: false, concise: false, compact: false })
console.log(result.code)
FINISH

随机文章
人生倒计时
default