├── .gitignore ├── .babelrc ├── code2.js ├── code1.js ├── code4.js ├── package.json ├── code3.js ├── deobfuscate2.js ├── deobfuscate1.js ├── deobfuscate3.js ├── deobfuscate4.1.js ├── deobfuscate4.js └── deobfuscate3.1.js /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | node_modules -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /code2.js: -------------------------------------------------------------------------------- 1 | const strings = ["\x68\x65\x6c\x6c\x6f", "\x77\x6f\x72\x6c\x64"]; 2 | -------------------------------------------------------------------------------- /code1.js: -------------------------------------------------------------------------------- 1 | const a = !![]; 2 | const b = "abc" == "bcd"; 3 | const c = (1 << 3) | 2; 4 | const d = parseInt("5" + "0"); 5 | -------------------------------------------------------------------------------- /code4.js: -------------------------------------------------------------------------------- 1 | const s = "3|1|2".split("|"); 2 | let x = 0; 3 | while (true) { 4 | switch (s[x++]) { 5 | case "1": 6 | const a = 1; 7 | continue; 8 | case "2": 9 | const b = 3; 10 | continue; 11 | case "3": 12 | const c = 0; 13 | continue; 14 | } 15 | break; 16 | } 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deobfuscate", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@babel/cli": "^7.14.8", 13 | "@babel/core": "^7.15.0", 14 | "@babel/node": "^7.14.9", 15 | "@babel/preset-env": "^7.15.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code3.js: -------------------------------------------------------------------------------- 1 | const _0x16c18d = function () { 2 | if (!![[]]) { 3 | console.log("hello world"); 4 | } else { 5 | console.log("this"); 6 | console.log("is"); 7 | console.log("dead"); 8 | console.log("code"); 9 | } 10 | }; 11 | const _0x1f7292 = function () { 12 | if ("xmv2nOdfy2N".charAt(4) !== String.fromCharCode(110)) { 13 | console.log("this"); 14 | console.log("is"); 15 | console.log("dead"); 16 | console.log("code"); 17 | } else { 18 | console.log("nice to meet you"); 19 | } 20 | }; 21 | 22 | _0x16c18d(); 23 | _0x1f7292(); 24 | -------------------------------------------------------------------------------- /deobfuscate2.js: -------------------------------------------------------------------------------- 1 | import traverse from "@babel/traverse"; 2 | import { parse } from "@babel/parser"; 3 | import generate from "@babel/generator"; 4 | import fs from "fs"; 5 | 6 | const code = fs.readFileSync("code2.js", "utf-8"); 7 | let ast = parse(code); 8 | traverse(ast, { 9 | StringLiteral({ node }) { 10 | if (node.extra && /\\[ux]/gi.test(node.extra.raw)) { 11 | node.extra.raw = node.extra.rawValue; 12 | // or just set to undefined 13 | // node.extra = undefined; 14 | } 15 | }, 16 | }); 17 | const { code: output } = generate(ast); 18 | console.log(output); 19 | -------------------------------------------------------------------------------- /deobfuscate1.js: -------------------------------------------------------------------------------- 1 | import traverse from "@babel/traverse"; 2 | import { parse } from "@babel/parser"; 3 | import generate from "@babel/generator"; 4 | import * as types from "@babel/types"; 5 | import fs from "fs"; 6 | 7 | const code = fs.readFileSync("code1.js", "utf-8"); 8 | let ast = parse(code); 9 | 10 | traverse(ast, { 11 | "UnaryExpression|BinaryExpression|ConditionalExpression|CallExpression": ( 12 | path 13 | ) => { 14 | // console.log(path); 15 | const { confident, value } = path.evaluate(); 16 | console.log({ confident, value }); 17 | if (value == Infinity || value == -Infinity) return; 18 | confident && path.replaceWith(types.valueToNode(value)); 19 | }, 20 | }); 21 | 22 | const { code: output } = generate(ast); 23 | console.log(output); 24 | -------------------------------------------------------------------------------- /deobfuscate3.js: -------------------------------------------------------------------------------- 1 | import traverse from "@babel/traverse"; 2 | import { parse } from "@babel/parser"; 3 | import generate from "@babel/generator"; 4 | import * as types from "@babel/types"; 5 | import fs from "fs"; 6 | 7 | const code = fs.readFileSync("code3.js", "utf-8"); 8 | let ast = parse(code); 9 | 10 | traverse(ast, { 11 | IfStatement(path) { 12 | let { consequent, alternate } = path.node; 13 | let testPath = path.get("test"); 14 | // console.log("test path", testPath); 15 | // console.log(typeof testPath); 16 | const evaluateTest = testPath.evaluateTruthy(); 17 | console.log("evaluateTest", evaluateTest); 18 | 19 | if (evaluateTest === true) { 20 | if (types.isBlockStatement(consequent)) { 21 | consequent = consequent.body; 22 | } 23 | path.replaceWithMultiple(consequent); 24 | } else if (evaluateTest === false) { 25 | if (alternate != null) { 26 | if (types.isBlockStatement(alternate)) { 27 | alternate = alternate.body; 28 | } 29 | path.replaceWithMultiple(alternate); 30 | } else { 31 | path.remove(); 32 | } 33 | } 34 | } 35 | }); 36 | 37 | const { code: output } = generate(ast); 38 | console.log(output); 39 | -------------------------------------------------------------------------------- /deobfuscate4.1.js: -------------------------------------------------------------------------------- 1 | import traverse from "@babel/traverse"; 2 | import { parse } from "@babel/parser"; 3 | import generate from "@babel/generator"; 4 | import * as types from "@babel/types"; 5 | import fs from "fs"; 6 | 7 | const code = fs.readFileSync("code4.js", "utf-8"); 8 | let ast = parse(code); 9 | 10 | traverse(ast, { 11 | WhileStatement(path) { 12 | const { node, scope } = path; 13 | const { test, body } = node; 14 | let switchNode = body.body[0]; 15 | let { discriminant, cases } = switchNode; 16 | let { object, property } = discriminant; 17 | let arrName = object.name; 18 | let binding = scope.getBinding(arrName); 19 | let { init } = binding.path.node; 20 | object = init.callee.object; 21 | property = init.callee.property; 22 | let argument = init.arguments[0].value; 23 | let arrayFlow = object.value[property.name](argument); 24 | let resultBody = []; 25 | arrayFlow.forEach((index) => { 26 | let switchCase = cases.filter((c) => c.test.value == index)[0]; 27 | let caseBody = switchCase.consequent; 28 | if (types.isContinueStatement(caseBody[caseBody.length - 1])) { 29 | caseBody.pop(); 30 | } 31 | resultBody = resultBody.concat(caseBody); 32 | }); 33 | path.replaceWithMultiple(resultBody); 34 | }, 35 | }); 36 | 37 | const { code: output } = generate(ast); 38 | console.log(output); 39 | -------------------------------------------------------------------------------- /deobfuscate4.js: -------------------------------------------------------------------------------- 1 | import traverse from "@babel/traverse"; 2 | import { parse } from "@babel/parser"; 3 | import generate from "@babel/generator"; 4 | import * as types from "@babel/types"; 5 | import fs from "fs"; 6 | 7 | const code = fs.readFileSync("code4.js", "utf-8"); 8 | let ast = parse(code); 9 | 10 | traverse(ast, { 11 | WhileStatement(path) { 12 | const { node, scope } = path; 13 | const { test, body } = node; 14 | if (!types.isLiteral(test, { value: true })) return; 15 | if (body.body.length != 2) return; 16 | let switchNode = body.body[0], 17 | breakNode = body.body[1]; 18 | if ( 19 | !types.isSwitchStatement(switchNode) || 20 | !types.isBreakStatement(breakNode) 21 | ) { 22 | return; 23 | } 24 | let { discriminant, cases } = switchNode; 25 | if (!types.isMemberExpression(discriminant)) return; 26 | let { object, property } = discriminant; 27 | if (!types.isIdentifier(object) || !types.isUpdateExpression(property)) 28 | return; 29 | 30 | let arrName = object.name; 31 | let binding = scope.getBinding(arrName); 32 | if (!binding || !binding.path || !binding.path.isVariableDeclarator()) 33 | return; 34 | let { init } = binding.path.node; 35 | if ( 36 | !types.isCallExpression(init) || 37 | !types.isMemberExpression(init.callee) || 38 | !init.arguments.length > 0 39 | ) { 40 | return; 41 | } 42 | 43 | object = init.callee.object; 44 | property = init.callee.property; 45 | let argument = init.arguments[0].value; 46 | 47 | if (!types.isStringLiteral(object) || !types.isIdentifier(property)) { 48 | return; 49 | } 50 | 51 | let arrayFlow = object.value[property.name](argument); 52 | let resultBody = []; 53 | arrayFlow.forEach((index) => { 54 | let switchCases = cases.filter( 55 | (switchCase) => switchCase.test.value == index 56 | ); 57 | let switchCase = switchCases.length > 0 ? switchCases[0] : undefined; 58 | if (!switchCase) { 59 | return; 60 | } 61 | let caseBody = switchCase.consequent; 62 | if (types.isContinueStatement(caseBody[caseBody.length - 1])) { 63 | caseBody.pop(); 64 | } 65 | resultBody = resultBody.concat(caseBody); 66 | }); 67 | 68 | path.replaceWithMultiple(resultBody); 69 | }, 70 | }); 71 | 72 | const { code: output } = generate(ast); 73 | console.log(output); 74 | -------------------------------------------------------------------------------- /deobfuscate3.1.js: -------------------------------------------------------------------------------- 1 | import traverse from "@babel/traverse"; 2 | import { parse } from "@babel/parser"; 3 | import generate from "@babel/generator"; 4 | import * as t from "@babel/types"; 5 | import fs from "fs"; 6 | 7 | const code = fs.readFileSync("code3.js", "utf-8"); 8 | let ast = parse(code); 9 | 10 | function callToStr(path) { 11 | // 将对象进行替换 12 | var node = path.node; 13 | 14 | if (!t.isObjectExpression(node.init)) return; 15 | 16 | // 获取对象内所有属性 17 | var objPropertiesList = node.init.properties; 18 | 19 | if (objPropertiesList.length == 0) return; 20 | 21 | // 对象名 22 | var objName = node.id.name; 23 | // 是否可删除该对象:发生替换时可删除,否则不删除 24 | var del_flag = false; 25 | 26 | objPropertiesList.forEach((prop) => { 27 | var key = prop.key.value; 28 | if (t.isFunctionExpression(prop.value)) { 29 | var retStmt = prop.value.body.body[0]; 30 | 31 | // 该path的最近父节点 32 | var fnPath = path.getFunctionParent(); 33 | fnPath.traverse({ 34 | CallExpression: function (_path) { 35 | if (!t.isMemberExpression(_path.node.callee)) return; 36 | 37 | var _node = _path.node.callee; 38 | if (!t.isIdentifier(_node.object) || _node.object.name !== objName) 39 | return; 40 | if ( 41 | !( 42 | t.isStringLiteral(_node.property) || 43 | t.isIdentifier(_node.property) 44 | ) 45 | ) 46 | return; 47 | if (!(_node.property.value == key || _node.property.name == key)) 48 | return; 49 | // if (!t.isStringLiteral(_node.property) || _node.property.value != key) 50 | // return; 51 | 52 | var args = _path.node.arguments; 53 | 54 | // 二元运算 55 | if (t.isBinaryExpression(retStmt.argument) && args.length === 2) { 56 | _path.replaceWith( 57 | t.binaryExpression(retStmt.argument.operator, args[0], args[1]) 58 | ); 59 | } 60 | // 逻辑运算 61 | else if ( 62 | t.isLogicalExpression(retStmt.argument) && 63 | args.length == 2 64 | ) { 65 | _path.replaceWith( 66 | t.logicalExpression(retStmt.argument.operator, args[0], args[1]) 67 | ); 68 | } 69 | // 函数调用 70 | else if ( 71 | t.isCallExpression(retStmt.argument) && 72 | t.isIdentifier(retStmt.argument.callee) 73 | ) { 74 | _path.replaceWith(t.callExpression(args[0], args.slice(1))); 75 | } 76 | del_flag = true; 77 | }, 78 | }); 79 | } else if (t.isStringLiteral(prop.value)) { 80 | var retStmt = prop.value.value; 81 | 82 | // 该path的最近父节点 83 | var fnPath = path.getFunctionParent(); 84 | fnPath.traverse({ 85 | MemberExpression: function (_path) { 86 | var _node = _path.node; 87 | if (!t.isIdentifier(_node.object) || _node.object.name !== objName) 88 | return; 89 | if ( 90 | !( 91 | t.isStringLiteral(_node.property) || 92 | t.isIdentifier(_node.property) 93 | ) 94 | ) 95 | return; 96 | if (!(_node.property.value == key || _node.property.name == key)) 97 | return; 98 | // if (!t.isStringLiteral(_node.property) || _node.property.value != key) 99 | // return; 100 | 101 | _path.replaceWith(t.stringLiteral(retStmt)); 102 | del_flag = true; 103 | }, 104 | }); 105 | } 106 | }); 107 | if (del_flag) { 108 | // 如果发生替换,则删除该对象 109 | path.remove(); 110 | } 111 | } 112 | 113 | traverse(ast, { VariableDeclarator: { exit: [callToStr] } }); 114 | 115 | const { code: output } = generate(ast); 116 | console.log(output); 117 | --------------------------------------------------------------------------------