home *** CD-ROM | disk | FTP | other *** search
/ Hacks & Cracks / Hacks_and_Cracks.iso / hackersguides-&-software / 40hex-11.zip / 40HEX-11.002 < prev    next >
Text File  |  1993-06-01  |  11KB  |  190 lines

  1. 40Hex Issue 11 Volume 3 Number 2                                      File 002
  2.  
  3.                              ─────────────────────
  4.                              ADVANCED POLYMORPHISM
  5.                                      PRIMER
  6.                                  PART THE FIRST
  7.                              ─────────────────────
  8.                                  By Dark Angel
  9.                                  Phalcon/Skism
  10.                              ─────────────────────
  11.  
  12.        With the recent proliferation of virus encryption "engines," I was
  13.   inspired to write my own.  In a few short weeks, I was able to construct one
  14.   such routine which can hold its own.  A polymorphic encryption routine is
  15.   nothing more than a complex code generator.  Writing such a routine, while
  16.   not incredibly difficult, requires careful planning and perhaps more than a
  17.   few false starts.
  18.  
  19.        The utility of true polymorphism is, by now, an accepted fact.
  20.   Scanning for the majority of viruses is a trivial task, involving merely the
  21.   identification of a specific pattern of bytes in executable files.  This
  22.   approach is quick and may be used to detect nearly all known viruses.
  23.   However, polymorphism throws a monkey wrench into the works.  Polymorphic
  24.   viruses encode each copy of the virus with a different decryption routine.
  25.   Since (theoretically) no bytes remain constant in each generated decryption
  26.   routine, virus detectors cannot rely on a simple pattern match to locate
  27.   these viruses.  Instead, they are forced to use an algorithmic appproach
  28.   susceptible to "false positives," misleading reports of the existence of the
  29.   virus where it is not truly present.  Creating a reliable algorithm to
  30.   detect the polymorphic routine takes far more effort than isolating a usable
  31.   scan string.  Additionally, if a virus detector fails to find even one
  32.   instance of the virus, then that single instance will remain undetected and
  33.   spawn many more generations of the virus.  Survival, of course, is the
  34.   ultimate goal of the virus.
  35.  
  36.        Before attempting to write a polymorphic routine, it is necessary to
  37.   obtain a manual detailing the 80x86 instruction set.  Without bit-level
  38.   manipulation of the opcodes, any polymorphic routine will be of limited
  39.   scope.  The nice rigid structure of the 80x86 instruction set will be
  40.   readily apparent after a simple perusal of the opcodes.  Exploitation of
  41.   this structured instruction set allows for the compact code generation
  42.   routines which lie at the heart of every significant polymorphic routine.
  43.  
  44.        After examining the structure of the opcodes, the basic organisation of
  45.   the polymorphic routine should be laid out.  Here, an understanding of the
  46.   basics behind such routines is required.  The traditional approach treats
  47.   the decryption routine as a simple executable string, such as
  48.   "BB1301B900022E8137123483C302E2F6."  A true (advanced) polymorphic routine,
  49.   by contrast, views the decryption routine as a conceptual algorithm, such
  50.   as, "Set up a 'pointer' register, that is, the register whose contents hold
  51.   a pointer to the memory to be decrypted.  Set up a counter register.  Use
  52.   the pointer register to decrypt one byte.  Update the pointer register.
  53.   Decrement the count register, looping if it is not zero."  Two routines
  54.   which fit this algorithm follow:
  55.  
  56.   Sample Encryption 1
  57.   ------ ---------- -
  58.        mov  bx,offset startencrypt   ; here, bx is the 'pointer' register
  59.        mov  cx,viruslength / 2       ; and cx holds the # of iterations
  60.   decrypt_loop:
  61.        xor  word ptr [bx],12h        ; decrypt one word at a time
  62.        inc  bx                       ; update the pointer register to
  63.        inc  bx                       ; point to the next word
  64.        loop decrypt_loop             ; and continue the decryption
  65.   startencrypt:
  66.  
  67.   Sample Encryption 2
  68.   ------ ---------- -
  69.   start:
  70.        mov  bx,viruslength           ; now bx holds the decryption length
  71.        mov  bp,offset start          ; bp is the 'pointer' register
  72.   decrypt_loop:
  73.        add  byte ptr [bp+0Ch],33h    ; bp+0Ch -> memory location to be
  74.                                      ; decrypted at each iteration
  75.        inc  bp                       ; update the pointer register
  76.        dec  bx                       ; and the count register
  77.        jnz  decrypt_loop             ; loop if still more to decrypt
  78.  
  79.        The number of possibilities is essentially infinite.  Naturally,
  80.   treating the decryption as an algorithm rather than as an executable string
  81.   greatly increases the flexibility in creating the actual routine.  Various
  82.   portions of the decryption algorithm may be tinkered with, allowing for
  83.   further variations.  Using the example above, one possible variation is to
  84.   swap the order of the setup of the registers, i.e.
  85.  
  86.        mov  cx,viruslength
  87.        mov  bx,offset startencrypt
  88.  
  89.   in lieu of
  90.  
  91.        mov  bx,offset startencrypt
  92.        mov  cx,viruslength
  93.  
  94.        It is up to the individual to decide upon the specific variations which
  95.   should be included in the polymorphic routine.  Depending upon the nature of
  96.   the variations and the structure of the polymorphic routine, each increase
  97.   in power may be accompanied with only a minimal sacrifice in code length.
  98.   The goal is for the routine to be capable of generating the greatest number
  99.   of variations in the least amount of code.  It is therefore desirable to
  100.   write the polymorphic routine in a manner such that additional variations
  101.   may be easily accommodated.  Modularity is helpful in this respect, as the
  102.   modest overhead is rapidly offset by substantial space savings.
  103.  
  104.        The first step most polymorphic routines undergo is the determination
  105.   of the precise variation which is to be encoded.  For example, a polymorphic
  106.   routine may decide that the decryption routine is to use word-length xor
  107.   encryption with bx as the pointer register, dx as a container for the
  108.   encryption value, and cx as the counter register.  Once this information is
  109.   known, the routine should be able to calculate the initial value of each
  110.   variable.  For example, if cx is the counter register for a byte-length
  111.   encryption, then it should hold the virus length.  To increase variability,
  112.   the length of the encryption can be increased by a small, random amount.
  113.   Note that some variables, in particular the pointer register, may not be
  114.   known before encoding the rest of the routine.  This detail is discussed
  115.   below.
  116.  
  117.        Of course, selecting the variables and registers will not in and of
  118.   itself yield a valid decryption routine; the polymorphic routine must also
  119.   encode the actual instructions to perform the job!  The cheesiest
  120.   polymorphic routines encode a single "mov" instruction for the assignment of
  121.   a value to a register.  The more complex routines encode a series of
  122.   instructions which are functionally equivalent to the simple three byte
  123.   "mov" statement yet far different in form.  For example,
  124.  
  125.        mov  ax, 808h
  126.  
  127.   could be replaced with
  128.  
  129.        mov  ax, 303h                 ; ax = 303h
  130.        mov  bx, 101h                 ; bx = 101h
  131.        add  ax, bx                   ; ax = 404h
  132.        shl  ax, 1                    ; ax = 808h
  133.  
  134.        Recall that the registers should be encoded in a random order.  The
  135.   counter variable, for example, should not always be the first to be encoded.
  136.   Predictability, the bane of polymorphic routines, must be avoided at all
  137.   costs.
  138.  
  139.        After the registers are encoded, the actual decryption loop should then
  140.   be encoded.  The loop can perform a number of actions, the most significant
  141.   of which should be to manipulate the memory location, i.e. the actual
  142.   decryption instruction, and to update the pointer register, if necessary.
  143.   Finally, the loop instruction itself should be encoded.  This can take many
  144.   forms, including "loop," "loopnz," "jnz," etc.  Possible variations include
  145.   altering the decryption value register and the counter register during each
  146.   iteration.
  147.  
  148.        This is the general pattern of encoding.  By placing garbling, or "do-
  149.   nothing," instructions between the essential pieces of code, further
  150.   variability may be ensured.  These instructions may take many forms.  If the
  151.   encoding routines are well-designed, the garbler can take advantage of the
  152.   pre-existing code to generate null instructions, such as assignments to
  153.   unused registers.
  154.  
  155.        Once the decryption routine has been written, it is necessary to
  156.   encrypt the virus code.  The traditional approach gives the polymorphic
  157.   routine the job of encrypting the code.  The polymorphic routine should
  158.   therefore "remember" how the precise variation used by the decryptor and
  159.   adjust the encryption routine in a complementary fashion.  An alternate
  160.   approach is for the polymorphic routine to simultaneously encode both the
  161.   encryption and decryption routines.  Although it adds overhead to the code,
  162.   it is an extremely flexible approach that easily accommodates variations
  163.   which may be later introduced into the polymorphic routine.
  164.  
  165.        Variable-length decryptors come at a significant trade-off; the exact
  166.   start of the decryption cannot be known before encoding the decryptor.
  167.   There are two approaches to working around this limitation.  The first is to
  168.   encode the pointer register in a single instruction, i.e. mov bx,185h and to
  169.   patch the initial value once it is known.  This is simplistic, though
  170.   undesirable, as it decreases the variability of the routine.  An alternate
  171.   approach is to encode the encryption instruction in the form xor word ptr
  172.   [bx+185h], cx (as in Sample Encryption 2, above) instead of xor word ptr
  173.   [bx], cx (as in Sample Encryption 1).  This increases the flexibility of the
  174.   routine, as the initial value of the pointer register need not be any fixed
  175.   value; correct decryption may be assured by adjusting the offset in the
  176.   decryption instruction.  It is then possible to encode the pointer register
  177.   with multiple instructions, increasing flexibility.  However, using either
  178.   method alone increases the predictability of the generated code.  A better
  179.   approach would be to incorporate both methods into a single polymorphic
  180.   routine and randomly selecting one during each run.
  181.  
  182.        As an example of a polymorphic routine, I present DAME, Dark Angel's
  183.   Multiple Encryptor and a simple virus which utilises it.  They appear in the
  184.   following article.  DAME uses a variety of powerful techniques to achieve
  185.   full polymorphism.  Additionally, it is easy to enhance; both the encoding
  186.   routines and the garblers can be extended algorithmically with minimal
  187.   effort.  In the next issue, I will thoroughly comment and explain the
  188.   various parts of DAME.
  189.  
  190.