js-confuser
Version:
JavaScript Obfuscation Tool.
208 lines (190 loc) • 11.6 kB
JavaScript
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]));
}
}
}
}
};
};
;