Didier Stevens

Tuesday 19 December 2006

Teaching a SpiderMonkey a new trick

Filed under: Reverse Engineering — Didier Stevens @ 9:28

Have you read NJ Verenini post on Websense’s Blog were he explains how to use SpiderMonkey to deobfuscate Javascript? As SpiderMonkey has no document object, Verenini shows a way to define your own document object to support document.write().

I’ve adapted the SpiderMonkey source code to include the document object. Not that my method is better than Verenini’s, I just wanted to play with SpiderMonkey.
An upcoming “Virus Lab” post will explain how I use this adapted SpiderMonkey, but for now I want to explain how I proceeded to modify SpiderMonkey.

If you’re not familiar with the SpiderMonkey source-code (like me), were do you start? I want to implement a document object with a write method. Is there something similar in JavsScript? Take a look at the Math object.

[object Math]

The Math object has several methods, like sin:
js> Math.sin(3.1415926/2)

document does not exist:
js> document
2: ReferenceError: document is not defined

The trick is to add a document object that has the same behaviour as the Math object (i.e. same members), and if this works, we adapt the document object by removing all Math members and adding a write method.

Greping for Math in the source code reveals that the object is defined in jsmath.c and jsmath.h. This is good, the Math object is defined in it’s own source files. So we will make our own source files for document based on Math: copy jsmath.[ch] to jsdocument.[ch]. Then edit jsdocument.[ch] and replace Math with document (there are some execeptions, like math.h).

Then we add jsdocument.[ch] to the makefile.
Greping for jsmath.h reveals that it’s included in jsapi.c. A quick search for
Math in jsapi.c reveals this code:
js_InitMathClass(cx, obj) &&
{js_InitMathClass, ATOM_OFFSET(Math)},

We add our own code:

js_InitDocumentClass(cx, obj) &&
{js_InitDocumentClass, ATOM_OFFSET(Document)},

Now when we build, we’ll get an error because we use a Document ATOM that we didn’t define. A bit of searching in the source code shows that atoms are defined in jsatom.[ch]. We search for Math and add extra code for Document.
And now the build succeeds!

js> document
[object document]
js> document.sin(3.1415926/2)

Now we have to remove all members and add our own write method, but this is for another post, where I’ll publish my modified spidermonkey (it’s GPLed).

Reversing with the commented source code is not so difficult as reversing binaries, especially the patching process. If you want to add a new feature, look for an existing similar feature and do an “intelligent” copy-paste of the source code.

Once upon a time, long ago, I read the Dragon Book, and this also explains how I was able to quickly understand how to modify SpiderMonkey.

Blog at WordPress.com.