restringer
Version:
Deobfuscate Javascript with emphasis on reconstructing strings
42 lines (40 loc) • 1.83 kB
JavaScript
import {areReferencesModified} from '../utils/areReferencesModified.js';
import {doesDescendantMatchCondition} from '../utils/doesDescendantMatchCondition.js';
import {getMainDeclaredObjectOfMemberExpression} from '../utils/getMainDeclaredObjectOfMemberExpression.js';
/**
* Replace variables which only point at other variables and do not change, with their target.
* E.g.
* const a = [...];
* const b = a;
* const c = b[0]; // <-- will be replaced with `const c = a[0];`
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveProxyReferences(arb, candidateFilter = () => true) {
const relevantNodes = [
...(arb.ast[0].typeMap.VariableDeclarator || []),
];
for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
if (['Identifier', 'MemberExpression'].includes(n.id.type) &&
['Identifier', 'MemberExpression'].includes(n.init?.type) &&
!/For.*Statement/.test(n.parentNode?.parentNode?.type) &&
candidateFilter(n)) {
const relevantIdentifier = getMainDeclaredObjectOfMemberExpression(n.id)?.declNode || n.id;
const refs = relevantIdentifier.references || [];
const replacementNode = n.init;
const replacementMainIdentifier = getMainDeclaredObjectOfMemberExpression(n.init)?.declNode;
if (replacementMainIdentifier && replacementMainIdentifier === relevantIdentifier) continue;
// Exclude changes in the identifier's own init
if (doesDescendantMatchCondition(n.init, n => n === relevantIdentifier)) continue;
if (refs.length && !areReferencesModified(arb.ast, refs) && !areReferencesModified(arb.ast, [replacementNode])) {
for (const ref of refs) {
arb.markNode(ref, replacementNode);
}
}
}
}
return arb;
}
export default resolveProxyReferences;