UNPKG

js-confuser

Version:

JavaScript Obfuscation Tool.

293 lines (271 loc) 15.7 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var t = _interopRequireWildcard(require("@babel/types")); var _astUtils = require("../utils/ast-utils"); var _order = require("../order"); var _constants = require("../constants"); var _functionUtils = require("../utils/function-utils"); var _NameGen = require("../utils/NameGen"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } var _default = exports["default"] = function _default(_ref) { var Plugin = _ref.Plugin; var me = Plugin(_order.Order.Flatten, { changeData: { functions: 0 } }); var isDebug = false; function flattenFunction(fnPath) { // Skip if already processed if (me.isSkipped(fnPath)) return; // Don't apply to generator functions if (fnPath.node.generator) return; // Skip getter/setter methods if (fnPath.isObjectMethod() || fnPath.isClassMethod()) { if (fnPath.node.kind !== "method") return; } // Do not apply to arrow functions if (t.isArrowFunctionExpression(fnPath.node)) return; if (!t.isBlockStatement(fnPath.node.body)) return; // Skip if marked as unsafe if (fnPath.node[_constants.UNSAFE]) return; var program = fnPath.findParent(function (p) { return p.isProgram(); }); var functionName = (0, _astUtils.getFunctionName)(fnPath); if (!t.isValidIdentifier(functionName, true)) { functionName = "anonymous"; } if (!me.computeProbabilityMap(me.options.flatten, functionName)) { return; } var strictMode = fnPath.find(function (path) { return (0, _astUtils.isStrictMode)(path); }); if (strictMode === fnPath) return; me.log("Transforming", functionName); var flatObjectName = "".concat(me.getPlaceholder(), "_flat_object"); var newFnName = "".concat(me.getPlaceholder(), "_flat_").concat(functionName); var nameGen = new _NameGen.NameGen(me.options.identifierGenerator); function generateProp(originalName, type) { var newPropertyName; do { newPropertyName = isDebug ? type + "_" + originalName : nameGen.generate(); } while (allPropertyNames.has(newPropertyName)); allPropertyNames.add(newPropertyName); return newPropertyName; } var standardProps = new Map(); var setterPropsNeeded = new Set(); var typeofProps = new Map(); var functionCallProps = new Map(); var allPropertyNames = new Set(); var identifierPaths = []; // Traverse function to identify variables to be replaced with flat object properties fnPath.traverse({ Identifier: { exit: function exit(identifierPath) { if (!(0, _astUtils.isVariableIdentifier)(identifierPath)) return; if (identifierPath.isBindingIdentifier() && (0, _astUtils.isDefiningIdentifier)(identifierPath)) return; if ((0, _functionUtils.isVariableFunctionIdentifier)(identifierPath)) return; if (identifierPath.node[_constants.UNSAFE]) return; var identifierName = identifierPath.node.name; if (identifierName === "arguments") return; var binding = identifierPath.scope.getBinding(identifierName); if (!binding) { return; } var isOutsideVariable = fnPath.scope.parent.getBinding(identifierName) === binding; if (!isOutsideVariable) { return; } identifierPaths.push(identifierPath); } } }); me.log("Function ".concat(functionName), "requires", Array.from(new Set(identifierPaths.map(function (x) { return x.node.name; })))); for (var _i = 0, _identifierPaths = identifierPaths; _i < _identifierPaths.length; _i++) { var identifierPath = _identifierPaths[_i]; var identifierName = identifierPath.node.name; if (typeof identifierName !== "string") continue; var isTypeof = identifierPath.parentPath.isUnaryExpression({ operator: "typeof" }); var isFunctionCall = identifierPath.parentPath.isCallExpression() && identifierPath.parentPath.node.callee === identifierPath.node; if (isTypeof) { var typeofProp = typeofProps.get(identifierName); if (!typeofProp) { typeofProp = generateProp(identifierName, "typeof"); typeofProps.set(identifierName, typeofProp); } (0, _astUtils.ensureComputedExpression)(identifierPath.parentPath); identifierPath.parentPath.replaceWith(t.memberExpression(t.identifier(flatObjectName), t.stringLiteral(typeofProp), true))[0].skip(); } else if (isFunctionCall) { var functionCallProp = functionCallProps.get(identifierName); if (!functionCallProp) { functionCallProp = generateProp(identifierName, "call"); functionCallProps.set(identifierName, functionCallProp); } (0, _astUtils.ensureComputedExpression)(identifierPath); // Replace identifier with a reference to the flat object property identifierPath.replaceWith(t.memberExpression(t.identifier(flatObjectName), t.stringLiteral(functionCallProp), true))[0].skip(); } else { var standardProp = standardProps.get(identifierName); if (!standardProp) { standardProp = generateProp(identifierName, "standard"); standardProps.set(identifierName, standardProp); } if (!setterPropsNeeded.has(identifierName)) { // Only provide 'set' method if the variable is modified var isModification = (0, _astUtils.isModifiedIdentifier)(identifierPath); if (isModification) { setterPropsNeeded.add(identifierName); } } (0, _astUtils.ensureComputedExpression)(identifierPath); // Replace identifier with a reference to the flat object property identifierPath.replaceWith(t.memberExpression(t.identifier(flatObjectName), t.stringLiteral(standardProp), true))[0].skip(); } } // for (const prop of [...typeofProps.keys(), ...functionCallProps.keys()]) { // if (!standardProps.has(prop)) { // standardProps.set(prop, generateProp()); // } // } var flatObjectProperties = []; var _iterator = _createForOfIteratorHelper(standardProps), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var entry = _step.value; var _entry = entry, _entry2 = _slicedToArray(_entry, 2), _identifierName = _entry2[0], objectProp = _entry2[1]; flatObjectProperties.push(me.skip(t.objectMethod("get", t.stringLiteral(objectProp), [], t.blockStatement([t.returnStatement(t.identifier(_identifierName))]), false, false, false))); // Not all properties need a setter if (setterPropsNeeded.has(_identifierName)) { var valueArgName = me.getPlaceholder() + "_value"; flatObjectProperties.push(me.skip(t.objectMethod("set", t.stringLiteral(objectProp), [t.identifier(valueArgName)], t.blockStatement([t.expressionStatement(t.assignmentExpression("=", t.identifier(_identifierName), t.identifier(valueArgName)))]), false, false, false))); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } var _iterator2 = _createForOfIteratorHelper(typeofProps), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var _entry3 = _step2.value; var _entry4 = _slicedToArray(_entry3, 2), _identifierName2 = _entry4[0], _objectProp = _entry4[1]; flatObjectProperties.push(me.skip(t.objectMethod("get", t.stringLiteral(_objectProp), [], t.blockStatement([t.returnStatement(t.unaryExpression("typeof", t.identifier(_identifierName2)))]), false, false, false))); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } var _iterator3 = _createForOfIteratorHelper(functionCallProps), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var _entry5 = _step3.value; var _entry6 = _slicedToArray(_entry5, 2), _identifierName3 = _entry6[0], _objectProp2 = _entry6[1]; flatObjectProperties.push(me.skip(t.objectMethod("method", t.stringLiteral(_objectProp2), [t.restElement(t.identifier("args"))], t.blockStatement([t.returnStatement(t.callExpression(t.identifier(_identifierName3), [t.spreadElement(t.identifier("args"))]))]), false, false, false))); } // Create the new flattened function } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } var flattenedFunctionDeclaration = t.functionDeclaration(t.identifier(newFnName), [t.arrayPattern(_toConsumableArray(fnPath.node.params)), t.identifier(flatObjectName)], t.blockStatement(_toConsumableArray(fnPath.node.body.body).concat()), false, fnPath.node.async); // Create the flat object variable declaration var flatObjectDeclaration = t.variableDeclaration("var", [t.variableDeclarator(t.identifier(flatObjectName), t.objectExpression(flatObjectProperties))]); var argName = me.getPlaceholder() + "_args"; // Replace original function body with a call to the flattened function fnPath.node.body = t.blockStatement([flatObjectDeclaration, t.returnStatement(t.callExpression(t.identifier(newFnName), [t.identifier(argName), t.identifier(flatObjectName)]))]); var originalLength = (0, _functionUtils.computeFunctionLength)(fnPath); fnPath.node.params = [t.restElement(t.identifier(argName))]; // Ensure updated parameter gets registered in the function scope fnPath.scope.crawl(); fnPath.skip(); // Add the new flattened function at the top level var newPath = (0, _astUtils.prependProgram)(program, flattenedFunctionDeclaration)[0]; me.skip(newPath); // Copy over all properties except the predictable flag var _iterator4 = _createForOfIteratorHelper(Object.getOwnPropertySymbols(fnPath.node)), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { var symbol = _step4.value; if (symbol !== _constants.PREDICTABLE) { newPath.node[symbol] = fnPath.node[symbol]; } } // Old function is no longer predictable (rest element parameter) } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } fnPath.node[_constants.PREDICTABLE] = false; // Old function is unsafe (uses arguments, this) fnPath.node[_constants.UNSAFE] = true; newPath.node[_constants.PREDICTABLE] = true; // Carry over 'use strict' directive if not already present if (strictMode) { newPath.node.body.directives.push(t.directive(t.directiveLiteral("use strict"))); // Non-simple parameter list conversion (0, _astUtils.prepend)(newPath, t.variableDeclaration("var", [t.variableDeclarator(t.arrayPattern(newPath.node.params), t.identifier("arguments"))])); newPath.node.params = []; // Using 'arguments' is unsafe newPath.node[_constants.UNSAFE] = true; // Params changed and using 'arguments' newPath.node[_constants.PREDICTABLE] = false; } // Ensure parameters are registered in the new function scope newPath.scope.crawl(); newPath.skip(); me.skip(newPath); // Set function length me.setFunctionLength(fnPath, originalLength); me.changeData.functions++; } return { visitor: { Function: { exit: function exit(path) { flattenFunction(path); } }, Program: function Program(path) { path.scope.crawl(); } } }; };