restringer
Version:
Deobfuscate Javascript with emphasis on reconstructing strings
40 lines (39 loc) • 1.69 kB
JavaScript
/**
* Calls to functions which only return an identifier will be replaced with the identifier itself.
* E.g.
* function a() {return String}
* a()(val) // <-- will be replaced with String(val)
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceCallExpressionsWithUnwrappedIdentifier(arb, candidateFilter = () => true) {
const relevantNodes = [
...(arb.ast[0].typeMap.CallExpression || []),
];
for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
if (((n.callee?.declNode?.parentNode?.type === 'VariableDeclarator' &&
/FunctionExpression/.test(n.callee.declNode.parentNode?.init?.type)) ||
(n.callee?.declNode?.parentNode?.type === 'FunctionDeclaration' &&
n.callee.declNode.parentKey === 'id')) &&
candidateFilter(n)) {
const declBody = n.callee.declNode.parentNode?.init?.body || n.callee.declNode.parentNode?.body;
if (!Array.isArray(declBody)) {
// Cases where an arrow function has no block statement
if (declBody.type === 'Identifier' || (declBody.type === 'CallExpression' && !declBody.arguments.length)) {
for (const ref of n.callee.declNode.references) {
arb.markNode(ref.parentNode, declBody);
}
} else if (declBody.type === 'BlockStatement' && declBody.body.length === 1 && declBody.body[0].type === 'ReturnStatement') {
const arg = declBody.body[0].argument;
if (arg.type === 'Identifier' || (arg.type === 'CallExpression' && !arg.arguments?.length)) {
arb.markNode(n, arg);
}
}
}
}
}
return arb;
}
export default replaceCallExpressionsWithUnwrappedIdentifier;