Friday, April 16, 2010

When overloading eval() fails

Today I encountered a small issue when decoding yet another 'crackme' challenge from Paweł Goleń. This time it turned out to be just a little bit more difficult, as Paweł:
  • used some onerror handlers to run the code
  • tried (unsuccessfully) to beat my function overloading
  • used multi-level obfuscation
But obviously, this could only slow down any determined programmer. So there I was, happily decrypting the code bit by bit, restarting Firefox from time to time (heavy debugging session in Firebug always ends up like this for me ;) ) when suddenly the code stopped working.

And all I did was to replace eval('code') with code. To be more specific, that is the actual code:
<img onerror="eval('code;') // ok" src="http://i.dont.exist" />
<img onerror="code; //gives errors" src="http://i.dont.exist" />

Such operation usually has no side effects - after all, eval is meant to immediately evaluate the passed code. But my eval was overloaded (check my previous post to see how I achieved this) and this caused problems. What's even worse - it turned out overloaded eval will not always work as expected and you cannot avoid it!

Eval() is special

The 'original' eval turned out to be a very special function (just like arguments being a very special array)  - it has its own execution context and you cannot emulate it with any other function. See the below example:

<script type="text/javascript">
var y = 'Klaatu barada nikto';
var eval2 = eval;
console.log('in global: ',y,this);
<img src="about:blank" onerror="console.log('in event handler:',y,this)">
<img src="about:blank" onerror="eval(&quot;console.log('in eval:',y,this)&quot;)">
<img src="about:blank" onerror="eval2(&quot;console.log('in eval2:',y,this)&quot;)">

Here we define a global variable y and we try to read the value of y from
  1. global context (<script> element)
  2. an event handler
  3. eval() function inside an event handler
  4. eval2() which is just a reference to 'original' eval (let's call it dummy overload ;))
What is important, this inside event handler points to <img> element, and images have their y property - so y should not be our 'Klaatu barada nikto', but a number. But running the above code in Firebug gives some unexpected results:

1st case works as expected (this is window, and global y is accessed), so is the 2nd (this is img, y is local), eval() does not change the scope nor variable visibility. But eval2()suddenly sees our global variable, even though it's in the context of <img>! WTF??

So there is a slight difference between original and overloaded eval() - although the context stays the same (thanks to Function.apply I used in original overloading), variable visibility is different - so one could potentially detect that eval() is overloaded.

We're doomed?

I tried to overcome this using various known techniques (wrapping in anonymous function, playing with scopes etc.) but to no avail. I cannot emulate eval without getting this strange behaviour.

Luckily, malware authors are is the same position - they usually obfuscate eval call by using some intermediate function (in other words, there is eval2 = eval equivalent somewhere in their code). But still, I'd rather have a perfect emulation... Is there any?

No comments: