UNPKG

js-confuser

Version:

JavaScript Obfuscation Tool.

208 lines (190 loc) 11.6 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 _template = _interopRequireDefault(require("../../templates/template")); var _order = require("../../order"); var _assert = require("assert"); var _bufferToStringTemplate = require("../../templates/bufferToStringTemplate"); var _getGlobalTemplate = require("../../templates/getGlobalTemplate"); var _astUtils = require("../../utils/ast-utils"); var _randomUtils = require("../../utils/random-utils"); var _encoding = require("./encoding"); var _node = require("../../utils/node"); var _constants = require("../../constants"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } 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 _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 _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 _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 _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 STRING_CONCEALING = Symbol("StringConcealing"); var _default = exports["default"] = function _default(_ref) { var Plugin = _ref.Plugin; var me = Plugin(_order.Order.StringConcealing, { changeData: { strings: 0 } }); var blocks = []; var stringMap = new Map(); var stringArrayName = me.getPlaceholder() + "_array"; var encodingImplementations = Object.create(null); var availableStringEncodings = me.options.customStringEncodings; // If no custom encodings are provided, use the default encoding if (!availableStringEncodings || availableStringEncodings.length === 0) { availableStringEncodings = [_encoding.createDefaultStringEncoding]; } function hasAllEncodings() { return availableStringEncodings.length === 0; } function createStringEncoding() { var encodingIndex = (0, _randomUtils.getRandomInteger)(0, availableStringEncodings.length); var encoding = availableStringEncodings[encodingIndex]; if (typeof encoding === "function") { encoding = encoding(encodingImplementations); var duplicateIdentity = typeof encoding.identity !== "undefined" && typeof encodingImplementations[encoding.identity] !== "undefined"; if (duplicateIdentity || encoding === null) { // Null returned -> All encodings have been created // Duplicate identity -> Most likely all encodings have been created // No longer create new encodings using this function availableStringEncodings = availableStringEncodings.filter(function (x) { return x !== encoding; }); // Return a random encoding already made encoding = (0, _randomUtils.choice)(Object.values(encodingImplementations)); (0, _assert.ok)(encoding, "Failed to create main string encoding"); } } if (typeof encoding.identity === "undefined") { encoding.identity = encodingIndex.toString(); } if (typeof encoding.code === "string") { encoding.code = new _template["default"](encoding.code); } encodingImplementations[encoding.identity] = encoding; return encoding; } return { visitor: { Program: { exit: function exit(programPath) { var mainEncodingImplementation; // Create a main encoder function for the Program programPath.node[STRING_CONCEALING] = { encodingImplementation: mainEncodingImplementation = createStringEncoding(), fnName: me.getPlaceholder() + "_MAIN_STR" }; blocks.push(programPath); // Use that encoder function for these fake strings var fakeStringCount = (0, _randomUtils.getRandomInteger)(75, 125); for (var i = 0; i < fakeStringCount; i++) { var fakeString = (0, _randomUtils.getRandomString)((0, _randomUtils.getRandomInteger)(5, 50)); stringMap.set(mainEncodingImplementation.encode(fakeString), stringMap.size); } programPath.traverse({ StringLiteral: { exit: function exit(path) { var _block; var originalValue = path.node.value; // Ignore require() calls / Import statements if ((0, _astUtils.isModuleImport)(path)) { return; } // Minimum length of 3 characters if (originalValue.length < 3) { return; } // Check user setting if (!me.computeProbabilityMap(me.options.stringConcealing, originalValue)) { return; } var block = path.findParent(function (p) { var _p$node; return p.isBlock() && !!((_p$node = p.node) !== null && _p$node !== void 0 && _p$node[STRING_CONCEALING]); }); var stringConcealingInterface = (_block = block) === null || _block === void 0 || (_block = _block.node) === null || _block === void 0 ? void 0 : _block[STRING_CONCEALING]; if (!block || !hasAllEncodings() && (0, _randomUtils.chance)(75 - blocks.length)) { // Create a new encoder function // Select random block parent (or Program) block = path.findParent(function (p) { return p.isBlock(); }); var stringConcealingNode = block.node; // Ensure not to overwrite the previous encoders if (!stringConcealingNode[STRING_CONCEALING]) { // Create a new encoding function for this block var encodingImplementation = createStringEncoding(); var fnName = me.getPlaceholder() + "_STR_" + blocks.length; stringConcealingInterface = { encodingImplementation: encodingImplementation, fnName: fnName }; // Save this info in the AST for future strings stringConcealingNode[STRING_CONCEALING] = stringConcealingInterface; blocks.push(block); } } (0, _assert.ok)(stringConcealingInterface); var encodedValue = stringConcealingInterface.encodingImplementation.encode(originalValue); // If a decoder function is provided, use it to validate each encoded string if (typeof stringConcealingInterface.encodingImplementation.decode === "function") { var decodedValue = stringConcealingInterface.encodingImplementation.decode(encodedValue); if (decodedValue !== originalValue) { return; } } var index = stringMap.get(encodedValue); if (typeof index === "undefined") { index = stringMap.size; stringMap.set(encodedValue, index); } me.changeData.strings++; // Ensure the string is computed so we can replace it with complex call expression (0, _astUtils.ensureComputedExpression)(path); // Replace the string literal with a call to the decoder function path.replaceWith(t.callExpression(t.identifier(stringConcealingInterface.fnName), [(0, _node.numericLiteral)(index)])); // Skip the transformation for the newly created node path.skip(); } } }); var bufferToStringName = me.getPlaceholder() + "_bufferToString"; var getGlobalFnName = me.getPlaceholder() + "_getGlobal"; var bufferToStringCode = _bufferToStringTemplate.BufferToStringTemplate.compile({ GetGlobalTemplate: (0, _getGlobalTemplate.createGetGlobalTemplate)(me, programPath), getGlobalFnName: getGlobalFnName, BufferToString: bufferToStringName }); (0, _astUtils.prependProgram)(programPath, bufferToStringCode); // Create the string array (0, _astUtils.prependProgram)(programPath, t.variableDeclaration("var", [t.variableDeclarator(t.identifier(stringArrayName), t.arrayExpression(Array.from(stringMap.keys()).map(function (x) { return t.stringLiteral(x); })))])); for (var _i = 0, _blocks = blocks; _i < _blocks.length; _i++) { var block = _blocks[_i]; var _ref2 = block.node[STRING_CONCEALING], encodingImplementation = _ref2.encodingImplementation, fnName = _ref2.fnName; var decodeFnName = fnName + "_decode"; (0, _assert.ok)(encodingImplementation.code instanceof _template["default"]); // The decoder function var decoder = encodingImplementation.code.addSymbols(_constants.NO_REMOVE).compile({ fnName: decodeFnName, __bufferToStringFunction__: bufferToStringName }); // The main function to get the string value var retrieveFunctionDeclaration = new _template["default"]("\n function ".concat(fnName, "(index) {\n return ").concat(decodeFnName, "(").concat(stringArrayName, "[index]);\n }\n ")).addSymbols(_constants.NO_REMOVE).single(); (0, _astUtils.prepend)(block, [].concat(_toConsumableArray(decoder), [retrieveFunctionDeclaration])); } } } } }; };