-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathreplaceNewFuncCallsWithLiteralContent.js
64 lines (62 loc) · 2.1 KB
/
replaceNewFuncCallsWithLiteralContent.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import {getCache} from '../utils/getCache.js';
import {generateHash} from '../utils/generateHash.js';
import {generateFlatAST, logger} from 'flast';
/**
* Extract string values of eval call expressions, and replace calls with the actual code, without running it through eval.
* E.g.
* new Function('!function() {console.log("hello world")}()')();
* will be replaced with
* !function () {console.log("hello world")}();
* @param {Arborist} arb
* @param {Function} candidateFilter (optional) a filter to apply on the candidates list
* @return {Arborist}
*/
function replaceNewFuncCallsWithLiteralContent(arb, candidateFilter = () => true) {
const cache = getCache(arb.ast[0].scriptHash);
const relevantNodes = [
...(arb.ast[0].typeMap.NewExpression || []),
];
for (let i = 0; i < relevantNodes.length; i++) {
const n = relevantNodes[i];
if (n.parentKey === 'callee' &&
!n.parentNode?.arguments?.length &&
n.callee?.name === 'Function' &&
n.arguments?.length === 1 &&
n.arguments[0].type === 'Literal' &&
candidateFilter(n)) {
const targetCodeStr = n.arguments[0].value;
const cacheName = `replaceEval-${generateHash(targetCodeStr)}`;
try {
if (!cache[cacheName]) {
let body;
if (targetCodeStr) {
body = generateFlatAST(targetCodeStr, {detailed: false, includeSrc: false})[0].body;
if (body.length > 1) {
body = {
type: 'BlockStatement',
body,
};
} else {
body = body[0];
if (body.type === 'ExpressionStatement') body = body.expression;
}
} else body = {
type: 'Literal',
value: targetCodeStr,
};
cache[cacheName] = body;
}
let replacementNode = cache[cacheName];
let targetNode = n.parentNode;
if (targetNode.parentNode.type === 'ExpressionStatement' && replacementNode.type === 'BlockStatement') {
targetNode = targetNode.parentNode;
}
arb.markNode(targetNode, replacementNode);
} catch (e) {
logger.debug(`[-] Unable to replace new function's body with call expression: ${e}`);
}
}
}
return arb;
}
export default replaceNewFuncCallsWithLiteralContent;