js-confuser
Version:
JavaScript Obfuscation Tool.
192 lines (180 loc) • 8.87 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 _order = require("../../order");
var _constants = require("../../constants");
var t = _interopRequireWildcard(require("@babel/types"));
var _staticUtils = require("../../utils/static-utils");
var _astUtils = require("../../utils/ast-utils");
var _template = _interopRequireDefault(require("../../templates/template"));
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; }
/**
* Moved Declarations moves variables in two ways:
*
* 1) Move variables to top of the current block
* 2) Move variables as unused function parameters
*/
var _default = exports["default"] = function _default(_ref) {
var Plugin = _ref.Plugin;
var me = Plugin(_order.Order.MovedDeclarations, {
changeData: {
variableDeclarations: 0,
functionParameters: 0
}
});
function isFunctionEligibleForParameterPacking(functionPath, proposedParameterName) {
// Getter/setter functions must have zero or one formal parameter
// We cannot add extra parameters to them
if (functionPath.isObjectMethod() || functionPath.isClassMethod()) {
if (functionPath.node.kind !== "method") {
return false;
}
}
// Rest params check
if (functionPath.get("params").find(function (p) {
return p.isRestElement();
})) return false;
// Max 1,000 parameters
if (functionPath.get("params").length > 1000) return false;
// Check for duplicate parameter names
var bindingIdentifiers = (0, _astUtils.getPatternIdentifierNames)(functionPath.get("params"));
// Duplicate parameter name not allowed
if (bindingIdentifiers.has(proposedParameterName)) return false;
return true;
}
return {
visitor: {
FunctionDeclaration: {
exit: function exit(path) {
var functionPath = path.findParent(function (path) {
return path.isFunction();
});
if (!functionPath || !functionPath.node[_constants.PREDICTABLE]) return;
var fnBody = functionPath.get("body");
if (!fnBody.isBlockStatement()) return;
// Must be direct child of the function
if (path.parentPath !== fnBody) return;
var functionName = path.node.id.name;
// Must be eligible for parameter packing
if (!isFunctionEligibleForParameterPacking(functionPath, functionName)) return;
var strictMode = (0, _astUtils.isStrictMode)(functionPath);
// Default parameters are not allowed when 'use strict' is declared
if (strictMode) return;
var functionExpression = path.node;
functionExpression.type = "FunctionExpression";
functionExpression.id = null;
var identifier = t.identifier(functionName);
functionPath.node.params.push(identifier);
var paramPath = functionPath.get("params").at(-1);
// Update binding to point to new path
var binding = functionPath.scope.getBinding(functionName);
if (binding) {
binding.kind = "param";
binding.path = paramPath;
binding.identifier = identifier;
}
(0, _astUtils.prepend)(fnBody, new _template["default"]("\n if(!".concat(functionName, ") {\n ").concat(functionName, " = {functionExpression};\n }\n ")).single({
functionExpression: functionExpression
}));
path.remove();
me.changeData.functionParameters++;
}
},
VariableDeclaration: {
exit: function exit(path) {
if (me.isSkipped(path)) return;
if (path.node.kind !== "var") return;
if (path.node.declarations.length !== 1) return;
var insertionMethod = "variableDeclaration";
var functionPath = path.findParent(function (path) {
return path.isFunction();
});
var declaration = path.node.declarations[0];
if (!t.isIdentifier(declaration.id)) return;
var varName = declaration.id.name;
var allowDefaultParamValue = true;
if (functionPath && functionPath.node[_constants.PREDICTABLE]) {
// Check for "use strict" directive
// Strict mode disallows non-simple parameters
// So we can't move the declaration to the function parameters
var strictMode = (0, _astUtils.isStrictMode)(functionPath);
if (strictMode) {
allowDefaultParamValue = false;
}
// Cannot add variables after rest element
// Cannot add over 1,000 parameters
if (isFunctionEligibleForParameterPacking(functionPath, varName)) {
insertionMethod = "functionParameter";
}
}
var name = declaration.id.name;
var value = declaration.init || t.identifier("undefined");
var isStatic = (0, _staticUtils.isStaticValue)(value);
var isDefinedAtTop = false;
var parentPath = path.parentPath;
if (parentPath.isBlock()) {
isDefinedAtTop = parentPath.get("body").filter(function (x) {
return x.type !== "ImportDeclaration";
}).indexOf(path) === 0;
}
// Already at the top - nothing will change
if (insertionMethod === "variableDeclaration" && isDefinedAtTop) {
return;
}
var defaultParamValue;
if (insertionMethod === "functionParameter" && isStatic && isDefinedAtTop && allowDefaultParamValue) {
defaultParamValue = value;
path.remove();
} else {
// For-in / For-of can only reference the variable name
if (parentPath.isForInStatement() || parentPath.isForOfStatement()) {
path.replaceWith(t.identifier(name));
} else {
path.replaceWith(t.assignmentExpression("=", t.identifier(name), declaration.init || t.identifier("undefined")));
}
}
switch (insertionMethod) {
case "functionParameter":
var identifier = t.identifier(name);
var param = identifier;
if (allowDefaultParamValue && defaultParamValue) {
param = t.assignmentPattern(param, defaultParamValue);
}
functionPath.node.params.push(param);
var paramPath = functionPath.get("params").at(-1);
// Update binding to point to new path
var binding = functionPath.scope.getBinding(name);
if (binding) {
binding.kind = "param";
binding.path = paramPath;
binding.identifier = identifier;
}
me.changeData.functionParameters++;
break;
case "variableDeclaration":
var block = path.findParent(function (path) {
return path.isBlock();
});
var topNode = block.node.body.filter(function (x) {
return x.type !== "ImportDeclaration";
})[0];
var variableDeclarator = t.variableDeclarator(t.identifier(name));
if (t.isVariableDeclaration(topNode) && topNode.kind === "var") {
topNode.declarations.push(variableDeclarator);
break;
} else {
(0, _astUtils.prepend)(block, me.skip(t.variableDeclaration("var", [variableDeclarator])));
}
me.changeData.variableDeclarations++;
break;
}
}
}
}
};
};
;