restringer
Version:
Deobfuscate Javascript with emphasis on reconstructing strings
115 lines (113 loc) • 2.77 kB
JavaScript
import {badValue} from '../config.js';
import {getObjType} from './getObjType.js';
import {generateCode, parseCode, logger} from 'flast';
/**
* Create a node from a value by its type.
* @param {*} value The value to be parsed into an ASTNode.
* @returns {ASTNode|badValue} The newly created node if successful; badValue string otherwise.
*/
function createNewNode(value) {
let newNode = badValue;
try {
if (![undefined, null].includes(value) && value.__proto__.constructor.name === 'Node') value = generateCode(value);
switch (getObjType(value)) {
case 'String':
case 'Number':
case 'Boolean':
if (['-', '+', '!'].includes(String(value)[0]) && String(value).length > 1) {
const absVal = String(value).substring(1);
if (Number.isNaN(parseInt(absVal)) && !['Infinity', 'NaN'].includes(absVal)) {
newNode = {
type: 'Literal',
value,
raw: String(value),
};
} else newNode = {
type: 'UnaryExpression',
operator: String(value)[0],
argument: createNewNode(absVal),
};
} else if (['Infinity', 'NaN'].includes(String(value))) {
newNode = {
type: 'Identifier',
name: String(value),
};
} else if (Object.is(value, -0)) {
newNode = {
type: 'UnaryExpression',
operator: '-',
argument: createNewNode(0),
};
} else {
newNode = {
type: 'Literal',
value: value,
raw: String(value),
};
}
break;
case 'Array': {
const elements = [];
for (const el of Array.from(value)) {
elements.push(createNewNode(el));
}
newNode = {
type: 'ArrayExpression',
elements,
};
break;
}
case 'Object': {
const properties = [];
for (const [k, v] of Object.entries(value)) {
const key = createNewNode(k);
const val = createNewNode(v);
if ([key, val].includes(badValue)) {
// noinspection ExceptionCaughtLocallyJS
throw Error();
}
properties.push({
type: 'Property',
key,
value: val,
});
}
newNode = {
type: 'ObjectExpression',
properties,
};
break;
}
case 'Undefined':
newNode = {
type: 'Identifier',
name: 'undefined',
};
break;
case 'Null':
newNode = {
type: 'Literal',
raw: 'null',
};
break;
case 'Function': // Covers functions and classes
try {
newNode = parseCode(value).body[0];
} catch {} // Probably a native function
break;
case 'RegExp':
newNode = {
type: 'Literal',
regex: {
pattern: value.source,
flags: value.flags,
},
};
break;
}
} catch (e) {
logger.debug(`[-] Unable to create a new node: ${e}`);
}
return newNode;
}
export {createNewNode};