这是一个瑞数5代解混淆的案例,本案例未考虑通用性,只是专项学习性的插件。这里只是解混淆了外层代码,并不是解混淆内部生成的代码。
If节点转Switch节点
例子
这里将if节点转换成switch,当然只是针对这段代码而写的。
这里是为switch合并做预处理,只针对最内层case,外层case并不在处理范围。
if (_$nE < 4) {
if (_$nE < 1) {
_$hk = window,
_$NB = String,
_$OA = Array,
_$Qd = document,
_$uO = Date;
} else if (_$nE < 2) {
_$bx = _$hk['$_ts'] = {};
} else if (_$nE < 3) {
_$bx = _$hk['$_ts'];
} else {
_$_l = !_$bx;
}
} else {
if (_$nE < 5) {
_$UX(0);
} else if (_$nE < 6) {
if (!_$_l)
_$nI += 1;
} else if (_$nE < 7) {
_$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
} else {
return;
}
}
----------------------------------------------
switch (_$nE) {
case 3:
switch (_$nE) {
case 0:
_$hk = window, _$NB = String, _$OA = Array, _$Qd = document, _$uO = Date;
case 1:
_$bx = _$hk['$_ts'] = {};
case 2:
_$bx = _$hk['$_ts'];
case 3:
_$_l = !_$bx;
}
case 4:
switch (_$nE) {
case 4:
_$UX(0);
case 5:
if (!_$_l) _$nI += 1;
case 6:
_$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
case 7:
return;
}
}
插件
function ifToSwitchNode(path, pathStr = "test.left") {
function getNodes(path, list = []) {
if (!path.isIfStatement()) {
list.push({
type: "SwitchCase",
consequent: path.node.body,
test: types.valueToNode(list[list.length - 2].right.value)
})
return list;
}
items.forEach(n => {
let tmep = path.get(n);
list.push(tmep.node);
})
return getNodes(path.get("alternate"), list);
}
function reductionTest(test) {
switch (test.operator) {
case "<":
test = types.valueToNode(test.right.value - 1)
break;
case "===":
test = types.valueToNode(test.right.value)
break;
}
return test;
}
let items = ["test", "consequent"];
let nodes = getNodes(path);
let cases = [], count = Math.trunc(nodes.length / items.length);
if (nodes.length % 2) cases.push(nodes.pop());
for (let i = 0; i < count; i++) {
cases.push({
type: "SwitchCase",
consequent: nodes.pop().body,
test: reductionTest(nodes.pop())
})
}
return {
type: "SwitchStatement",
discriminant: path.get(pathStr).node,
cases: cases.reverse()
}
}
const ifToSwitch = {
IfStatement(path) {
let {node} = path;
let {alternate} = node;
if (alternate === null) return;
let newNode = ifToSwitchNode(path);
path.replaceInline(newNode)
}
}
switch合并
例子
这里将多维的switch合并为一维的。
switch (_$nE) {
case 3:
switch (_$nE) {
case 0:
_$hk = window, _$NB = String, _$OA = Array, _$Qd = document, _$uO = Date;
case 1:
_$bx = _$hk['$_ts'] = {};
case 2:
_$bx = _$hk['$_ts'];
case 3:
_$_l = !_$bx;
}
case 4:
switch (_$nE) {
case 4:
_$UX(0);
case 5:
if (!_$_l) _$nI += 1;
case 6:
_$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
case 7:
return;
}
}
----------------------------------------------
switch (_$nE) {
case 0:
_$hk = window, _$NB = String, _$OA = Array, _$Qd = document, _$uO = Date;
case 1:
_$bx = _$hk['$_ts'] = {};
case 2:
_$bx = _$hk['$_ts'];
case 3:
_$_l = !_$bx;
case 4:
_$UX(0);
case 5:
if (!_$_l) _$nI += 1;
case 6:
_$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
case 7:
return;
}
插件
function getCaseAll(cases, caseAll = []) {
if (!types.isSwitchStatement(cases[0].consequent[0])) return cases;
for (let i = 0; i < cases.length; i++) {
let caseNode = cases[i];
if (!types.isSwitchStatement(caseNode.consequent[0])) {
if (types.isSwitchStatement(cases[i - 1].consequent[0])) caseAll.push(caseNode);
break;
}
caseAll = caseAll.concat(getCaseAll(caseNode.consequent[0].cases));
}
return caseAll;
}
const mergeSwitch = {
SwitchStatement(path) {
if (path.parentPath.isSwitchCase()) return;
let nextPath = path.get("cases.0.consequent.0");
if (!types.isSwitchStatement(nextPath)) return;
path.node.cases = getCaseAll(path.node.cases);
}
}
缓存关键数据
插件
这里是为方便后续操作做准备。
/**
* 向上查询某类型的ParentPath
* @Param path
* @param type
* @returns {null|*}
*/
function findParentPath(path, type) {
while (!path.isProgram()) {
path = path.parentPath;
if (!path[`is${type}`]()) return path.parentPath;
}
}
/**
* 节点筛选器
* @param list [node/path...] 元素node或path都可
* @param filter 类型 array [str...] 类型列表
* @param filterMode 过滤器模式 默认false | false - 只输出配置的类型 true - 过滤(不输出)配置的类型
* @param isCode 默认true返回代码 false返回节点列表
* @returns {string|array} code/itemList
*/
function nodeFilter(list, filter = [true], filterMode = false, isCode = true) {
let code = "", itemList = [];
if (!list.length) return "";
let isPath = typeof list[0].isReturnStatement === "function";
if (isPath) list = list.reverse();
list.forEach(node => {
if (isPath) node = node.node;
if (filter[0] === true ||
(!filterMode === filter.includes(node.type))) {
isCode ? code += `${generator(node).code}\n` : itemList.push(node);
}
})
return isCode ? code : itemList;
}
/***
* 获取需要用到的对象名和节点
* @param path
* @param resultPath
*/
function getFuncInfo(path, resultPath) {
let info = Object();
info["switchPath"] = path.get('body.body.1');
let expressionNode = path.node.body.body[0];
let arrayName = expressionNode.expression.right.object.name;
let largeArrayInit = path.scope.getBinding(arrayName).path.node.init;
let largeArrayName = largeArrayInit.object.name;
let largeArrayIndex = largeArrayInit.property.value;
info["array"] = eval(generator(path.scope.getBinding(largeArrayName).path.node.init).code)[largeArrayIndex];
info["indexName"] = expressionNode.expression.right.property.argument.name;
info["variable"] = nodeFilter(path.getAllPrevSiblings(), ['VariableDeclaration', 'FunctionDeclaration'], false, false);
info["path"] = resultPath;
return info;
}
let funcInfo = {};
/***
* 缓存关键数据
* @type {{WhileStatement(*): void}}
*/
const cacheCriticalData = {
WhileStatement(path) {
let resultPath = findParentPath(path, "FunctionDeclaration");
if (!resultPath) return;
let funcName = "main";
if (!resultPath.isFunctionExpression()) {
funcName = resultPath.node.id.name;
}
// 缓存path和关键变量名以便后续使用
funcInfo[funcName] = getFuncInfo(path, resultPath);
}
}
合并调用信息前的准备
插件
let cache = {};
const mergeCallInfo = {
CallExpression(path) {
let name = path.node.callee.name;
if (Object.keys(funcInfo).includes(name)) {
let now = funcInfo[name];
const {cases} = now.switchPath.node;
let value = path.node.arguments[0].value;
let replaceBody = [];
let callCode = path.toString();
if (Object.keys(cache).includes(callCode)) return;
let constantViolations = (() => {
let list = [];
now.path.scope.getBinding(now.indexName).constantViolations.forEach(p => list.push(p.node.start))
return list;
})();
for (let i = value; i < now.array.length; i++) {
let index = now.array[i];
let case_body = cases[index].consequent[0];
if (types.isIfStatement(case_body)) case_body.start = case_body.consequent.start;
if (case_body && constantViolations.includes(case_body.start)) {
if (types.isIfStatement(case_body)) {
let node = JSON.parse(JSON.stringify(path.node));
node.arguments[0].value = evaluationExpression(case_body.consequent, now.indexName, i);
case_body.consequent = node;
} else {
i = evaluationExpression(case_body, now.indexName, i);
case_body = null;
}
}
if (!case_body) continue;
replaceBody.push(case_body);
if (types.isReturnStatement(case_body)) break;
}
if (!replaceBody.length) return;
replaceBody = now.variable.concat(replaceBody);
cache[callCode] = {
type: "ExpressionStatement",
expression: {
type: "CallExpression",
callee: {
type: "FunctionExpression",
params: now.path.node.params,
body: {
type: "BlockStatement",
body: replaceBody
}
},
arguments: path.node.arguments
}
};
}
}
}
$#合并调用
例子
switch (_$8w) {
case 0:
_$hk['$_ts'] = {};
case 1:
_$qA = _$vT.substr(_$yG, _$B_).split(_$NB.fromCharCode(255));
case 2:
var _$6U = _$UX(10);
case 3:
var _$B_ = _$z6();
case 4:
_$6U += "boDAnZapOCX8xJU2au447jYLkgwNztHO7AuauIp4P26lQTtdW5d$Q3e1G5F9IC3qE8ksXFTNV0jGl75dTsyxNioGl4Svu60uHKu3zrllyNPYY939zhkvUkumErxFngcRvZax5JQGjs3gejM9wARz_JsdQepMi5S6GKrhg3LvVtwUD70h1ZXQA3OjFPNF";
case 5:
_$pY = _$8_ === undefined || _$8_ === "";
case 6:
return 0;
case 7:
return _$UX(12, _$6U);
case 8:
var _$nE = _$z6();
case 9:
_$8_._$hk = 12;
case 10:
var _$dQ = _$z6();
----------------------------------------------
_$8_._$DK = 7;
_$8_._$hk = 12;
_$8_._$6n = 4;
_$8_._$Hn = "_$74";
_$8_._$Li = "_$v5";
_$8_._$gP = "_$pl";
_$8_._$jq = "_$ez";
_$8_._$u5 = "_$2X";
_$8_._$Zu = "_$Gn";
_$8_._$XK = "_$qK";
_$8_._$jS = "_$Ui";
_$8_._$pY = "_$qL";
_$8_._$J6 = "_$nE";
_$8_._$OA = "gabGed5GyIa";
_$8_._$2t = "JTKWP2.d7Dq";
_$8_._$uO = "Cr9JCX._VGtwUqL.MQKwjE";
_$8_._$B2 = "8ew8MTOflwq";
_$8_._$NB = _$KM;
_$8_._$Lc = "hLBEA6IMPqBY1gfp_t9V1G";
_$8_._$tQ = 57;
插件
因为直接替换卡住了,所以返璞归真正则替换吧!
function processCharacters(str) {
return str.replace(/\$/g, "\\$").replace(/\[/g, "\\[")
.replace(/\]/g, "\\]").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/\+/g, "\\+");
}
function replaceMergeCall() {
let cacheKeys = Object.keys(cache);
let {code} = generator(ast);
cacheKeys = [...new Set(cacheKeys)];
cacheKeys = [...cacheKeys, ...cacheKeys, ...cacheKeys];
cacheKeys.forEach(key => {
let re = new RegExp(processCharacters(key), "g");
let callCode = nodeFilter([cache[key]]);
code = code.replace(re, callCode.replace(/\'/g, '"'));
})
ast = parser.parse(code.replace(/;\n;/g, ";"));
}
拆分逗号表达式
插件
copy的蔡老板的插件,有现成的何必动手。
const decode_comma = {
//破解逗号表达式,兼容之前的脚本
ExpressionStatement(path) {
let {expression} = path.node;
if (!types.isSequenceExpression(expression)) return;
let body = [];
expression.expressions.forEach(express => {
body.push(types.expressionStatement(express));
})
path.replaceInline(body);
}
}
删除未引用
插件
/***
* 删除未引用
* @type {{VariableDeclarator(*): void}}
*/
const unreferenced = {
'VariableDeclarator|FunctionDeclaration'(path) {
const func_name = path.node.id.name;
const binding = path.scope.getBinding(func_name);
// 如果变量没有被引用过,那么删除也没关系
// 此处不能用有无修改过进行判断,因为没有被修改过并不意味着没用
if (binding && !binding.referenced) path.remove();
}
}
定制的删除未引用
插件
ast学的不深就乱写了,本着能用就行。
const forUnreferenced = {
VariableDeclarator(path) {
let _path = path.parentPath.parentPath.parentPath;
if (!_path.isFunctionExpression() || !_path.node.params.length) return;
let body = _path.node.body.body;
let start = body[0].start;
let end = body[body.length - 1].end;
let name = path.node.id.name;
const binding = path.scope.getBinding(name);
if (!binding) return;
let referencePaths = binding.referencePaths;
let referenced = 0;
for (let i = 0; i < binding.references; i++) {
let rp = referencePaths[i];
if (start < rp.node.start && rp.node.start < end) referenced++;
}
if (referenced) return;
path.remove();
}
}
替换值函数
只return数字的函数。
const replaceValueFunc = {
FunctionDeclaration(path) {
let {body, id, params} = path.node;
if (params.length || body.body.length !== 1) return;
const binding = path.scope.getBinding(id.name);
if (!binding) return;
let referencePaths = path.scope.getBinding(id.name).referencePaths;
referencePaths.forEach(rp => {
rp.parentPath.replaceInline(body.body[0].argument)
})
path.remove();
}
}
取反if
处理这if节点 if(!xx) function (xx) { xxx }(xx)
const negateJudgment = {
IfStatement(path) {
let {test, consequent} = path.node;
if (!types.isUnaryExpression(test)) return;
if (!types.isCallExpression(consequent.expression)) return;
path.node.consequent = consequent.expression.callee.body;
}
}
解码控制流
到这里只有7个case了
const decodeControlFlow = {
WhileStatement(path) {
let {body} = path.node;
let switchNode = body.body[1];
let {cases} = switchNode;
let replace_body = [];
funcInfo['main'].array.forEach(index => {
let case_body = cases[index].consequent;
if (types.isContinueStatement(case_body[case_body.length - 1])) {
case_body.pop();
}
replace_body = replace_body.concat(case_body);
}
);
path.replaceInline(replace_body);
}
}
到这里解混淆的绝大部分,具体流程也清晰可见了。
完整插件
const fs = require('fs');
//babel库相关,解析,转换,构建,生产
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
const generator = require("@babel/generator").default;
//读取文件
let encode_file = "./encode.js", decode_file = "./decode_result.js";
if (process.argv.length > 2) {
encode_file = process.argv[2];
}
if (process.argv.length > 3) {
decode_file = process.argv[3];
}
let jsCode = fs.readFileSync(encode_file, {encoding: "utf-8"});
//转换为ast树
let ast = parser.parse(jsCode);
function ifToSwitchNode(path, pathStr = "test.left") {
function getNodes(path, list = []) {
if (!path.isIfStatement()) {
list.push({
type: "SwitchCase",
consequent: path.node.body,
test: types.valueToNode(list[list.length - 2].right.value)
})
return list;
}
items.forEach(n => {
let tmep = path.get(n);
list.push(tmep.node);
})
return getNodes(path.get("alternate"), list);
}
function reductionTest(test) {
switch (test.operator) {
case "<":
test = types.valueToNode(test.right.value - 1)
break;
case "===":
test = types.valueToNode(test.right.value)
break;
}
return test;
}
let items = ["test", "consequent"];
let nodes = getNodes(path);
let cases = [], count = Math.trunc(nodes.length / items.length);
if (nodes.length % 2) cases.push(nodes.pop());
for (let i = 0; i < count; i++) {
cases.push({
type: "SwitchCase",
consequent: nodes.pop().body,
test: reductionTest(nodes.pop())
})
}
return {
type: "SwitchStatement",
discriminant: path.get(pathStr).node,
cases: cases.reverse()
}
}
const ifToSwitch = {
IfStatement(path) {
let {node} = path;
let {alternate} = node;
if (alternate === null) return;
let newNode = ifToSwitchNode(path);
path.replaceInline(newNode)
}
}
function getCaseAll(cases, caseAll = []) {
if (!types.isSwitchStatement(cases[0].consequent[0])) return cases;
for (let i = 0; i < cases.length; i++) {
let caseNode = cases[i];
if (!types.isSwitchStatement(caseNode.consequent[0])) {
if (types.isSwitchStatement(cases[i - 1].consequent[0])) caseAll.push(caseNode);
break;
}
caseAll = caseAll.concat(getCaseAll(caseNode.consequent[0].cases));
}
return caseAll;
}
const mergeSwitch = {
SwitchStatement(path) {
if (path.parentPath.isSwitchCase()) return;
let nextPath = path.get("cases.0.consequent.0");
if (!types.isSwitchStatement(nextPath)) return;
path.node.cases = getCaseAll(path.node.cases);
}
}
/**
* 向上查询某类型的ParentPath
* @param path
* @param type
* @returns {null|*}
*/
function findParentPath(path, type) {
while (!path.isProgram()) {
path = path.parentPath;
if (!path[`is${type}`]()) return path.parentPath;
}
}
/***
* 获取需要用到的对象名和节点
* @param path
* @param resultPath
*/
function getFuncInfo(path, resultPath) {
let info = Object();
info["switchPath"] = path.get('body.body.1');
let expressionNode = path.node.body.body[0];
let arrayName = expressionNode.expression.right.object.name;
let largeArrayInit = path.scope.getBinding(arrayName).path.node.init;
let largeArrayName = largeArrayInit.object.name;
let largeArrayIndex = largeArrayInit.property.value;
info["array"] = eval(generator(path.scope.getBinding(largeArrayName).path.node.init).code)[largeArrayIndex];
info["indexName"] = expressionNode.expression.right.property.argument.name;
info["variable"] = nodeFilter(path.getAllPrevSiblings(), ['VariableDeclaration', 'FunctionDeclaration'], false, false);
info["path"] = resultPath;
return info;
}
let funcInfo = {};
/***
* 缓存关键数据
* @type {{WhileStatement(*): void}}
*/
const cacheCriticalData = {
WhileStatement(path) {
let resultPath = findParentPath(path, "FunctionDeclaration");
if (!resultPath) return;
let funcName = "main";
if (!resultPath.isFunctionExpression()) {
funcName = resultPath.node.id.name;
}
// 缓存path和关键变量名以便后续使用
funcInfo[funcName] = getFuncInfo(path, resultPath);
}
}
/**
* 节点筛选器
* @param list [node/path...] 元素node或path都可
* @param filter 类型 array [str...] 类型列表
* @param filterMode 过滤器模式 默认false | false - 只输出配置的类型 true - 过滤(不输出)配置的类型
* @param isCode 默认true返回代码 false返回节点列表
* @returns {string|array} code/itemList
*/
function nodeFilter(list, filter = [true], filterMode = false, isCode = true) {
let code = "", itemList = [];
if (!list.length) return "";
let isPath = typeof list[0].isReturnStatement === "function";
if (isPath) list = list.reverse();
list.forEach(node => {
if (isPath) node = node.node;
if (filter[0] === true ||
(!filterMode === filter.includes(node.type))) {
isCode ? code += `${generator(node).code}\n` : itemList.push(node);
}
})
return isCode ? code : itemList;
}
/**
* 计算表达式
* @param node 表达式 node type: Expression
* @param name
* @param value
* @returns {any} 输出表达式code执行的结果
*/
function evaluationExpression(node, name, value) {
let replaceList = [[name, value]];
if (types.isExpressionStatement(node)) {
// 处理赋值操作直接返回value
if (node.expression.operator === "=") return node.expression.right.value;
replaceList = replaceList.concat([["\\+=", "+"], ["\\-=", "-"]]);
}
let reg, code = generator(node).code;
replaceList.forEach(item => {
// 动态生成正则 需要注意$字符
reg = new RegExp(`${item[0].replace(/\$/g, "\\$")}`, "g");
// 获取testCode | 将替换标识符为value 例子 -> let v = 1 | test节点代码 v >= 1 | 替换后 1 >= 1
code = code.replace(reg, item[1]);
});
try {
return eval(code);
} catch (e) {
console.error(e)
debugger
}
}
let cache = {};
const mergeCallInfo = {
CallExpression(path) {
let name = path.node.callee.name;
if (Object.keys(funcInfo).includes(name)) {
let now = funcInfo[name];
const {cases} = now.switchPath.node;
let value = path.node.arguments[0].value;
let replaceBody = [];
let callCode = path.toString();
if (Object.keys(cache).includes(callCode)) return;
let constantViolations = (() => {
let list = [];
now.path.scope.getBinding(now.indexName).constantViolations.forEach(p => list.push(p.node.start))
return list;
})();
for (let i = value; i < now.array.length; i++) {
let index = now.array[i];
let case_body = cases[index].consequent[0];
if (types.isIfStatement(case_body)) case_body.start = case_body.consequent.start;
if (case_body && constantViolations.includes(case_body.start)) {
if (types.isIfStatement(case_body)) {
let node = JSON.parse(JSON.stringify(path.node));
node.arguments[0].value = evaluationExpression(case_body.consequent, now.indexName, i);
case_body.consequent = node;
} else {
i = evaluationExpression(case_body, now.indexName, i);
case_body = null;
}
}
if (!case_body) continue;
replaceBody.push(case_body);
if (types.isReturnStatement(case_body)) break;
}
if (!replaceBody.length) return;
replaceBody = now.variable.concat(replaceBody);
cache[callCode] = {
type: "ExpressionStatement",
expression: {
type: "CallExpression",
callee: {
type: "FunctionExpression",
params: now.path.node.params,
body: {
type: "BlockStatement",
body: replaceBody
}
},
arguments: path.node.arguments
}
};
}
}
}
function processCharacters(str) {
return str.replace(/\$/g, "\\$").replace(/\[/g, "\\[")
.replace(//g, "\\]").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/\+/g, "\\+");
}
function replaceMergeCall() {
let cacheKeys = Object.keys(cache);
let {code} = generator(ast);
cacheKeys = [...new Set(cacheKeys)];
cacheKeys = [...cacheKeys, ...cacheKeys, ...cacheKeys];
cacheKeys.forEach(key => {
let re = new RegExp(processCharacters(key), "g");
let callCode = nodeFilter([cache[key]]);
code = code.replace(re, callCode.replace(/\'/g, '"'));
})
ast = parser.parse(code.replace(/;\n;/g, ";"));
}
const decode_comma = {
//破解逗号表达式,兼容之前的脚本
ExpressionStatement(path) {
let {expression} = path.node;
if (!types.isSequenceExpression(expression)) return;
let body = [];
expression.expressions.forEach(express => {
body.push(types.expressionStatement(express));
})
path.replaceInline(body);
}
}
/***
* 删除未引用
* @type {{VariableDeclarator(*): void}}
*/
const unreferenced = {
'VariableDeclarator|FunctionDeclaration'(path) {
const func_name = path.node.id.name;
const binding = path.scope.getBinding(func_name);
// 如果变量没有被引用过,那么删除也没关系
// 此处不能用有无修改过进行判断,因为没有被修改过并不意味着没用
if (binding && !binding.referenced) path.remove();
}
}
const replaceValueFunc = {
FunctionDeclaration(path) {
let {body, id, params} = path.node;
if (params.length || body.body.length !== 1) return;
const binding = path.scope.getBinding(id.name);
if (!binding) return;
let referencePaths = path.scope.getBinding(id.name).referencePaths;
referencePaths.forEach(rp => {
rp.parentPath.replaceInline(body.body[0].argument)
})
path.remove();
}
}
const forUnreferenced = {
VariableDeclarator(path) {
let _path = path.parentPath.parentPath.parentPath;
if (!_path.isFunctionExpression() || !_path.node.params.length) return;
let body = _path.node.body.body;
let start = body[0].start;
let end = body[body.length - 1].end;
let name = path.node.id.name;
const binding = path.scope.getBinding(name);
if (!binding) return;
let referencePaths = binding.referencePaths;
let referenced = 0;
for (let i = 0; i < binding.references; i++) {
let rp = referencePaths[i];
if (start < rp.node.start && rp.node.start < end) referenced++;
}
if (referenced) return;
path.remove();
}
}
const negateJudgment = {
IfStatement(path) {
let {test, consequent} = path.node;
if (!types.isUnaryExpression(test)) return;
if (!types.isCallExpression(consequent.expression)) return;
path.node.consequent = consequent.expression.callee.body;
}
}
const decodeControlFlow = {
WhileStatement(path) {
let {body} = path.node;
let switchNode = body.body[1];
let {cases} = switchNode;
let replace_body = [];
funcInfo['main'].array.forEach(index => {
let case_body = cases[index].consequent;
if (types.isContinueStatement(case_body[case_body.length - 1])) {
case_body.pop();
}
replace_body = replace_body.concat(case_body);
}
);
path.replaceInline(replace_body);
}
}
console.time("处理完毕,耗时")
traverse(ast, ifToSwitch)
traverse(ast, mergeSwitch)
traverse(ast, cacheCriticalData)
traverse(ast, mergeCallInfo)
replaceMergeCall()
traverse(ast, decode_comma)
traverse(ast, unreferenced)
traverse(ast, forUnreferenced)
traverse(ast, replaceValueFunc)
traverse(ast, negateJudgment)
traverse(ast, decodeControlFlow)
console.timeEnd("处理完毕,耗时")
//生成新的js code,并保存到文件中输出
let {code} = generator(ast, opts = {jsescOption: {"minimal": true}});
fs.writeFile(decode_file, code, (err) => {
});