Does there exist a string s
such that
(new Function(s))();
and
eval(s);
behave differently? I'm trying to "detect" how a string is being evaluated.
The eval() function in JavaScript is used to evaluate the expression. It is JavaScirpt's global function, which evaluates the specified string as JavaScript code and executes it. The parameter of the eval() function is a string. If the parameter represents the statements, eval() evaluates the statements.
The argument of the eval() function is a string. It will evaluate the source string as a script body, which means both statements and expressions are allowed. It returns the completion value of the code. For expressions, it's the value the expression evaluates to.
Check for the arguments
object. If it exists, you're in the function. If it doesn't it has been eval
ed.
Note that you'll have to put the check for arguments
in a try...catch
block like this:
var s = 'try {document.writeln(arguments ? "Function" : "Eval") } catch(e) { document.writeln("Eval!") }';
(new Function(s))();
eval(s);
Demo
Solution to nnnnnn
's concern. For this, I've edited the eval function itself:
var _eval = eval;
eval = function (){
// Your custom code here, for when it's eval
_eval.apply(this, arguments);
};
function test(x){
eval("try{ alert(arguments[0]) } catch(e){ alert('Eval detected!'); }");
}
test("In eval, but it wasn't detected");
The current answer does not work in strict mode since you can't redefine eval. Moreover, redefining eval
is problematic for many other reasons.
The way to differenciate them is based on the fact that well... one of them creates a function and what doesn't. What can functions do? They can return
stuff :)
We can simply exploit that and do something with return
:
// is in function
try {
return true;
} catch(e) { // in JS you can catch syntax errors
false; //eval returns the return of the expression.
}
So in example:
var s = "try{ return true; }catch(e){ false; }";
eval(s); // false
Function(s)(); // true
(new Function(s))(); // true, same as line above
(function(){ return eval(s); })(); // the nested 'problematic' case - false
evaled code can be detected by invoking an error and checking if the native stack-trace contains a lower row/column indicator.
if (typeof window === 'object') {
// browser
window.isEvilEval = function () {
return parseInt(String(new Error().stack).split(':').pop(), 10) < 10;
};
} else {
// nodejs (must be global to be callable from within Function)
global.isEvilEval = function () {
return (
new Error().stack
.split('\n')
.filter((l) => l.trim().startsWith('at eval') && l.indexOf('<anonymous>:1') > -1).length > 0
);
};
}
// test - directly in code => false
console.log(isEvilEval());
// test - in evil eval => true
eval('console.log(isEvilEval())');
// test scoped in function => false
Function('console.log(isEvilEval())')();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With