Hijacking JavaScript Functions
February 11th, 2008 by Ryan GovostesI spent several hours last week tracking down an obnoxious bug in WebKit JavaScriptCore’s Function.toString() implementation where multiple var declarations on a single line would get grouped with parentheses (Radar, Trac, Bugzilla). The incredible WebKit team made a working patch within 23 hours of my report, kudos to them.
Joe and I very much enjoy hijacking code. While this may become a recurring theme on this blog, right now I’m just going to share how to do it in JavaScript. Let’s say one of the .js files included from your page declares the function foo() as
function foo() { var x = "spinach"; alert(x); }
If you run foo(), it will obviously display a dialog reading “spinach”. But for some reason or other, you need it to say “eggplant” instead, but you can’t alter the original code. Furthermore, pretend we’re in a situation where it’s inconvenient to reimplement the function. No problem — we can just hijack it and modify the code:
// First, get the code to the function // Here we strip off the "function foo() { ... }" var c_foo = foo.toString().replace(/^[^{]*{/|>, '').replace(/}$/|>, ''); // Now perform whatever modifications we need c_foo = c_foo.replace('spinach', 'eggplant'); // Now overwrite the function with a new Function object using our code foo = new Function(c_foo);
Now whenever foo() is called, it will use our modified code. Of course, in this simple example we could have just redeclared foo(), but this becomes far more feasible with more complex code.
As an interesting aside, when you call toString() on a function, it’s not actually printing out the function as it was declared (hence, the bug I mentioned at the top of the post). In the case of JavaScriptCore (used by Safari), a function is broken into a graph of various nodes representing keywords, loops, strings constants, and so on. When you convert the function to a string, it traverses the graph and constructs a more familiar representation of it. As such, it’s kind of a handy way to reformat obfuscated (or just hard to read) code, but you’ll lose commenting.