restringer
Version:
Deobfuscate Javascript with emphasis on reconstructing strings
46 lines (45 loc) • 1.73 kB
JavaScript
/**
* Resolve the value of member expressions to objects which hold literals that were directly assigned to the expression.
* E.g.
* function a() {}
* a.b = 3;
* a.c = '5';
* console.log(a.b + a.c); // a.b + a.c will be replaced with '35'
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function resolveMemberExpressionsWithDirectAssignment(arb, candidateFilter = () => true) {
const relevantNodes = [
...(arb.ast[0].typeMap.MemberExpression || []),
];
rnLoop: for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
if (n.object.declNode &&
n.parentNode.type === 'AssignmentExpression' &&
n.parentNode.right.type === 'Literal' &&
candidateFilter(n)) {
const prop = n.property?.value || n.property?.name;
const valueUses = [];
for (let j = 0; j < n.object.declNode.references.length; j++) {
/** @type {ASTNode} */
const ref = n.object.declNode.references[j];
if (ref.parentNode !== n && ref.parentNode.type === 'MemberExpression' &&
prop === ref.parentNode.property[ref.parentNode.property.computed ? 'value' : 'name']) {
// Skip if the value is reassigned
if (ref.parentNode.parentNode.type === 'UpdateExpression' ||
(ref.parentNode.parentNode.type === 'AssignmentExpression' && ref.parentNode.parentKey === 'left')) continue rnLoop;
valueUses.push(ref);
}
}
if (valueUses.length) {
const replacementNode = n.parentNode.right;
for (let j = 0; j < valueUses.length; j++) {
arb.markNode(valueUses[j].parentNode, replacementNode);
}
}
}
}
return arb;
}
export default resolveMemberExpressionsWithDirectAssignment;