UNPKG

restringer

Version:

Deobfuscate Javascript with emphasis on reconstructing strings

71 lines (67 loc) 2.5 kB
import {parseCode} from 'flast'; const largeNumber = 999e8; const sortByNodeId = (a, b) => a.nodeId > b.nodeId ? 1 : b.nodeId > a.nodeId ? -1 : 0; const funcStartRegexp = new RegExp('function[^(]*'); /** * Add a name to a FunctionExpression. * @param {ASTNode} n The target node * @param {string} [name] The new name. Defaults to 'func + n.nodeId'. * @return {ASTNode} The new node with the name set */ function addNameToFE(n, name) { name = name || 'func' + n.nodeId; const funcSrc = '(' + n.src.replace(funcStartRegexp, 'function ' + name) + ');'; const newNode = parseCode(funcSrc); if (newNode) { newNode.nodeId = n.nodeId; newNode.src = funcSrc; return newNode; } } /** * Return the source code of the ordered nodes. * @param {ASTNode[]} nodes * @param {boolean} preserveOrder (optional) When false, IIFEs are pushed to the end of the code. * @return {string} Combined source code of the nodes. */ function createOrderedSrc(nodes, preserveOrder = false) { const parsedNodes = []; for (let i = 0; i < nodes.length; i++) { let n = nodes[i]; if (n.type === 'CallExpression') { if (n.parentNode.type === 'ExpressionStatement') { nodes[i] = n.parentNode; if (!preserveOrder && n.callee.type === 'FunctionExpression') { // Set nodeId to place IIFE just after its argument's declaration let maxArgNodeId = 0; for (let j = 0; j < n.arguments.length; j++) { const arg = n.arguments[j]; if (arg?.declNode?.nodeId > maxArgNodeId) { maxArgNodeId = arg.declNode.nodeId; } } nodes[i].nodeId = maxArgNodeId ? maxArgNodeId + 1 : nodes[i].nodeId + largeNumber; } } else if (n.callee.type === 'FunctionExpression') { if (!preserveOrder) { const newNode = addNameToFE(n, n.parentNode?.id?.name); newNode.nodeId = newNode.nodeId + largeNumber; nodes[i] = newNode; } else nodes[i] = n; } } else if (n.type === 'FunctionExpression' && !n.id) { nodes[i] = addNameToFE(n, n.parentNode?.id?.name); } n = nodes[i]; // In case the node was replaced if (!parsedNodes.includes(n)) parsedNodes.push(n); } parsedNodes.sort(sortByNodeId); let output = ''; for (let i = 0; i < parsedNodes.length; i++) { const n = parsedNodes[i]; const addSemicolon = ['VariableDeclarator', 'AssignmentExpression'].includes(n.type); output += (n.type === 'VariableDeclarator' ? `${n.parentNode.kind} ` : '') + n.src + (addSemicolon ? ';' : '') + '\n'; } return output; } export {createOrderedSrc};